Merge "Make wifi module use shared metalava args"
diff --git a/apex/sdkext/Android.bp b/apex/sdkext/Android.bp
index b9071f8..5369a96 100644
--- a/apex/sdkext/Android.bp
+++ b/apex/sdkext/Android.bp
@@ -23,6 +23,7 @@
     java_libs: [ "framework-sdkext" ],
     prebuilts: [
       "com.android.sdkext.ldconfig",
+      "cur_sdkinfo",
       "derive_sdk.rc",
     ],
     key: "com.android.sdkext.key",
@@ -51,3 +52,33 @@
     filename: "ld.config.txt",
     installable: false,
 }
+
+python_binary_host {
+    name: "gen_sdkinfo",
+    srcs: [
+        "sdk.proto",
+        "gen_sdkinfo.py",
+    ],
+    proto: {
+        canonical_path_from_root: false,
+    },
+    version: {
+        py3: {
+            embedded_launcher: true,
+        },
+    },
+}
+
+gensrcs {
+    name: "cur_sdkinfo_src",
+    srcs: [""],
+    tools: [ "gen_sdkinfo" ],
+    cmd: "$(location) -v 0 -o $(out)",
+}
+
+prebuilt_etc {
+    name: "cur_sdkinfo",
+    src: ":cur_sdkinfo_src",
+    filename: "sdkinfo.binarypb",
+    installable: false,
+}
diff --git a/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java b/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java
index d3b9397..a8a7eff 100644
--- a/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java
+++ b/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java
@@ -60,7 +60,7 @@
      */
     public static int getExtensionVersion(@SdkVersion int sdk) {
         if (sdk < VERSION_CODES.R) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException(String.valueOf(sdk) + " does not have extensions");
         }
         return R_EXTENSION_INT;
     }
diff --git a/apex/sdkext/gen_sdkinfo.py b/apex/sdkext/gen_sdkinfo.py
new file mode 100644
index 0000000..5af478b
--- /dev/null
+++ b/apex/sdkext/gen_sdkinfo.py
@@ -0,0 +1,19 @@
+import sdk_pb2
+import sys
+
+if __name__ == '__main__':
+  argv = sys.argv[1:]
+  if not len(argv) == 4 or sorted([argv[0], argv[2]]) != ['-o', '-v']:
+    print('usage: gen_sdkinfo -v <version> -o <output-file>')
+    sys.exit(1)
+
+  for i in range(len(argv)):
+    if sys.argv[i] == '-o':
+      filename = sys.argv[i+1]
+    if sys.argv[i] == '-v':
+      version = int(sys.argv[i+1])
+
+  proto = sdk_pb2.SdkVersion()
+  proto.version = version
+  with open(filename, 'wb') as f:
+    f.write(proto.SerializeToString())
diff --git a/apex/sdkext/sdk.proto b/apex/sdkext/sdk.proto
new file mode 100644
index 0000000..d15b935
--- /dev/null
+++ b/apex/sdkext/sdk.proto
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+syntax = "proto3";
+package com.android.sdkext.proto;
+
+option java_outer_classname = "SdkProto";
+option optimize_for = LITE_RUNTIME;
+
+message SdkVersion {
+  int32 version = 1;
+}
diff --git a/api/current.txt b/api/current.txt
index 1254a85..028f077 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -17246,6 +17246,7 @@
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 1; // 0x1
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME = 12; // 0xc
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING = 10; // 0xa
+    field public static final int REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING = 15; // 0xf
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING = 4; // 0x4
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_RAW = 3; // 0x3
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS = 5; // 0x5
@@ -35028,6 +35029,7 @@
     method public void dump(@NonNull java.io.FileDescriptor, @Nullable String[]) throws android.os.RemoteException;
     method public void dumpAsync(@NonNull java.io.FileDescriptor, @Nullable String[]) throws android.os.RemoteException;
     method @Nullable public String getInterfaceDescriptor() throws android.os.RemoteException;
+    method public static int getSuggestedMaxIpcSizeBytes();
     method public boolean isBinderAlive();
     method public void linkToDeath(@NonNull android.os.IBinder.DeathRecipient, int) throws android.os.RemoteException;
     method public boolean pingBinder();
@@ -35224,6 +35226,7 @@
     method public void readMap(@NonNull java.util.Map, @Nullable ClassLoader);
     method @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader);
     method @Nullable public android.os.Parcelable[] readParcelableArray(@Nullable ClassLoader);
+    method @Nullable public android.os.Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader);
     method @NonNull public <T extends android.os.Parcelable> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader);
     method @Nullable public android.os.PersistableBundle readPersistableBundle();
     method @Nullable public android.os.PersistableBundle readPersistableBundle(@Nullable ClassLoader);
@@ -35271,6 +35274,7 @@
     method public void writeNoException();
     method public void writeParcelable(@Nullable android.os.Parcelable, int);
     method public <T extends android.os.Parcelable> void writeParcelableArray(@Nullable T[], int);
+    method public void writeParcelableCreator(@NonNull android.os.Parcelable);
     method public <T extends android.os.Parcelable> void writeParcelableList(@Nullable java.util.List<T>, int);
     method public void writePersistableBundle(@Nullable android.os.PersistableBundle);
     method public void writeSerializable(@Nullable java.io.Serializable);
@@ -44600,6 +44604,7 @@
     method public void notifyConfigChangedForSubId(int);
     field public static final String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
     field public static final int DATA_CYCLE_THRESHOLD_DISABLED = -2; // 0xfffffffe
+    field public static final int DATA_CYCLE_USE_PLATFORM_DEFAULT = -1; // 0xffffffff
     field public static final String EXTRA_SLOT_INDEX = "android.telephony.extra.SLOT_INDEX";
     field public static final String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
     field public static final String KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY = "5g_nr_ssrsrp_thresholds_int_array";
@@ -44663,7 +44668,10 @@
     field public static final String KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING = "config_plans_package_override_string";
     field public static final String KEY_CONFIG_TELEPHONY_USE_OWN_NUMBER_FOR_VOICEMAIL_BOOL = "config_telephony_use_own_number_for_voicemail_bool";
     field public static final String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
+    field public static final String KEY_DATA_LIMIT_NOTIFICATION_BOOL = "data_limit_notification_bool";
     field public static final String KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG = "data_limit_threshold_bytes_long";
+    field public static final String KEY_DATA_RAPID_NOTIFICATION_BOOL = "data_rapid_notification_bool";
+    field public static final String KEY_DATA_WARNING_NOTIFICATION_BOOL = "data_warning_notification_bool";
     field public static final String KEY_DATA_WARNING_THRESHOLD_BYTES_LONG = "data_warning_threshold_bytes_long";
     field public static final String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
     field public static final String KEY_DEFAULT_VM_NUMBER_ROAMING_AND_IMS_UNREGISTERED_STRING = "default_vm_number_roaming_and_ims_unregistered_string";
@@ -51081,6 +51089,9 @@
     method public boolean dispatchUnhandledMove(android.view.View, int);
     method protected void dispatchVisibilityChanged(@NonNull android.view.View, int);
     method public void dispatchWindowFocusChanged(boolean);
+    method public void dispatchWindowInsetsAnimationFinished(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation);
+    method @NonNull public android.view.WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull android.view.WindowInsets);
+    method @NonNull public android.view.WindowInsetsAnimationCallback.AnimationBounds dispatchWindowInsetsAnimationStarted(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation, @NonNull android.view.WindowInsetsAnimationCallback.AnimationBounds);
     method public void dispatchWindowSystemUiVisiblityChanged(int);
     method public void dispatchWindowVisibilityChanged(int);
     method @CallSuper public void draw(android.graphics.Canvas);
@@ -51261,6 +51272,7 @@
     method @android.view.ViewDebug.ExportedProperty(category="layout") public final int getWidth();
     method protected int getWindowAttachCount();
     method public android.view.WindowId getWindowId();
+    method @Nullable public android.view.WindowInsetsController getWindowInsetsController();
     method public int getWindowSystemUiVisibility();
     method public android.os.IBinder getWindowToken();
     method public int getWindowVisibility();
@@ -51599,6 +51611,7 @@
     method public void setVisibility(int);
     method @Deprecated public void setWillNotCacheDrawing(boolean);
     method public void setWillNotDraw(boolean);
+    method public void setWindowInsetsAnimationCallback(@Nullable android.view.WindowInsetsAnimationCallback);
     method public void setX(float);
     method public void setY(float);
     method public void setZ(float);
@@ -52485,6 +52498,7 @@
     method public android.transition.Transition getExitTransition();
     method protected final int getFeatures();
     method protected final int getForcedWindowFlags();
+    method @Nullable public android.view.WindowInsetsController getInsetsController();
     method @NonNull public abstract android.view.LayoutInflater getLayoutInflater();
     method protected final int getLocalFeatures();
     method public android.media.session.MediaController getMediaController();
@@ -52700,7 +52714,9 @@
     method @NonNull public android.view.WindowInsets consumeStableInsets();
     method @NonNull public android.view.WindowInsets consumeSystemWindowInsets();
     method @Nullable public android.view.DisplayCutout getDisplayCutout();
+    method @NonNull public android.graphics.Insets getInsets(int);
     method @NonNull public android.graphics.Insets getMandatorySystemGestureInsets();
+    method @NonNull public android.graphics.Insets getMaxInsets(int) throws java.lang.IllegalArgumentException;
     method public int getStableInsetBottom();
     method public int getStableInsetLeft();
     method public int getStableInsetRight();
@@ -52719,6 +52735,7 @@
     method @NonNull public android.view.WindowInsets inset(@IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
     method public boolean isConsumed();
     method public boolean isRound();
+    method public boolean isVisible(int);
     method @Deprecated @NonNull public android.view.WindowInsets replaceSystemWindowInsets(int, int, int, int);
     method @Deprecated @NonNull public android.view.WindowInsets replaceSystemWindowInsets(android.graphics.Rect);
   }
@@ -52728,11 +52745,76 @@
     ctor public WindowInsets.Builder(@NonNull android.view.WindowInsets);
     method @NonNull public android.view.WindowInsets build();
     method @NonNull public android.view.WindowInsets.Builder setDisplayCutout(@Nullable android.view.DisplayCutout);
+    method @NonNull public android.view.WindowInsets.Builder setInsets(int, @NonNull android.graphics.Insets);
     method @NonNull public android.view.WindowInsets.Builder setMandatorySystemGestureInsets(@NonNull android.graphics.Insets);
+    method @NonNull public android.view.WindowInsets.Builder setMaxInsets(int, @NonNull android.graphics.Insets) throws java.lang.IllegalArgumentException;
     method @NonNull public android.view.WindowInsets.Builder setStableInsets(@NonNull android.graphics.Insets);
     method @NonNull public android.view.WindowInsets.Builder setSystemGestureInsets(@NonNull android.graphics.Insets);
     method @NonNull public android.view.WindowInsets.Builder setSystemWindowInsets(@NonNull android.graphics.Insets);
     method @NonNull public android.view.WindowInsets.Builder setTappableElementInsets(@NonNull android.graphics.Insets);
+    method @NonNull public android.view.WindowInsets.Builder setVisible(int, boolean);
+  }
+
+  public static final class WindowInsets.Type {
+    method public static int all();
+    method public static int captionBar();
+    method public static int ime();
+    method public static int mandatorySystemGestures();
+    method public static int navigationBars();
+    method public static int statusBars();
+    method public static int systemBars();
+    method public static int systemGestures();
+    method public static int tappableElement();
+    method public static int windowDecor();
+  }
+
+  public interface WindowInsetsAnimationCallback {
+    method public default void onFinished(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation);
+    method @NonNull public android.view.WindowInsets onProgress(@NonNull android.view.WindowInsets);
+    method @NonNull public default android.view.WindowInsetsAnimationCallback.AnimationBounds onStarted(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation, @NonNull android.view.WindowInsetsAnimationCallback.AnimationBounds);
+  }
+
+  public static final class WindowInsetsAnimationCallback.AnimationBounds {
+    ctor public WindowInsetsAnimationCallback.AnimationBounds(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets);
+    method @NonNull public android.graphics.Insets getLowerBound();
+    method @NonNull public android.graphics.Insets getUpperBound();
+    method @NonNull public android.view.WindowInsetsAnimationCallback.AnimationBounds inset(@NonNull android.graphics.Insets);
+  }
+
+  public static final class WindowInsetsAnimationCallback.InsetsAnimation {
+    ctor public WindowInsetsAnimationCallback.InsetsAnimation(int, @Nullable android.view.animation.Interpolator, long);
+    method public long getDurationMillis();
+    method @FloatRange(from=0.0f, to=1.0f) public float getFraction();
+    method public float getInterpolatedFraction();
+    method @Nullable public android.view.animation.Interpolator getInterpolator();
+    method public int getTypeMask();
+    method public void setDuration(long);
+    method public void setFraction(@FloatRange(from=0.0f, to=1.0f) float);
+  }
+
+  public interface WindowInsetsAnimationControlListener {
+    method public void onCancelled();
+    method public void onReady(@NonNull android.view.WindowInsetsAnimationController, int);
+  }
+
+  public interface WindowInsetsAnimationController {
+    method public void finish(boolean);
+    method @FloatRange(from=0.0f, to=1.0f) public float getCurrentFraction();
+    method @NonNull public android.graphics.Insets getCurrentInsets();
+    method @NonNull public android.graphics.Insets getHiddenStateInsets();
+    method @NonNull public android.graphics.Insets getShownStateInsets();
+    method public int getTypes();
+    method public void setInsetsAndAlpha(@Nullable android.graphics.Insets, @FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=0.0f, to=1.0f) float);
+  }
+
+  public interface WindowInsetsController {
+    method public default void controlInputMethodAnimation(long, @NonNull android.view.WindowInsetsAnimationControlListener);
+    method public default void hideInputMethod();
+    method public void setSystemBarsAppearance(int);
+    method public void setSystemBarsBehavior(int);
+    method public default void showInputMethod();
+    field public static final int APPEARANCE_LIGHT_NAVIGATION_BARS = 16; // 0x10
+    field public static final int APPEARANCE_LIGHT_STATUS_BARS = 8; // 0x8
   }
 
   public interface WindowManager extends android.view.ViewManager {
diff --git a/api/system-current.txt b/api/system-current.txt
index ebcda3d..7504582 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -546,10 +546,12 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method @Deprecated public void onGetInstantAppIntentFilter(@Nullable int[], @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback);
     method @Deprecated public void onGetInstantAppIntentFilter(@NonNull android.content.Intent, @Nullable int[], @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback);
-    method public void onGetInstantAppIntentFilter(@NonNull android.content.Intent, @Nullable int[], @NonNull android.os.UserHandle, @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback);
+    method @Deprecated public void onGetInstantAppIntentFilter(@NonNull android.content.Intent, @Nullable int[], @NonNull android.os.UserHandle, @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback);
+    method public void onGetInstantAppIntentFilter(@NonNull android.content.pm.InstantAppRequestInfo, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback);
     method @Deprecated public void onGetInstantAppResolveInfo(@Nullable int[], @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback);
     method @Deprecated public void onGetInstantAppResolveInfo(@NonNull android.content.Intent, @Nullable int[], @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback);
-    method public void onGetInstantAppResolveInfo(@NonNull android.content.Intent, @Nullable int[], @NonNull android.os.UserHandle, @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback);
+    method @Deprecated public void onGetInstantAppResolveInfo(@NonNull android.content.Intent, @Nullable int[], @NonNull android.os.UserHandle, @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback);
+    method public void onGetInstantAppResolveInfo(@NonNull android.content.pm.InstantAppRequestInfo, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback);
   }
 
   public static final class InstantAppResolverService.InstantAppResolutionCallback {
@@ -1350,6 +1352,14 @@
     field public static final int OPTIONAL_CODECS_SUPPORT_UNKNOWN = -1; // 0xffffffff
   }
 
+  public final class BluetoothA2dpSink implements android.bluetooth.BluetoothProfile {
+    method public void finalize();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isAudioPlaying(@Nullable android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice, int);
+    field @RequiresPermission(android.Manifest.permission.BLUETOOTH) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED";
+  }
+
   public final class BluetoothAdapter {
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean addOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean connectAllEnabledProfiles(@NonNull android.bluetooth.BluetoothDevice);
@@ -1920,6 +1930,18 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.InstantAppIntentFilter> CREATOR;
   }
 
+  public final class InstantAppRequestInfo implements android.os.Parcelable {
+    ctor public InstantAppRequestInfo(@NonNull android.content.Intent, @Nullable int[], @NonNull android.os.UserHandle, boolean, @NonNull String);
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.InstantAppRequestInfo> CREATOR;
+    field @Nullable public final int[] hostDigestPrefix;
+    field @NonNull public final android.content.Intent intent;
+    field public final boolean isRequesterInstantApp;
+    field @NonNull public final String token;
+    field @NonNull public final android.os.UserHandle userHandle;
+  }
+
   public final class InstantAppResolveInfo implements android.os.Parcelable {
     ctor public InstantAppResolveInfo(@NonNull android.content.pm.InstantAppResolveInfo.InstantAppDigest, @Nullable String, @Nullable java.util.List<android.content.pm.InstantAppIntentFilter>, int);
     ctor public InstantAppResolveInfo(@NonNull android.content.pm.InstantAppResolveInfo.InstantAppDigest, @Nullable String, @Nullable java.util.List<android.content.pm.InstantAppIntentFilter>, long, @Nullable android.os.Bundle);
@@ -4173,18 +4195,20 @@
 package android.media.session {
 
   public final class MediaSessionManager {
-    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.Callback);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void addOnMediaKeyEventDispatchedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.OnMediaKeyEventDispatchedListener);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void addOnMediaKeyEventSessionChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.OnMediaKeyEventSessionChangedListener);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void removeOnMediaKeyEventDispatchedListener(@NonNull android.media.session.MediaSessionManager.OnMediaKeyEventDispatchedListener);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void removeOnMediaKeyEventSessionChangedListener(@NonNull android.media.session.MediaSessionManager.OnMediaKeyEventSessionChangedListener);
     method @RequiresPermission(android.Manifest.permission.SET_MEDIA_KEY_LISTENER) public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, @Nullable android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER) public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, @Nullable android.os.Handler);
-    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void unregisterCallback(@NonNull android.media.session.MediaSessionManager.Callback);
   }
 
-  public abstract static class MediaSessionManager.Callback {
-    ctor public MediaSessionManager.Callback();
-    method public abstract void onAddressedPlayerChanged(android.media.session.MediaSession.Token);
-    method public abstract void onAddressedPlayerChanged(android.content.ComponentName);
-    method public abstract void onMediaKeyEventDispatched(android.view.KeyEvent, android.media.session.MediaSession.Token);
-    method public abstract void onMediaKeyEventDispatched(android.view.KeyEvent, android.content.ComponentName);
+  public static interface MediaSessionManager.OnMediaKeyEventDispatchedListener {
+    method public default void onMediaKeyEventDispatched(@NonNull android.view.KeyEvent, @NonNull String, @NonNull android.media.session.MediaSession.Token);
+  }
+
+  public static interface MediaSessionManager.OnMediaKeyEventSessionChangedListener {
+    method public default void onMediaKeyEventSessionChanged(@NonNull String, @Nullable android.media.session.MediaSession.Token);
   }
 
   public static interface MediaSessionManager.OnMediaKeyListener {
@@ -4538,6 +4562,14 @@
     method public void onUpstreamChanged(@Nullable android.net.Network);
   }
 
+  public class InvalidPacketException extends java.lang.Exception {
+    ctor public InvalidPacketException(int);
+    field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb
+    field public static final int ERROR_INVALID_LENGTH = -23; // 0xffffffe9
+    field public static final int ERROR_INVALID_PORT = -22; // 0xffffffea
+    field public final int error;
+  }
+
   public final class IpConfiguration implements android.os.Parcelable {
     ctor public IpConfiguration();
     ctor public IpConfiguration(@NonNull android.net.IpConfiguration);
@@ -4588,6 +4620,15 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecTransform buildTunnelModeTransform(@NonNull java.net.InetAddress, @NonNull android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
   }
 
+  public class KeepalivePacketData {
+    ctor protected KeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[]) throws android.net.InvalidPacketException;
+    method @NonNull public byte[] getPacket();
+    field @NonNull public final java.net.InetAddress dstAddress;
+    field public final int dstPort;
+    field @NonNull public final java.net.InetAddress srcAddress;
+    field public final int srcPort;
+  }
+
   public class LinkAddress implements android.os.Parcelable {
     ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int);
     ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
@@ -4867,7 +4908,7 @@
     method @NonNull public java.util.List<android.net.LinkAddress> getInternalAddresses();
     method @NonNull public java.util.List<java.net.InetAddress> getInternalDhcpServers();
     method @NonNull public java.util.List<java.net.InetAddress> getInternalDnsServers();
-    method @NonNull public java.util.List<android.net.LinkAddress> getInternalSubnets();
+    method @NonNull public java.util.List<android.net.IpPrefix> getInternalSubnets();
     method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getOutboundTrafficSelectors();
   }
 
@@ -4936,6 +4977,7 @@
   public final class IkeSessionConfiguration {
     ctor public IkeSessionConfiguration();
     method @NonNull public String getRemoteApplicationVersion();
+    method @NonNull public java.util.List<byte[]> getRemoteVendorIDs();
     method public boolean isIkeExtensionEnabled(int);
     field public static final int EXTENSION_TYPE_FRAGMENTATION = 1; // 0x1
     field public static final int EXTENSION_TYPE_MOBIKE = 2; // 0x2
@@ -4955,9 +4997,9 @@
     ctor public IkeSessionParams.Builder();
     method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.IkeSaProposal);
     method @NonNull public android.net.ipsec.ike.IkeSessionParams build();
-    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthDigitalSignature(@NonNull java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.security.PrivateKey);
-    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthDigitalSignature(@NonNull java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.util.List<java.security.cert.X509Certificate>, @NonNull java.security.PrivateKey);
-    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthEap(@NonNull java.security.cert.X509Certificate, @NonNull android.net.eap.EapSessionConfig);
+    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthDigitalSignature(@Nullable java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.security.PrivateKey);
+    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthDigitalSignature(@Nullable java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.util.List<java.security.cert.X509Certificate>, @NonNull java.security.PrivateKey);
+    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthEap(@Nullable java.security.cert.X509Certificate, @NonNull android.net.eap.EapSessionConfig);
     method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthPsk(@NonNull byte[]);
     method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setLocalIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
     method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setRemoteIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
@@ -4975,7 +5017,7 @@
   }
 
   public static class IkeSessionParams.IkeAuthDigitalSignRemoteConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
-    method @NonNull public java.security.cert.X509Certificate getRemoteCaCert();
+    method @Nullable public java.security.cert.X509Certificate getRemoteCaCert();
   }
 
   public static class IkeSessionParams.IkeAuthEapConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
@@ -5039,12 +5081,10 @@
     ctor public TunnelModeChildSessionParams.Builder();
     method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
     method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalAddressRequest(int);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalAddressRequest(@NonNull java.net.InetAddress, int);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalAddressRequest(@NonNull java.net.Inet4Address);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalAddressRequest(@NonNull java.net.Inet6Address, int);
     method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalDhcpServerRequest(int);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalDhcpServerRequest(@NonNull java.net.InetAddress);
     method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalDnsServerRequest(int);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalDnsServerRequest(@NonNull java.net.InetAddress);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalSubnetRequest(int);
     method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
     method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal);
     method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams build();
@@ -5068,9 +5108,6 @@
   public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Netmask extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
   }
 
-  public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Subnet extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
-  }
-
   public static interface TunnelModeChildSessionParams.ConfigRequestIpv6Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
     method @Nullable public java.net.Inet6Address getAddress();
     method public int getPrefixLength();
@@ -5080,9 +5117,6 @@
     method @Nullable public java.net.Inet6Address getAddress();
   }
 
-  public static interface TunnelModeChildSessionParams.ConfigRequestIpv6Subnet extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
-  }
-
 }
 
 package android.net.ipsec.ike.exceptions {
@@ -9637,9 +9671,6 @@
 
   public class TelephonyManager {
     method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void carrierActionReportDefaultNetworkStatus(int, boolean);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void carrierActionResetAll(int);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void carrierActionSetRadioEnabled(int, boolean);
     method public int checkCarrierPrivilegesForPackage(String);
     method public int checkCarrierPrivilegesForPackageAnyPhone(String);
     method public void dial(String);
@@ -9713,9 +9744,11 @@
     method public boolean needsOtaServiceProvisioning();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void reportDefaultNetworkStatus(boolean);
     method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
     method public void requestModemActivityInfo(@NonNull android.os.ResultReceiver);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetAllCarrierActions();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig();
     method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void resetSettings();
@@ -9729,6 +9762,7 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunisticNetworkState(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setPreferredNetworkTypeBitmask(long);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadio(boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRadioEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadioPower(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSimPowerState(int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSimPowerStateForSlot(int, int);
diff --git a/cmds/svc/src/com/android/commands/svc/DataCommand.java b/cmds/svc/src/com/android/commands/svc/DataCommand.java
index 35510cf..b4dbd1d 100644
--- a/cmds/svc/src/com/android/commands/svc/DataCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/DataCommand.java
@@ -16,12 +16,16 @@
 
 package com.android.commands.svc;
 
-import android.os.ServiceManager;
-import android.os.RemoteException;
-import android.content.Context;
-import com.android.internal.telephony.ITelephony;
-
+/**
+ * @deprecated Please use adb shell cmd phone data enabled/disable instead.
+ */
+@Deprecated
 public class DataCommand extends Svc.Command {
+
+    private static final String DECPRECATED_MESSAGE =
+            "adb shell svc data enable/disable is deprecated;"
+            + "please use adb shell cmd phone data enable/disable instead.";
+
     public DataCommand() {
         super("data");
     }
@@ -33,36 +37,10 @@
     public String longHelp() {
         return shortHelp() + "\n"
                 + "\n"
-                + "usage: svc data [enable|disable]\n"
-                + "         Turn mobile data on or off.\n\n";
+                + DECPRECATED_MESSAGE;
     }
 
     public void run(String[] args) {
-        boolean validCommand = false;
-        if (args.length >= 2) {
-            boolean flag = false;
-            if ("enable".equals(args[1])) {
-                flag = true;
-                validCommand = true;
-            } else if ("disable".equals(args[1])) {
-                flag = false;
-                validCommand = true;
-            }
-            if (validCommand) {
-                ITelephony phoneMgr
-                        = ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
-                try {
-                    if (flag) {
-                        phoneMgr.enableDataConnectivity();
-                    } else
-                        phoneMgr.disableDataConnectivity();
-                }
-                catch (RemoteException e) {
-                    System.err.println("Mobile data operation failed: " + e);
-                }
-                return;
-            }
-        }
-        System.err.println(longHelp());
+        System.err.println(DECPRECATED_MESSAGE);
     }
 }
diff --git a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
index 8b62e2f..d82b151 100644
--- a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
+++ b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
@@ -17,6 +17,8 @@
 package android.accessibilityservice;
 
 
+import static android.accessibilityservice.AccessibilityService.GESTURE_DOUBLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_DOUBLE_TAP_AND_HOLD;
 import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN;
 import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN_AND_LEFT;
 import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN_AND_RIGHT;
@@ -58,6 +60,8 @@
 
     /** @hide */
     @IntDef(prefix = { "GESTURE_" }, value = {
+            GESTURE_DOUBLE_TAP,
+            GESTURE_DOUBLE_TAP_AND_HOLD,
             GESTURE_SWIPE_UP,
             GESTURE_SWIPE_UP_AND_LEFT,
             GESTURE_SWIPE_UP_AND_DOWN,
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 47fdcde..0f619c8 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -300,6 +300,18 @@
     public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 16;
 
     /**
+     * The user has performed a double tap gesture on the touch screen.
+     * @hide
+     */
+    public static final int GESTURE_DOUBLE_TAP = 17;
+
+    /**
+     * The user has performed a double tap and hold gesture on the touch screen.
+     * @hide
+     */
+    public static final int GESTURE_DOUBLE_TAP_AND_HOLD = 18;
+
+    /**
      * The {@link Intent} that must be declared as handled by the service.
      */
     public static final String SERVICE_INTERFACE =
diff --git a/core/java/android/app/IInstantAppResolver.aidl b/core/java/android/app/IInstantAppResolver.aidl
index 7318762..8618fbb 100644
--- a/core/java/android/app/IInstantAppResolver.aidl
+++ b/core/java/android/app/IInstantAppResolver.aidl
@@ -16,15 +16,13 @@
 
 package android.app;
 
-import android.content.Intent;
+import android.content.pm.InstantAppRequestInfo;
 import android.os.IRemoteCallback;
 
 /** @hide */
 oneway interface IInstantAppResolver {
-    void getInstantAppResolveInfoList(in Intent sanitizedIntent, in int[] hostDigestPrefix,
-            int userId, String token, int sequence, IRemoteCallback callback);
+    void getInstantAppResolveInfoList(in InstantAppRequestInfo request, int sequence,
+            IRemoteCallback callback);
 
-    void getInstantAppIntentFilterList(in Intent sanitizedIntent, in int[] hostDigestPrefix,
-            int userId, String token, IRemoteCallback callback);
-
+    void getInstantAppIntentFilterList(in InstantAppRequestInfo request, IRemoteCallback callback);
 }
diff --git a/core/java/android/app/InstantAppResolverService.java b/core/java/android/app/InstantAppResolverService.java
index a7be542..a413c60 100644
--- a/core/java/android/app/InstantAppResolverService.java
+++ b/core/java/android/app/InstantAppResolverService.java
@@ -21,6 +21,7 @@
 import android.annotation.SystemApi;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.InstantAppRequestInfo;
 import android.content.pm.InstantAppResolveInfo;
 import android.os.Build;
 import android.os.Bundle;
@@ -59,8 +60,9 @@
      * Called to retrieve resolve info for instant applications immediately.
      *
      * @param digestPrefix The hash prefix of the instant app's domain.
-     * @deprecated Should implement {@link #onGetInstantAppResolveInfo(Intent, int[], UserHandle,
-     *             String, InstantAppResolutionCallback)}.
+     *
+     * @deprecated Should implement {@link #onGetInstantAppResolveInfo(InstantAppRequestInfo,
+     *             InstantAppResolutionCallback)}
      */
     @Deprecated
     public void onGetInstantAppResolveInfo(@Nullable int[] digestPrefix, @NonNull String token,
@@ -73,8 +75,9 @@
      * sources.
      *
      * @param digestPrefix The hash prefix of the instant app's domain.
-     * @deprecated Should implement {@link #onGetInstantAppIntentFilter(Intent, int[], UserHandle,
-     *             String, InstantAppResolutionCallback)}.
+     *
+     * @deprecated Should implement {@link #onGetInstantAppIntentFilter(InstantAppRequestInfo,
+     *             InstantAppResolutionCallback)}
      */
     @Deprecated
     public void onGetInstantAppIntentFilter(@Nullable int[] digestPrefix, @NonNull String token,
@@ -103,8 +106,8 @@
      *
      * @see InstantAppResolveInfo
      *
-     * @deprecated Should implement {@link #onGetInstantAppResolveInfo(Intent, int[], UserHandle,
-     *             String, InstantAppResolutionCallback)}.
+     * @deprecated Should implement {@link #onGetInstantAppResolveInfo(InstantAppRequestInfo,
+     *             InstantAppResolutionCallback)}
      */
     @Deprecated
     public void onGetInstantAppResolveInfo(@NonNull Intent sanitizedIntent,
@@ -134,8 +137,8 @@
      *              {@link Intent#EXTRA_INSTANT_APP_TOKEN}.
      * @param callback The {@link InstantAppResolutionCallback} to provide results to.
      *
-     * @deprecated Should implement {@link #onGetInstantAppIntentFilter(Intent, int[], UserHandle,
-     *             String, InstantAppResolutionCallback)}.
+     * @deprecated Should implement {@link #onGetInstantAppIntentFilter(InstantAppRequestInfo,
+     *             InstantAppResolutionCallback)}
      */
     @Deprecated
     public void onGetInstantAppIntentFilter(@NonNull Intent sanitizedIntent,
@@ -170,7 +173,11 @@
      * @param callback The {@link InstantAppResolutionCallback} to provide results to.
      *
      * @see InstantAppResolveInfo
+     *
+     * @deprecated Should implement {@link #onGetInstantAppResolveInfo(InstantAppRequestInfo,
+     *             InstantAppResolutionCallback
      */
+    @Deprecated
     public void onGetInstantAppResolveInfo(@NonNull Intent sanitizedIntent,
             @Nullable int[] hostDigestPrefix, @NonNull UserHandle userHandle,
             @NonNull String token, @NonNull InstantAppResolutionCallback callback) {
@@ -193,7 +200,11 @@
      *              Intent, int[], UserHandle, String, InstantAppResolutionCallback)} and provided
      *              to the currently visible installer via {@link Intent#EXTRA_INSTANT_APP_TOKEN}.
      * @param callback The {@link InstantAppResolutionCallback} to provide results to.
+     *
+     * @deprecated Should implement {@link #onGetInstantAppIntentFilter(InstantAppRequestInfo,
+     *             InstantAppResolutionCallback)}
      */
+    @Deprecated
     public void onGetInstantAppIntentFilter(@NonNull Intent sanitizedIntent,
             @Nullable int[] hostDigestPrefix, @NonNull UserHandle userHandle,
             @NonNull String token, @NonNull InstantAppResolutionCallback callback) {
@@ -202,6 +213,41 @@
     }
 
     /**
+     * Called to retrieve resolve info for instant applications immediately. The response will be
+     * ignored if not provided within a reasonable time. {@link InstantAppResolveInfo}s provided
+     * in response to this method may be partial to request a second phase of resolution which will
+     * result in a subsequent call to {@link #onGetInstantAppIntentFilter(InstantAppRequestInfo,
+     * InstantAppResolutionCallback)}
+     *
+     * @param request The parameters for this resolution request
+     * @param callback The {@link InstantAppResolutionCallback} to provide results to.
+     *
+     * @see InstantAppResolveInfo
+     */
+    public void onGetInstantAppResolveInfo(@NonNull InstantAppRequestInfo request,
+            @NonNull InstantAppResolutionCallback callback) {
+        // If not overridden, forward to the old method.
+        onGetInstantAppResolveInfo(request.intent, request.hostDigestPrefix, request.userHandle,
+                request.token, callback);
+    }
+
+    /**
+     * Called to retrieve intent filters for potentially matching instant applications. Unlike
+     * {@link #onGetInstantAppResolveInfo(InstantAppRequestInfo, InstantAppResolutionCallback)},
+     * the response may take as long as necessary to respond. All {@link InstantAppResolveInfo}s
+     * provided in response to this method must be completely populated.
+     *
+     * @param request The parameters for this resolution request
+     * @param callback The {@link InstantAppResolutionCallback} to provide results to.
+     */
+    public void onGetInstantAppIntentFilter(@NonNull InstantAppRequestInfo request,
+            @NonNull InstantAppResolutionCallback callback) {
+        // If not overridden, forward to the old method.
+        onGetInstantAppIntentFilter(request.intent, request.hostDigestPrefix, request.userHandle,
+                request.token, callback);
+    }
+
+    /**
      * Returns a {@link Looper} to perform service operations on.
      */
     Looper getLooper() {
@@ -218,35 +264,29 @@
     public final IBinder onBind(Intent intent) {
         return new IInstantAppResolver.Stub() {
             @Override
-            public void getInstantAppResolveInfoList(Intent sanitizedIntent, int[] digestPrefix,
-                    int userId, String token, int sequence, IRemoteCallback callback) {
+            public void getInstantAppResolveInfoList(InstantAppRequestInfo request, int sequence,
+                    IRemoteCallback callback) {
                 if (DEBUG_INSTANT) {
-                    Slog.v(TAG, "[" + token + "] Phase1 called; posting");
+                    Slog.v(TAG, "[" + request.token + "] Phase1 called; posting");
                 }
                 final SomeArgs args = SomeArgs.obtain();
-                args.arg1 = callback;
-                args.arg2 = digestPrefix;
-                args.arg3 = userId;
-                args.arg4 = token;
-                args.arg5 = sanitizedIntent;
-                mHandler.obtainMessage(ServiceHandler.MSG_GET_INSTANT_APP_RESOLVE_INFO,
-                        sequence, 0, args).sendToTarget();
+                args.arg1 = request;
+                args.arg2 = callback;
+                mHandler.obtainMessage(ServiceHandler.MSG_GET_INSTANT_APP_RESOLVE_INFO, sequence,
+                        0, args).sendToTarget();
             }
 
             @Override
-            public void getInstantAppIntentFilterList(Intent sanitizedIntent,
-                    int[] digestPrefix, int userId, String token, IRemoteCallback callback) {
+            public void getInstantAppIntentFilterList(InstantAppRequestInfo request,
+                    IRemoteCallback callback) {
                 if (DEBUG_INSTANT) {
-                    Slog.v(TAG, "[" + token + "] Phase2 called; posting");
+                    Slog.v(TAG, "[" + request.token + "] Phase2 called; posting");
                 }
                 final SomeArgs args = SomeArgs.obtain();
-                args.arg1 = callback;
-                args.arg2 = digestPrefix;
-                args.arg3 = userId;
-                args.arg4 = token;
-                args.arg5 = sanitizedIntent;
-                mHandler.obtainMessage(ServiceHandler.MSG_GET_INSTANT_APP_INTENT_FILTER,
-                        args).sendToTarget();
+                args.arg1 = request;
+                args.arg2 = callback;
+                mHandler.obtainMessage(ServiceHandler.MSG_GET_INSTANT_APP_INTENT_FILTER, args)
+                        .sendToTarget();
             }
         };
     }
@@ -287,36 +327,33 @@
             switch (action) {
                 case MSG_GET_INSTANT_APP_RESOLVE_INFO: {
                     final SomeArgs args = (SomeArgs) message.obj;
-                    final IRemoteCallback callback = (IRemoteCallback) args.arg1;
-                    final int[] digestPrefix = (int[]) args.arg2;
-                    final int userId = (int) args.arg3;
-                    final String token = (String) args.arg4;
-                    final Intent intent = (Intent) args.arg5;
+                    final InstantAppRequestInfo request = (InstantAppRequestInfo) args.arg1;
+                    final IRemoteCallback callback = (IRemoteCallback) args.arg2;
+                    args.recycle();
                     final int sequence = message.arg1;
                     if (DEBUG_INSTANT) {
-                        Slog.d(TAG, "[" + token + "] Phase1 request;"
-                                + " prefix: " + Arrays.toString(digestPrefix)
-                                + ", userId: " + userId);
+                        Slog.d(TAG, "[" + request.token + "] Phase1 request;"
+                                + " prefix: " + Arrays.toString(request.hostDigestPrefix)
+                                + ", userId: " + request.userHandle.getIdentifier());
                     }
-                    onGetInstantAppResolveInfo(intent, digestPrefix, UserHandle.of(userId), token,
+                    onGetInstantAppResolveInfo(request,
                             new InstantAppResolutionCallback(sequence, callback));
                 } break;
 
                 case MSG_GET_INSTANT_APP_INTENT_FILTER: {
                     final SomeArgs args = (SomeArgs) message.obj;
-                    final IRemoteCallback callback = (IRemoteCallback) args.arg1;
-                    final int[] digestPrefix = (int[]) args.arg2;
-                    final int userId = (int) args.arg3;
-                    final String token = (String) args.arg4;
-                    final Intent intent = (Intent) args.arg5;
+                    final InstantAppRequestInfo request = (InstantAppRequestInfo) args.arg1;
+                    final IRemoteCallback callback = (IRemoteCallback) args.arg2;
+                    args.recycle();
                     if (DEBUG_INSTANT) {
-                        Slog.d(TAG, "[" + token + "] Phase2 request;"
-                                + " prefix: " + Arrays.toString(digestPrefix)
-                                + ", userId: " + userId);
+                        Slog.d(TAG, "[" + request.token + "] Phase2 request;"
+                                + " prefix: " + Arrays.toString(request.hostDigestPrefix)
+                                + ", userId: " + request.userHandle.getIdentifier());
                     }
-                    onGetInstantAppIntentFilter(intent, digestPrefix, UserHandle.of(userId), token,
+                    onGetInstantAppIntentFilter(request,
                             new InstantAppResolutionCallback(-1 /*sequence*/, callback));
-                } break;
+                }
+                break;
 
                 default: {
                     throw new IllegalArgumentException("Unknown message: " + action);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 6e7ead1..7332978 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1349,6 +1349,9 @@
      * Broadcast action: send when any policy admin changes a policy.
      * This is generally used to find out when a new policy is in effect.
      *
+     * If the profile owner of an organization-owned managed profile changes some user
+     * restriction explicitly on the parent user, this broadcast will <em>not</em> be
+     * sent to the parent user.
      * @hide
      */
     @UnsupportedAppUsage
@@ -7958,18 +7961,23 @@
      * <p>
      * The calling device admin must be a profile or device owner; if it is not, a security
      * exception will be thrown.
+     * <p>
+     * The profile owner of an organization-owned managed profile may invoke this method on
+     * the {@link DevicePolicyManager} instance it obtained from
+     * {@link #getParentProfileInstance(ComponentName)}, for enforcing device-wide restrictions.
+     * <p>
+     * See the constants in {@link android.os.UserManager} for the list of restrictions that can
+     * be enforced device-wide.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @param key The key of the restriction. See the constants in {@link android.os.UserManager}
-     *            for the list of keys.
+     * @param key   The key of the restriction.
      * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void addUserRestriction(@NonNull ComponentName admin,
             @UserManager.UserRestrictionKey String key) {
-        throwIfParentInstance("addUserRestriction");
         if (mService != null) {
             try {
-                mService.setUserRestriction(admin, key, true);
+                mService.setUserRestriction(admin, key, true, mParentInstance);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -7981,18 +7989,22 @@
      * <p>
      * The calling device admin must be a profile or device owner; if it is not, a security
      * exception will be thrown.
+     * <p>
+     * The profile owner of an organization-owned managed profile may invoke this method on
+     * the {@link DevicePolicyManager} instance it obtained from
+     * {@link #getParentProfileInstance(ComponentName)}, for clearing device-wide restrictions.
+     * <p>
+     * See the constants in {@link android.os.UserManager} for the list of restrictions.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @param key The key of the restriction. See the constants in {@link android.os.UserManager}
-     *            for the list of keys.
+     * @param key   The key of the restriction.
      * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public void clearUserRestriction(@NonNull ComponentName admin,
             @UserManager.UserRestrictionKey String key) {
-        throwIfParentInstance("clearUserRestriction");
         if (mService != null) {
             try {
-                mService.setUserRestriction(admin, key, false);
+                mService.setUserRestriction(admin, key, false, mParentInstance);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -8006,16 +8018,20 @@
      * The target user may have more restrictions set by the system or other device owner / profile
      * owner. To get all the user restrictions currently set, use
      * {@link UserManager#getUserRestrictions()}.
+     * <p>
+     * The profile owner of an organization-owned managed profile may invoke this method on
+     * the {@link DevicePolicyManager} instance it obtained from
+     * {@link #getParentProfileInstance(ComponentName)}, for retrieving device-wide restrictions
+     * it previously set with {@link #addUserRestriction(ComponentName, String)}.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public @NonNull Bundle getUserRestrictions(@NonNull ComponentName admin) {
-        throwIfParentInstance("getUserRestrictions");
         Bundle ret = null;
         if (mService != null) {
             try {
-                ret = mService.getUserRestrictions(admin);
+                ret = mService.getUserRestrictions(admin, mParentInstance);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 949e8ab..9c82ff6 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -208,8 +208,8 @@
     void setRestrictionsProvider(in ComponentName who, in ComponentName provider);
     ComponentName getRestrictionsProvider(int userHandle);
 
-    void setUserRestriction(in ComponentName who, in String key, boolean enable);
-    Bundle getUserRestrictions(in ComponentName who);
+    void setUserRestriction(in ComponentName who, in String key, boolean enable, boolean parent);
+    Bundle getUserRestrictions(in ComponentName who, boolean parent);
     void addCrossProfileIntentFilter(in ComponentName admin, in IntentFilter filter, int flags);
     void clearCrossProfileIntentFilters(in ComponentName admin);
 
diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java
index cf33676..c6957e1 100755
--- a/core/java/android/bluetooth/BluetoothA2dpSink.java
+++ b/core/java/android/bluetooth/BluetoothA2dpSink.java
@@ -17,7 +17,9 @@
 package android.bluetooth;
 
 import android.Manifest;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
@@ -39,6 +41,7 @@
  *
  * @hide
  */
+@SystemApi
 public final class BluetoothA2dpSink implements BluetoothProfile {
     private static final String TAG = "BluetoothA2dpSink";
     private static final boolean DBG = true;
@@ -59,71 +62,14 @@
      * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
      * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
-     * receive.
+     * @hide
      */
+    @SystemApi
+    @SuppressLint("ActionValue")
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
     public static final String ACTION_CONNECTION_STATE_CHANGED =
             "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED";
 
-    /**
-     * Intent used to broadcast the change in the Playing state of the A2DP Sink
-     * profile.
-     *
-     * <p>This intent will have 3 extras:
-     * <ul>
-     * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
-     * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
-     * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
-     * </ul>
-     *
-     * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
-     * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING},
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
-     * receive.
-     */
-    public static final String ACTION_PLAYING_STATE_CHANGED =
-            "android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED";
-
-    /**
-     * A2DP sink device is streaming music. This state can be one of
-     * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
-     * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
-     */
-    public static final int STATE_PLAYING = 10;
-
-    /**
-     * A2DP sink device is NOT streaming music. This state can be one of
-     * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
-     * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
-     */
-    public static final int STATE_NOT_PLAYING = 11;
-
-    /**
-     * Intent used to broadcast the change in the Playing state of the A2DP Sink
-     * profile.
-     *
-     * <p>This intent will have 3 extras:
-     * <ul>
-     * <li> {@link #EXTRA_AUDIO_CONFIG} - The audio configuration for the remote device. </li>
-     * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
-     * </ul>
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
-     * receive.
-     */
-    public static final String ACTION_AUDIO_CONFIG_CHANGED =
-            "android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED";
-
-    /**
-     * Extra for the {@link #ACTION_AUDIO_CONFIG_CHANGED} intent.
-     *
-     * This extra represents the current audio configuration of the A2DP source device.
-     * {@see BluetoothAudioConfig}
-     */
-    public static final String EXTRA_AUDIO_CONFIG =
-            "android.bluetooth.a2dp-sink.profile.extra.AUDIO_CONFIG";
-
     private BluetoothAdapter mAdapter;
     private final BluetoothProfileConnector<IBluetoothA2dpSink> mProfileConnector =
             new BluetoothProfileConnector(this, BluetoothProfile.A2DP_SINK,
@@ -170,13 +116,11 @@
      * the state. Users can get the connection state of the profile
      * from this intent.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
-     * permission.
-     *
      * @param device Remote Bluetooth Device
      * @return false on immediate error, true otherwise
      * @hide
      */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     public boolean connect(BluetoothDevice device) {
         if (DBG) log("connect(" + device + ")");
         final IBluetoothA2dpSink service = getService();
@@ -210,14 +154,12 @@
      * {@link #STATE_DISCONNECTING} can be used to distinguish between the
      * two scenarios.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
-     * permission.
-     *
      * @param device Remote Bluetooth Device
      * @return false on immediate error, true otherwise
      * @hide
      */
     @UnsupportedAppUsage
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     public boolean disconnect(BluetoothDevice device) {
         if (DBG) log("disconnect(" + device + ")");
         final IBluetoothA2dpSink service = getService();
@@ -235,6 +177,8 @@
 
     /**
      * {@inheritDoc}
+     *
+     * @hide
      */
     @Override
     public List<BluetoothDevice> getConnectedDevices() {
@@ -254,6 +198,8 @@
 
     /**
      * {@inheritDoc}
+     *
+     * @hide
      */
     @Override
     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
@@ -273,6 +219,8 @@
 
     /**
      * {@inheritDoc}
+     *
+     * @hide
      */
     @Override
     public int getConnectionState(BluetoothDevice device) {
@@ -300,6 +248,8 @@
      * @return audio configuration for the device, or null
      *
      * {@see BluetoothAudioConfig}
+     *
+     * @hide
      */
     public BluetoothAudioConfig getAudioConfig(BluetoothDevice device) {
         if (VDBG) log("getAudioConfig(" + device + ")");
@@ -347,7 +297,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
-    public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
+    public boolean setConnectionPolicy(@Nullable BluetoothDevice device, int connectionPolicy) {
         if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
         final IBluetoothA2dpSink service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
@@ -395,7 +345,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public int getConnectionPolicy(BluetoothDevice device) {
+    public int getConnectionPolicy(@Nullable BluetoothDevice device) {
         if (VDBG) log("getConnectionPolicy(" + device + ")");
         final IBluetoothA2dpSink service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
@@ -411,13 +361,16 @@
     }
 
     /**
-     * Check if A2DP profile is streaming music.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     * Check if audio is playing on the bluetooth device (A2DP profile is streaming music).
      *
      * @param device BluetoothDevice device
+     * @return true if audio is playing (A2dp is streaming music), false otherwise
+     *
+     * @hide
      */
-    public boolean isA2dpPlaying(BluetoothDevice device) {
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public boolean isAudioPlaying(@Nullable BluetoothDevice device) {
         final IBluetoothA2dpSink service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
             try {
@@ -448,9 +401,9 @@
                 return "connected";
             case STATE_DISCONNECTING:
                 return "disconnecting";
-            case STATE_PLAYING:
+            case BluetoothA2dp.STATE_PLAYING:
                 return "playing";
-            case STATE_NOT_PLAYING:
+            case BluetoothA2dp.STATE_NOT_PLAYING:
                 return "not playing";
             default:
                 return "<unknown state " + state + ">";
diff --git a/core/java/android/content/pm/AuxiliaryResolveInfo.java b/core/java/android/content/pm/AuxiliaryResolveInfo.java
index 202df50..7d07e1d 100644
--- a/core/java/android/content/pm/AuxiliaryResolveInfo.java
+++ b/core/java/android/content/pm/AuxiliaryResolveInfo.java
@@ -46,17 +46,21 @@
     public final Intent failureIntent;
     /** The matching filters for this resolve info. */
     public final List<AuxiliaryFilter> filters;
+    /** Stored {@link InstantAppRequest#hostDigestPrefixSecure} to prevent re-generation */
+    public final int[] hostDigestPrefixSecure;
 
     /** Create a response for installing an instant application. */
     public AuxiliaryResolveInfo(@NonNull String token,
             boolean needsPhase2,
             @Nullable Intent failureIntent,
-            @Nullable List<AuxiliaryFilter> filters) {
+            @Nullable List<AuxiliaryFilter> filters,
+            @Nullable int[] hostDigestPrefix) {
         this.token = token;
         this.needsPhaseTwo = needsPhase2;
         this.failureIntent = failureIntent;
         this.filters = filters;
         this.installFailureActivity = null;
+        this.hostDigestPrefixSecure = hostDigestPrefix;
     }
 
     /** Create a response for installing a split on demand. */
@@ -69,6 +73,7 @@
         this.token = null;
         this.needsPhaseTwo = false;
         this.failureIntent = failureIntent;
+        this.hostDigestPrefixSecure = null;
     }
 
     /** Create a response for installing a split on demand. */
@@ -126,4 +131,4 @@
                     + ", splitName='" + splitName + '\'' + '}';
         }
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/android/content/pm/BaseParceledListSlice.java b/core/java/android/content/pm/BaseParceledListSlice.java
index 4178309..ffbca16 100644
--- a/core/java/android/content/pm/BaseParceledListSlice.java
+++ b/core/java/android/content/pm/BaseParceledListSlice.java
@@ -47,7 +47,7 @@
      * TODO get this number from somewhere else. For now set it to a quarter of
      * the 1MB limit.
      */
-    private static final int MAX_IPC_SIZE = IBinder.MAX_IPC_SIZE;
+    private static final int MAX_IPC_SIZE = IBinder.getSuggestedMaxIpcSizeBytes();
 
     private final List<T> mList;
 
diff --git a/core/java/android/content/pm/InstantAppRequest.java b/core/java/android/content/pm/InstantAppRequest.java
index 361d4e4..f692db1 100644
--- a/core/java/android/content/pm/InstantAppRequest.java
+++ b/core/java/android/content/pm/InstantAppRequest.java
@@ -16,9 +16,10 @@
 
 package android.content.pm;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Intent;
 import android.os.Bundle;
-import android.text.TextUtils;
 
 /**
  * Information needed to make an instant application resolution request.
@@ -34,32 +35,40 @@
     public final String resolvedType;
     /** The name of the package requesting the instant application */
     public final String callingPackage;
+    /** Whether or not the requesting package was an instant app */
+    public final boolean isRequesterInstantApp;
     /** ID of the user requesting the instant application */
     public final int userId;
     /**
      * Optional extra bundle provided by the source application to the installer for additional
-     * verification. */
+     * verification.
+     */
     public final Bundle verificationBundle;
     /** Whether resolution occurs because an application is starting */
     public final boolean resolveForStart;
-    /** The instant app digest for this request */
-    public final InstantAppResolveInfo.InstantAppDigest digest;
+    /**
+     * The hash prefix of an instant app's domain or null if no host is defined.
+     * Secure version that should be carried through for external use.
+     */
+    @Nullable
+    public final int[] hostDigestPrefixSecure;
+    /** A unique identifier */
+    @NonNull
+    public final String token;
 
     public InstantAppRequest(AuxiliaryResolveInfo responseObj, Intent origIntent,
-            String resolvedType, String callingPackage, int userId, Bundle verificationBundle,
-            boolean resolveForStart) {
+            String resolvedType, String callingPackage, boolean isRequesterInstantApp,
+            int userId, Bundle verificationBundle, boolean resolveForStart,
+            @Nullable int[] hostDigestPrefixSecure, @NonNull String token) {
         this.responseObj = responseObj;
         this.origIntent = origIntent;
         this.resolvedType = resolvedType;
         this.callingPackage = callingPackage;
+        this.isRequesterInstantApp = isRequesterInstantApp;
         this.userId = userId;
         this.verificationBundle = verificationBundle;
         this.resolveForStart = resolveForStart;
-        if (origIntent.getData() != null && !TextUtils.isEmpty(origIntent.getData().getHost())) {
-            digest = new InstantAppResolveInfo.InstantAppDigest(
-                    origIntent.getData().getHost(), 5 /*maxDigests*/);
-        } else {
-            digest = InstantAppResolveInfo.InstantAppDigest.UNDEFINED;
-        }
+        this.hostDigestPrefixSecure = hostDigestPrefixSecure;
+        this.token = token;
     }
 }
diff --git a/core/java/android/content/pm/InstantAppRequestInfo.aidl b/core/java/android/content/pm/InstantAppRequestInfo.aidl
new file mode 100644
index 0000000..0f94220
--- /dev/null
+++ b/core/java/android/content/pm/InstantAppRequestInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 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.content.pm;
+
+parcelable InstantAppRequestInfo;
diff --git a/core/java/android/content/pm/InstantAppRequestInfo.java b/core/java/android/content/pm/InstantAppRequestInfo.java
new file mode 100644
index 0000000..83d5536
--- /dev/null
+++ b/core/java/android/content/pm/InstantAppRequestInfo.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2019 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.content.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.Intent;
+import android.os.Parcelable;
+import android.os.UserHandle;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Information exposed to {@link android.app.InstantAppResolverService} to complete
+ * an instant application resolution request.
+ * @hide
+ */
+@SystemApi
+@DataClass(genParcelable = true, genConstructor = true, genAidl = true)
+public final class InstantAppRequestInfo implements Parcelable {
+
+    /**
+     * The sanitized {@link Intent} used for resolution. A sanitized Intent is an intent with
+     * potential PII removed from the original intent. Fields removed include extras and the
+     * host + path of the data, if defined.
+     */
+    @NonNull
+    public final Intent intent;
+
+    /** The hash prefix of the instant app's domain or null if no host is defined. */
+    @Nullable
+    public final int[] hostDigestPrefix;
+
+    /** The user requesting the instant application */
+    @NonNull
+    public final UserHandle userHandle;
+
+    /** Whether or not the requesting package was an instant app itself */
+    public final boolean isRequesterInstantApp;
+
+    /** A unique identifier */
+    @NonNull
+    public final String token;
+
+
+
+    // Code below generated by codegen v1.0.13.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/InstantAppRequestInfo.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Creates a new InstantAppRequestInfo.
+     *
+     * @param intent
+     *   The sanitized {@link Intent} used for resolution. A sanitized Intent is an intent with
+     *   potential PII removed from the original intent. Fields removed include extras and the
+     *   host + path of the data, if defined.
+     * @param hostDigestPrefix
+     *   The hash prefix of the instant app's domain or null if no host is defined.
+     * @param userHandle
+     *   The user requesting the instant application
+     * @param isRequesterInstantApp
+     *   Whether or not the requesting package was an instant app itself
+     * @param token
+     *   A unique identifier
+     */
+    @DataClass.Generated.Member
+    public InstantAppRequestInfo(
+            @NonNull Intent intent,
+            @Nullable int[] hostDigestPrefix,
+            @NonNull UserHandle userHandle,
+            boolean isRequesterInstantApp,
+            @NonNull String token) {
+        this.intent = intent;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, intent);
+        this.hostDigestPrefix = hostDigestPrefix;
+        this.userHandle = userHandle;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, userHandle);
+        this.isRequesterInstantApp = isRequesterInstantApp;
+        this.token = token;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, token);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        byte flg = 0;
+        if (isRequesterInstantApp) flg |= 0x8;
+        if (hostDigestPrefix != null) flg |= 0x2;
+        dest.writeByte(flg);
+        dest.writeTypedObject(intent, flags);
+        if (hostDigestPrefix != null) dest.writeIntArray(hostDigestPrefix);
+        dest.writeTypedObject(userHandle, flags);
+        dest.writeString(token);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ InstantAppRequestInfo(@NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        boolean _isRequesterInstantApp = (flg & 0x8) != 0;
+        Intent _intent = (Intent) in.readTypedObject(Intent.CREATOR);
+        int[] _hostDigestPrefix = (flg & 0x2) == 0 ? null : in.createIntArray();
+        UserHandle _userHandle = (UserHandle) in.readTypedObject(UserHandle.CREATOR);
+        String _token = in.readString();
+
+        this.intent = _intent;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, intent);
+        this.hostDigestPrefix = _hostDigestPrefix;
+        this.userHandle = _userHandle;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, userHandle);
+        this.isRequesterInstantApp = _isRequesterInstantApp;
+        this.token = _token;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, token);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<InstantAppRequestInfo> CREATOR
+            = new Parcelable.Creator<InstantAppRequestInfo>() {
+        @Override
+        public InstantAppRequestInfo[] newArray(int size) {
+            return new InstantAppRequestInfo[size];
+        }
+
+        @Override
+        public InstantAppRequestInfo createFromParcel(@NonNull android.os.Parcel in) {
+            return new InstantAppRequestInfo(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1574373347443L,
+            codegenVersion = "1.0.13",
+            sourceFile = "frameworks/base/core/java/android/content/pm/InstantAppRequestInfo.java",
+            inputSignatures = "public final @android.annotation.NonNull android.content.Intent intent\npublic final @android.annotation.Nullable int[] hostDigestPrefix\npublic final @android.annotation.NonNull android.os.UserHandle userHandle\npublic final  boolean isRequesterInstantApp\npublic final @android.annotation.NonNull java.lang.String token\nclass InstantAppRequestInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genConstructor=true, genAidl=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/content/pm/parsing/AndroidPackage.java b/core/java/android/content/pm/parsing/AndroidPackage.java
index 515185e..35df474 100644
--- a/core/java/android/content/pm/parsing/AndroidPackage.java
+++ b/core/java/android/content/pm/parsing/AndroidPackage.java
@@ -229,6 +229,11 @@
 
     String getOverlayTargetName();
 
+    /**
+     * Map of overlayable name to actor name.
+     */
+    Map<String, String> getOverlayables();
+
     // TODO(b/135203078): Does this and getAppInfoPackageName have to be separate methods?
     //  The refactor makes them the same value with no known consequences, so should be redundant.
     String getPackageName();
diff --git a/core/java/android/content/pm/parsing/ApkParseUtils.java b/core/java/android/content/pm/parsing/ApkParseUtils.java
index 0deb2ab..7732316 100644
--- a/core/java/android/content/pm/parsing/ApkParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkParseUtils.java
@@ -52,6 +52,7 @@
 import android.content.pm.split.DefaultSplitAssetLoader;
 import android.content.pm.split.SplitAssetDependencyLoader;
 import android.content.pm.split.SplitAssetLoader;
+import android.content.res.ApkAssets;
 import android.content.res.AssetManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -92,6 +93,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /** @hide */
@@ -287,8 +289,23 @@
                                 + result.getErrorMessage());
             }
 
-            return result.getResultAndNull()
-                    .setVolumeUuid(volumeUuid)
+            ParsingPackage pkg = result.getResultAndNull();
+            ApkAssets apkAssets = assets.getApkAssets()[0];
+            if (apkAssets.definesOverlayable()) {
+                SparseArray<String> packageNames = assets.getAssignedPackageIdentifiers();
+                int size = packageNames.size();
+                for (int index = 0; index < size; index++) {
+                    String packageName = packageNames.get(index);
+                    Map<String, String> overlayableToActor = assets.getOverlayableMap(packageName);
+                    if (overlayableToActor != null && !overlayableToActor.isEmpty()) {
+                        for (String overlayable : overlayableToActor.keySet()) {
+                            pkg.addOverlayable(overlayable, overlayableToActor.get(overlayable));
+                        }
+                    }
+                }
+            }
+
+            return pkg.setVolumeUuid(volumeUuid)
                     .setApplicationVolumeUuid(volumeUuid)
                     .setSigningDetails(SigningDetails.UNKNOWN);
         } catch (PackageParserException e) {
diff --git a/core/java/android/content/pm/parsing/PackageImpl.java b/core/java/android/content/pm/parsing/PackageImpl.java
index 377279e..0e736d5 100644
--- a/core/java/android/content/pm/parsing/PackageImpl.java
+++ b/core/java/android/content/pm/parsing/PackageImpl.java
@@ -18,6 +18,8 @@
 
 import static android.os.Build.VERSION_CODES.DONUT;
 
+import static java.util.Collections.emptyMap;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Intent;
@@ -55,11 +57,13 @@
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
 import com.android.server.SystemConfig;
 
 import java.security.PublicKey;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -126,6 +130,7 @@
     private String overlayCategory;
     private int overlayPriority;
     private boolean overlayIsStatic;
+    private Map<String, String> overlayables = emptyMap();
 
     private String staticSharedLibName;
     private long staticSharedLibVersion;
@@ -475,7 +480,7 @@
 
     @Override
     public Map<String, ArraySet<PublicKey>> getKeySetMapping() {
-        return keySetMapping == null ? Collections.emptyMap() : keySetMapping;
+        return keySetMapping == null ? emptyMap() : keySetMapping;
     }
 
     @Override
@@ -773,6 +778,13 @@
     }
 
     @Override
+    public ParsingPackage addOverlayable(String overlayableName, String actorName) {
+        this.overlayables = CollectionUtils.add(this.overlayables,
+                TextUtils.safeIntern(overlayableName), TextUtils.safeIntern(actorName));
+        return this;
+    }
+
+    @Override
     public PackageImpl addAdoptPermission(String adoptPermission) {
         this.adoptPermissions = ArrayUtils.add(this.adoptPermissions, adoptPermission);
         return this;
@@ -2125,6 +2137,11 @@
     }
 
     @Override
+    public Map<String, String> getOverlayables() {
+        return overlayables;
+    }
+
+    @Override
     public boolean isOverlayIsStatic() {
         return overlayIsStatic;
     }
@@ -2291,7 +2308,7 @@
         appInfo.metaData = appMetaData;
         appInfo.minAspectRatio = minAspectRatio;
         appInfo.minSdkVersion = minSdkVersion;
-        appInfo.name = name;
+        appInfo.name = className;
         if (appInfo.name != null) {
             appInfo.name = appInfo.name.trim();
         }
@@ -2957,6 +2974,7 @@
         dest.writeString(this.overlayCategory);
         dest.writeInt(this.overlayPriority);
         dest.writeBoolean(this.overlayIsStatic);
+        dest.writeMap(this.overlayables);
         dest.writeString(this.staticSharedLibName);
         dest.writeLong(this.staticSharedLibVersion);
         dest.writeStringList(this.libraryNames);
@@ -3100,6 +3118,8 @@
         this.overlayCategory = in.readString();
         this.overlayPriority = in.readInt();
         this.overlayIsStatic = in.readBoolean();
+        this.overlayables = new HashMap<>();
+        in.readMap(overlayables, boot);
         this.staticSharedLibName = TextUtils.safeIntern(in.readString());
         this.staticSharedLibVersion = in.readLong();
         this.libraryNames = in.createStringArrayList();
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index 43c1f6e..aff1b2e 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -62,6 +62,8 @@
 
     ParsingPackage addOriginalPackage(String originalPackage);
 
+    ParsingPackage addOverlayable(String overlayableName, String actorName);
+
     ParsingPackage addPermission(ParsedPermission permission);
 
     ParsingPackage addPermissionGroup(ParsedPermissionGroup permissionGroup);
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 1f29d1a..c84c4a7 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -935,7 +935,7 @@
     /**
      * <p>List of the maximum number of regions that can be used for metering in
      * auto-exposure (AE), auto-white balance (AWB), and auto-focus (AF);
-     * this corresponds to the the maximum number of elements in
+     * this corresponds to the maximum number of elements in
      * {@link CaptureRequest#CONTROL_AE_REGIONS android.control.aeRegions}, {@link CaptureRequest#CONTROL_AWB_REGIONS android.control.awbRegions},
      * and {@link CaptureRequest#CONTROL_AF_REGIONS android.control.afRegions}.</p>
      * <p><b>Range of valid values:</b><br></p>
@@ -955,7 +955,7 @@
     /**
      * <p>The maximum number of metering regions that can be used by the auto-exposure (AE)
      * routine.</p>
-     * <p>This corresponds to the the maximum allowed number of elements in
+     * <p>This corresponds to the maximum allowed number of elements in
      * {@link CaptureRequest#CONTROL_AE_REGIONS android.control.aeRegions}.</p>
      * <p><b>Range of valid values:</b><br>
      * Value will be &gt;= 0. For FULL-capability devices, this
@@ -973,7 +973,7 @@
     /**
      * <p>The maximum number of metering regions that can be used by the auto-white balance (AWB)
      * routine.</p>
-     * <p>This corresponds to the the maximum allowed number of elements in
+     * <p>This corresponds to the maximum allowed number of elements in
      * {@link CaptureRequest#CONTROL_AWB_REGIONS android.control.awbRegions}.</p>
      * <p><b>Range of valid values:</b><br>
      * Value will be &gt;= 0.</p>
@@ -989,7 +989,7 @@
 
     /**
      * <p>The maximum number of metering regions that can be used by the auto-focus (AF) routine.</p>
-     * <p>This corresponds to the the maximum allowed number of elements in
+     * <p>This corresponds to the maximum allowed number of elements in
      * {@link CaptureRequest#CONTROL_AF_REGIONS android.control.afRegions}.</p>
      * <p><b>Range of valid values:</b><br>
      * Value will be &gt;= 0. For FULL-capability devices, this
@@ -1987,6 +1987,7 @@
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME MONOCHROME}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA SECURE_IMAGE_DATA}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA SYSTEM_CAMERA}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING OFFLINE_PROCESSING}</li>
      * </ul></p>
      * <p>This key is available on all devices.</p>
      *
@@ -2006,6 +2007,7 @@
      * @see #REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME
      * @see #REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA
      * @see #REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA
+     * @see #REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING
      */
     @PublicKey
     @NonNull
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 799c716..f2a7abd 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1004,6 +1004,51 @@
      */
     public static final int REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA = 14;
 
+    /**
+     * <p>The camera device supports the OFFLINE_PROCESSING use case.</p>
+     * <p>With OFFLINE_PROCESSING capability, the application can switch an ongoing
+     * capture session to offline mode by calling the
+     * CameraCaptureSession#switchToOffline method and specify streams to be kept in offline
+     * mode. The camera will then stop currently active repeating requests, prepare for
+     * some requests to go into offline mode, and return an offline session object. After
+     * the switchToOffline call returns, the original capture session is in closed state as
+     * if the CameraCaptureSession#close method has been called.
+     * In the offline mode, all inflight requests will continue to be processed in the
+     * background, and the application can immediately close the camera or create a new
+     * capture session without losing those requests' output images and capture results.</p>
+     * <p>While the camera device is processing offline requests, it
+     * might not be able to support all stream configurations it can support
+     * without offline requests. When that happens, the createCaptureSession
+     * method call will fail. The following stream configurations are guaranteed to work
+     * without hitting the resource busy exception:</p>
+     * <ul>
+     * <li>One ongoing offline session: target one output surface of YUV or
+     * JPEG format, any resolution.</li>
+     * <li>The active camera capture session:<ol>
+     * <li>One preview surface (SurfaceView or SurfaceTexture) up to 1920 width</li>
+     * <li>One YUV ImageReader surface up to 1920 width</li>
+     * <li>One Jpeg ImageReader, any resolution: the camera device is
+     *    allowed to slow down JPEG output speed by 50% if there is any ongoing offline
+     *    session.</li>
+     * <li>One ImageWriter surface of private format, any resolution if the device supports
+     *    PRIVATE_REPROCESSING capability</li>
+     * </ol>
+     * </li>
+     * <li>Alternatively, the active camera session above can be replaced by an legacy
+     * {@link android.hardware.Camera Camera} with the following parameter settings:<ol>
+     * <li>Preview size up to 1920 width</li>
+     * <li>Preview callback size up to 1920 width</li>
+     * <li>Video size up to 1920 width</li>
+     * <li>Picture size, any resolution: the camera device is
+     *     allowed to slow down JPEG output speed by 50% if there is any ongoing offline
+     *     session.</li>
+     * </ol>
+     * </li>
+     * </ul>
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     */
+    public static final int REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING = 15;
+
     //
     // Enumeration values for CameraCharacteristics#SCALER_CROPPING_TYPE
     //
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index bcbc337..41435c9 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -29,6 +29,7 @@
 import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
+import android.hardware.camera2.ICameraOfflineSession;
 import android.hardware.camera2.TotalCaptureResult;
 import android.hardware.camera2.params.InputConfiguration;
 import android.hardware.camera2.params.OutputConfiguration;
@@ -866,6 +867,38 @@
         }
     }
 
+    public void switchToOffline(ICameraDeviceCallbacks cbs, Surface[] offlineOutputs)
+            throws CameraAccessException {
+        if ((offlineOutputs == null) || (offlineOutputs.length == 0)) {
+            throw new IllegalArgumentException("Invalid offline outputs!");
+        }
+        if (cbs == null) {
+            throw new IllegalArgumentException("Invalid device callbacks!");
+        }
+
+        ICameraOfflineSession offlineSession = null;
+        synchronized(mInterfaceLock) {
+            int streamId = -1;
+            for (Surface surface : offlineOutputs) {
+                for (int i = 0; i < mConfiguredOutputs.size(); i++) {
+                    if (surface == mConfiguredOutputs.valueAt(i).getSurface()) {
+                        streamId = mConfiguredOutputs.keyAt(i);
+                        break;
+                    }
+                }
+                if (streamId == -1) {
+                    throw new IllegalArgumentException("Offline surface is not part of this" +
+                            " session");
+                }
+            }
+
+            offlineSession = mRemoteDevice.switchToOffline(cbs,
+                    offlineOutputs);
+            // TODO: Initialize CameraOfflineSession wrapper, clear 'mConfiguredOutputs',
+            // and update request tracking
+        }
+    }
+
     public void tearDown(Surface surface) throws CameraAccessException {
         if (surface == null) throw new IllegalArgumentException("Surface is null");
 
diff --git a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
index 3660f29..397417b 100644
--- a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
+++ b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
@@ -28,6 +28,8 @@
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.ICameraDeviceUser;
+import android.hardware.camera2.ICameraDeviceCallbacks;
+import android.hardware.camera2.ICameraOfflineSession;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.params.OutputConfiguration;
 import android.hardware.camera2.params.SessionConfiguration;
@@ -248,6 +250,17 @@
         }
     }
 
+    public ICameraOfflineSession switchToOffline(ICameraDeviceCallbacks cbs,
+            Surface[] offlineOutputs)
+            throws CameraAccessException {
+        try {
+            return mRemoteDevice.switchToOffline(cbs, offlineOutputs);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
     public void finalizeOutputConfigurations(int streamId, OutputConfiguration deferredConfig)
             throws CameraAccessException {
         try {
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index 5d1435a..6ab0c29 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -24,6 +24,7 @@
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
+import android.hardware.camera2.ICameraOfflineSession;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.impl.CaptureResultExtras;
 import android.hardware.camera2.impl.PhysicalCaptureResultInfo;
@@ -789,6 +790,12 @@
     }
 
     @Override
+    public ICameraOfflineSession switchToOffline(ICameraDeviceCallbacks cbs,
+            Surface[] offlineOutputs) {
+        throw new UnsupportedOperationException("Legacy device does not support switchToOffline");
+    }
+
+    @Override
     public IBinder asBinder() {
         // This is solely intended to be used for in-process binding.
         return null;
diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
index 6eaf54b..23f18a8 100644
--- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
+++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
@@ -1163,7 +1163,7 @@
             if (orderedPreviewSizes != null) {
                 for (Size size : orderedPreviewSizes) {
                     if ((mDisplaySize.getWidth() >= size.getWidth()) &&
-                            (mDisplaySize.getWidth() >= size.getHeight())) {
+                            (mDisplaySize.getHeight() >= size.getHeight())) {
                         return size;
                     }
                 }
diff --git a/core/java/android/net/InvalidPacketException.java b/core/java/android/net/InvalidPacketException.java
new file mode 100644
index 0000000..909998d
--- /dev/null
+++ b/core/java/android/net/InvalidPacketException.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Thrown when a packet is invalid.
+ * @hide
+ */
+@SystemApi
+public class InvalidPacketException extends Exception {
+    public final int error;
+
+    // Must match SocketKeepalive#ERROR_INVALID_IP_ADDRESS.
+    /** Invalid IP address. */
+    public static final int ERROR_INVALID_IP_ADDRESS = -21;
+
+    // Must match SocketKeepalive#ERROR_INVALID_PORT.
+    /** Invalid port number. */
+    public static final int ERROR_INVALID_PORT = -22;
+
+    // Must match SocketKeepalive#ERROR_INVALID_LENGTH.
+    /** Invalid packet length. */
+    public static final int ERROR_INVALID_LENGTH = -23;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "ERROR_" }, value = {
+        ERROR_INVALID_IP_ADDRESS,
+        ERROR_INVALID_PORT,
+        ERROR_INVALID_LENGTH
+    })
+    public @interface ErrorCode {}
+
+    /**
+     * This packet is invalid.
+     * See the error code for details.
+     */
+    public InvalidPacketException(@ErrorCode final int error) {
+        this.error = error;
+    }
+}
diff --git a/core/java/android/net/KeepalivePacketData.java b/core/java/android/net/KeepalivePacketData.java
index 9b8b732..2b8b7e6 100644
--- a/core/java/android/net/KeepalivePacketData.java
+++ b/core/java/android/net/KeepalivePacketData.java
@@ -16,13 +16,13 @@
 
 package android.net;
 
-import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
-import static android.net.SocketKeepalive.ERROR_INVALID_PORT;
+import static android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS;
+import static android.net.InvalidPacketException.ERROR_INVALID_PORT;
 
-import android.net.SocketKeepalive.InvalidPacketException;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.net.util.IpUtils;
 import android.os.Parcel;
-import android.os.Parcelable;
 import android.util.Log;
 
 import java.net.InetAddress;
@@ -33,13 +33,16 @@
  *
  * @hide
  */
-public class KeepalivePacketData implements Parcelable {
+@SystemApi
+public class KeepalivePacketData {
     private static final String TAG = "KeepalivePacketData";
 
     /** Source IP address */
+    @NonNull
     public final InetAddress srcAddress;
 
     /** Destination IP address */
+    @NonNull
     public final InetAddress dstAddress;
 
     /** Source port */
@@ -51,13 +54,14 @@
     /** Packet data. A raw byte string of packet data, not including the link-layer header. */
     private final byte[] mPacket;
 
-    protected static final int IPV4_HEADER_LENGTH = 20;
-    protected static final int UDP_HEADER_LENGTH = 8;
-
     // This should only be constructed via static factory methods, such as
-    // nattKeepalivePacket
-    protected KeepalivePacketData(InetAddress srcAddress, int srcPort,
-            InetAddress dstAddress, int dstPort, byte[] data) throws InvalidPacketException {
+    // nattKeepalivePacket.
+    /**
+     * A holding class for data necessary to build a keepalive packet.
+     */
+    protected KeepalivePacketData(@NonNull InetAddress srcAddress, int srcPort,
+            @NonNull InetAddress dstAddress, int dstPort,
+                    @NonNull byte[] data) throws InvalidPacketException {
         this.srcAddress = srcAddress;
         this.dstAddress = dstAddress;
         this.srcPort = srcPort;
@@ -78,16 +82,12 @@
         }
     }
 
+    @NonNull
     public byte[] getPacket() {
         return mPacket.clone();
     }
 
-    /* Parcelable Implementation */
-    public int describeContents() {
-        return 0;
-    }
-
-    /** Write to parcel */
+    /** @hide */
     public void writeToParcel(Parcel out, int flags) {
         out.writeString(srcAddress.getHostAddress());
         out.writeString(dstAddress.getHostAddress());
@@ -96,6 +96,7 @@
         out.writeByteArray(mPacket);
     }
 
+    /** @hide */
     protected KeepalivePacketData(Parcel in) {
         srcAddress = NetworkUtils.numericToInetAddress(in.readString());
         dstAddress = NetworkUtils.numericToInetAddress(in.readString());
@@ -103,17 +104,4 @@
         dstPort = in.readInt();
         mPacket = in.createByteArray();
     }
-
-    /** Parcelable Creator */
-    public static final @android.annotation.NonNull Parcelable.Creator<KeepalivePacketData> CREATOR =
-            new Parcelable.Creator<KeepalivePacketData>() {
-                public KeepalivePacketData createFromParcel(Parcel in) {
-                    return new KeepalivePacketData(in);
-                }
-
-                public KeepalivePacketData[] newArray(int size) {
-                    return new KeepalivePacketData[size];
-                }
-            };
-
 }
diff --git a/core/java/android/net/NattKeepalivePacketData.java b/core/java/android/net/NattKeepalivePacketData.java
index a77c244..3fb52f1 100644
--- a/core/java/android/net/NattKeepalivePacketData.java
+++ b/core/java/android/net/NattKeepalivePacketData.java
@@ -19,7 +19,6 @@
 import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
 import static android.net.SocketKeepalive.ERROR_INVALID_PORT;
 
-import android.net.SocketKeepalive.InvalidPacketException;
 import android.net.util.IpUtils;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -32,6 +31,9 @@
 
 /** @hide */
 public final class NattKeepalivePacketData extends KeepalivePacketData implements Parcelable {
+    private static final int IPV4_HEADER_LENGTH = 20;
+    private static final int UDP_HEADER_LENGTH = 8;
+
     // This should only be constructed via static factory methods, such as
     // nattKeepalivePacket
     private NattKeepalivePacketData(InetAddress srcAddress, int srcPort,
diff --git a/core/java/android/net/SocketKeepalive.java b/core/java/android/net/SocketKeepalive.java
index ec73866..fb224fb 100644
--- a/core/java/android/net/SocketKeepalive.java
+++ b/core/java/android/net/SocketKeepalive.java
@@ -147,17 +147,6 @@
         }
     }
 
-    /**
-     * This packet is invalid.
-     * See the error code for details.
-     * @hide
-     */
-    public static class InvalidPacketException extends ErrorCodeException {
-        public InvalidPacketException(final int error) {
-            super(error);
-        }
-    }
-
     @NonNull final IConnectivityManager mService;
     @NonNull final Network mNetwork;
     @NonNull final ParcelFileDescriptor mPfd;
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index 12bce8a..ed980f3 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -182,6 +182,14 @@
     public static final int MAX_IPC_SIZE = 64 * 1024;
 
     /**
+     * Limit that should be placed on IPC sizes, in bytes, to keep them safely under the transaction
+     * buffer limit.
+     */
+    static int getSuggestedMaxIpcSizeBytes() {
+        return MAX_IPC_SIZE;
+    }
+
+    /**
      * Get the canonical name of the interface supported by this binder.
      */
     public @Nullable String getInterfaceDescriptor() throws RemoteException;
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 9eb6445..339397b 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -1815,8 +1815,12 @@
         p.writeToParcel(this, parcelableFlags);
     }
 
-    /** @hide */
-    @UnsupportedAppUsage
+    /**
+     * Flatten the name of the class of the Parcelable into this Parcel.
+     *
+     * @param p The Parcelable object to be written.
+     * @see #readParcelableCreator
+     */
     public final void writeParcelableCreator(@NonNull Parcelable p) {
         String name = p.getClass().getName();
         writeString(name);
@@ -3011,8 +3015,19 @@
         return (T) creator.createFromParcel(this);
     }
 
-    /** @hide */
-    @UnsupportedAppUsage
+    /**
+     * Read and return a Parcelable.Creator from the parcel. The given class loader will be used to
+     * load the {@link Parcelable.Creator}. If it is null, the default class loader will be used.
+     *
+     * @param loader A ClassLoader from which to instantiate the {@link Parcelable.Creator}
+     * object, or null for the default class loader.
+     * @return the previously written {@link Parcelable.Creator}, or null if a null Creator was
+     * written.
+     * @throws BadParcelableException Throws BadParcelableException if there was an error trying to
+     * read the {@link Parcelable.Creator}.
+     *
+     * @see #writeParcelableCreator
+     */
     @Nullable
     public final Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader loader) {
         String name = readString();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ee9aa09..0318129 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8416,6 +8416,12 @@
         public static final String PEOPLE_STRIP = "people_strip";
 
         /**
+         * Controls if window magnification is enabled.
+         * @hide
+         */
+        public static final String WINDOW_MAGNIFICATION = "window_magnification";
+
+        /**
          * Keys we no longer back up under the current schema, but want to continue to
          * process when restoring historical backup datasets.
          *
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 85f13d5..c04ac59 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1895,7 +1895,8 @@
                     && ((mSmartActions == null ? 0 : mSmartActions.size())
                         == (other.mSmartActions == null ? 0 : other.mSmartActions.size()))
                     && Objects.equals(mSmartReplies, other.mSmartReplies)
-                    && Objects.equals(mCanBubble, other.mCanBubble);
+                    && Objects.equals(mCanBubble, other.mCanBubble)
+                    && Objects.equals(mVisuallyInterruptive, other.mVisuallyInterruptive);
         }
     }
 
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 28eb79a..71ac578 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -16,13 +16,13 @@
 
 package android.view;
 
-import static android.view.DisplayEventReceiver.CONFIG_CHANGED_EVENT_SUPPRESS;
 import static android.view.DisplayEventReceiver.VSYNC_SOURCE_APP;
 import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER;
 
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.FrameInfo;
+import android.graphics.Insets;
 import android.hardware.display.DisplayManagerGlobal;
 import android.os.Build;
 import android.os.Handler;
@@ -219,9 +219,10 @@
     /**
      * Callback type: Animation callback to handle inset updates. This is separate from
      * {@link #CALLBACK_ANIMATION} as we need to "gather" all inset animation updates via
-     * {@link WindowInsetsAnimationController#changeInsets} for multiple ongoing animations but then
-     * update the whole view system with a single callback to {@link View#dispatchWindowInsetsAnimationProgress}
-     * that contains all the combined updated insets.
+     * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)} for multiple
+     * ongoing animations but then update the whole view system with a single callback to
+     * {@link View#dispatchWindowInsetsAnimationProgress} that contains all the combined updated
+     * insets.
      * <p>
      * Both input and animation may change insets, so we need to run this after these callbacks, but
      * before traversals.
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index 411508f..615dab0 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -66,6 +66,7 @@
     private static final String BOTTOM_MARKER = "@bottom";
     private static final String DP_MARKER = "@dp";
     private static final String RIGHT_MARKER = "@right";
+    private static final String LEFT_MARKER = "@left";
 
     /**
      * Category for overlays that allow emulating a display cutout on devices that don't have
@@ -647,6 +648,9 @@
         if (spec.endsWith(RIGHT_MARKER)) {
             offsetX = displayWidth;
             spec = spec.substring(0, spec.length() - RIGHT_MARKER.length()).trim();
+        } else if (spec.endsWith(LEFT_MARKER)) {
+            offsetX = 0;
+            spec = spec.substring(0, spec.length() - LEFT_MARKER.length()).trim();
         } else {
             offsetX = displayWidth / 2f;
         }
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 3d139cd..7ea4f30 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -21,7 +21,6 @@
 import static android.view.InsetsState.ISIDE_LEFT;
 import static android.view.InsetsState.ISIDE_RIGHT;
 import static android.view.InsetsState.ISIDE_TOP;
-import static android.view.InsetsState.toPublicType;
 
 import android.annotation.Nullable;
 import android.graphics.Insets;
@@ -34,7 +33,8 @@
 import android.view.InsetsState.InternalInsetsSide;
 import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
 import android.view.WindowInsets.Type.InsetsType;
-import android.view.WindowInsetsAnimationListener.InsetsAnimation;
+import android.view.WindowInsetsAnimationCallback.AnimationBounds;
+import android.view.WindowInsetsAnimationCallback.InsetsAnimation;
 import android.view.WindowManager.LayoutParams;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -66,20 +66,21 @@
     private final @InsetsType int mTypes;
     private final Supplier<SyncRtSurfaceTransactionApplier> mTransactionApplierSupplier;
     private final InsetsController mController;
-    private final WindowInsetsAnimationListener.InsetsAnimation mAnimation;
+    private final WindowInsetsAnimationCallback.InsetsAnimation mAnimation;
     private final Rect mFrame;
     private Insets mCurrentInsets;
     private Insets mPendingInsets;
+    private float mPendingFraction;
     private boolean mFinished;
     private boolean mCancelled;
-    private int mFinishedShownTypes;
+    private boolean mShownOnFinish;
 
     @VisibleForTesting
     public InsetsAnimationControlImpl(SparseArray<InsetsSourceConsumer> consumers, Rect frame,
             InsetsState state, WindowInsetsAnimationControlListener listener,
             @InsetsType int types,
             Supplier<SyncRtSurfaceTransactionApplier> transactionApplierSupplier,
-            InsetsController controller) {
+            InsetsController controller, long durationMs) {
         mConsumers = consumers;
         mListener = listener;
         mTypes = types;
@@ -97,9 +98,10 @@
         // TODO: Check for controllability first and wait for IME if needed.
         listener.onReady(this, types);
 
-        mAnimation = new WindowInsetsAnimationListener.InsetsAnimation(mTypes, mHiddenInsets,
-                mShownInsets);
-        mController.dispatchAnimationStarted(mAnimation);
+        mAnimation = new WindowInsetsAnimationCallback.InsetsAnimation(mTypes,
+                InsetsController.INTERPOLATOR, durationMs);
+        mController.dispatchAnimationStarted(mAnimation,
+                new AnimationBounds(mHiddenInsets, mShownInsets));
     }
 
     @Override
@@ -123,7 +125,7 @@
     }
 
     @Override
-    public void changeInsets(Insets insets) {
+    public void setInsetsAndAlpha(Insets insets, float alpha, float fraction) {
         if (mFinished) {
             throw new IllegalStateException(
                     "Can't change insets on an animation that is finished.");
@@ -132,6 +134,7 @@
             throw new IllegalStateException(
                     "Can't change insets on an animation that is cancelled.");
         }
+        mPendingFraction = sanitize(fraction);
         mPendingInsets = sanitize(insets);
         mController.scheduleApplyChangeInsets();
     }
@@ -155,30 +158,35 @@
         SyncRtSurfaceTransactionApplier applier = mTransactionApplierSupplier.get();
         applier.scheduleApply(params.toArray(new SurfaceParams[params.size()]));
         mCurrentInsets = mPendingInsets;
+        mAnimation.setFraction(mPendingFraction);
         if (mFinished) {
-            mController.notifyFinished(this, mFinishedShownTypes);
+            mController.notifyFinished(this, mShownOnFinish);
         }
         return mFinished;
     }
 
     @Override
-    public void finish(int shownTypes) {
+    public void finish(boolean shown) {
         if (mCancelled) {
             return;
         }
         InsetsState state = new InsetsState(mController.getState());
         for (int i = mConsumers.size() - 1; i >= 0; i--) {
             InsetsSourceConsumer consumer = mConsumers.valueAt(i);
-            boolean visible = (shownTypes & toPublicType(consumer.getType())) != 0;
-            state.getSource(consumer.getType()).setVisible(visible);
+            state.getSource(consumer.getType()).setVisible(shown);
         }
         Insets insets = getInsetsFromState(state, mFrame, null /* typeSideMap */);
-        changeInsets(insets);
+        setInsetsAndAlpha(insets, 1f /* alpha */, shown ? 1f : 0f /* fraction */);
         mFinished = true;
-        mFinishedShownTypes = shownTypes;
+        mShownOnFinish = shown;
     }
 
+    @Override
     @VisibleForTesting
+    public float getCurrentFraction() {
+        return mAnimation.getFraction();
+    }
+
     public void onCancelled() {
         if (mFinished) {
             return;
@@ -191,6 +199,10 @@
         return mAnimation;
     }
 
+    WindowInsetsAnimationControlListener getListener() {
+        return mListener;
+    }
+
     private Insets calculateInsets(InsetsState state, Rect frame,
             SparseArray<InsetsSourceConsumer> consumers, boolean shown,
             @Nullable @InternalInsetsSide SparseIntArray typeSideMap) {
@@ -210,9 +222,16 @@
     }
 
     private Insets sanitize(Insets insets) {
+        if (insets == null) {
+            insets = getCurrentInsets();
+        }
         return Insets.max(Insets.min(insets, mShownInsets), mHiddenInsets);
     }
 
+    private static float sanitize(float alpha) {
+        return alpha >= 1 ? 1 : (alpha <= 0 ? 0 : alpha);
+    }
+
     private void updateLeashesForSide(@InternalInsetsSide int side, int offset, int inset,
             ArrayList<SurfaceParams> surfaceParams, InsetsState state) {
         ArraySet<InsetsSourceConsumer> items = mSideSourceMap.get(side);
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 43fec82..8870311 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -39,6 +39,8 @@
 import android.view.SurfaceControl.Transaction;
 import android.view.WindowInsets.Type;
 import android.view.WindowInsets.Type.InsetsType;
+import android.view.WindowInsetsAnimationCallback.AnimationBounds;
+import android.view.WindowInsetsAnimationCallback.InsetsAnimation;
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
 
@@ -55,11 +57,12 @@
 
     private static final int ANIMATION_DURATION_SHOW_MS = 275;
     private static final int ANIMATION_DURATION_HIDE_MS = 340;
-    private static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
     private static final int DIRECTION_NONE = 0;
     private static final int DIRECTION_SHOW = 1;
     private static final int DIRECTION_HIDE = 2;
 
+    static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+
     @IntDef ({DIRECTION_NONE, DIRECTION_SHOW, DIRECTION_HIDE})
     private @interface AnimationDirection{}
 
@@ -85,8 +88,75 @@
             return object.getCurrentInsets();
         }
         @Override
-        public void set(WindowInsetsAnimationController object, Insets value) {
-            object.changeInsets(value);
+        public void set(WindowInsetsAnimationController controller, Insets value) {
+            controller.setInsetsAndAlpha(
+                    value, 1f /* alpha */, (((DefaultAnimationControlListener)
+                            ((InsetsAnimationControlImpl) controller).getListener())
+                                    .getRawProgress()));
+        }
+    }
+
+    private class DefaultAnimationControlListener implements WindowInsetsAnimationControlListener {
+
+        private WindowInsetsAnimationController mController;
+        private ObjectAnimator mAnimator;
+        private boolean mShow;
+
+        DefaultAnimationControlListener(boolean show) {
+            mShow = show;
+        }
+
+        @Override
+        public void onReady(WindowInsetsAnimationController controller, int types) {
+            mController = controller;
+            if (mShow) {
+                showDirectly(types);
+            } else {
+                hideDirectly(types);
+            }
+            mAnimationDirection = mShow ? DIRECTION_SHOW : DIRECTION_HIDE;
+            mAnimator = ObjectAnimator.ofObject(
+                    controller,
+                    new InsetsProperty(),
+                    sEvaluator,
+                    mShow ? controller.getHiddenStateInsets() : controller.getShownStateInsets(),
+                    mShow ? controller.getShownStateInsets() : controller.getHiddenStateInsets()
+            );
+            mAnimator.setDuration(getDurationMs());
+            mAnimator.setInterpolator(INTERPOLATOR);
+            mAnimator.addListener(new AnimatorListenerAdapter() {
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    onAnimationFinish();
+                }
+            });
+            mAnimator.start();
+        }
+
+        @Override
+        public void onCancelled() {
+            // Animator can be null when it is cancelled before onReady() completes.
+            if (mAnimator != null) {
+                mAnimator.cancel();
+            }
+        }
+
+        private void onAnimationFinish() {
+            mAnimationDirection = DIRECTION_NONE;
+            mController.finish(mShow);
+        }
+
+        private float getRawProgress() {
+            float fraction = (float) mAnimator.getCurrentPlayTime() / mAnimator.getDuration();
+            return mShow ? fraction : 1 - fraction;
+        }
+
+        private long getDurationMs() {
+            if (mAnimator != null) {
+                return mAnimator.getDuration();
+            }
+            return mShow ? ANIMATION_DURATION_SHOW_MS : ANIMATION_DURATION_HIDE_MS;
         }
     }
 
@@ -278,24 +348,25 @@
     }
 
     @Override
-    public void controlWindowInsetsAnimation(@InsetsType int types,
+    public void controlWindowInsetsAnimation(@InsetsType int types, long durationMs,
             WindowInsetsAnimationControlListener listener) {
-        controlWindowInsetsAnimation(types, listener, false /* fromIme */);
+        controlWindowInsetsAnimation(types, listener, false /* fromIme */, durationMs);
     }
 
     private void controlWindowInsetsAnimation(@InsetsType int types,
-            WindowInsetsAnimationControlListener listener, boolean fromIme) {
+            WindowInsetsAnimationControlListener listener, boolean fromIme, long durationMs) {
         // If the frame of our window doesn't span the entire display, the control API makes very
         // little sense, as we don't deal with negative insets. So just cancel immediately.
         if (!mState.getDisplayFrame().equals(mFrame)) {
             listener.onCancelled();
             return;
         }
-        controlAnimationUnchecked(types, listener, mFrame, fromIme);
+        controlAnimationUnchecked(types, listener, mFrame, fromIme, durationMs);
     }
 
     private void controlAnimationUnchecked(@InsetsType int types,
-            WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme) {
+            WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme,
+            long durationMs) {
         if (types == 0) {
             // nothing to animate.
             return;
@@ -326,7 +397,7 @@
 
         final InsetsAnimationControlImpl controller = new InsetsAnimationControlImpl(consumers,
                 frame, mState, listener, typesReady,
-                () -> new SyncRtSurfaceTransactionApplier(mViewRoot.mView), this);
+                () -> new SyncRtSurfaceTransactionApplier(mViewRoot.mView), this, durationMs);
         mAnimationControls.add(controller);
     }
 
@@ -397,10 +468,13 @@
     }
 
     @VisibleForTesting
-    public void notifyFinished(InsetsAnimationControlImpl controller, int shownTypes) {
+    public void notifyFinished(InsetsAnimationControlImpl controller, boolean shown) {
         mAnimationControls.remove(controller);
-        hideDirectly(controller.getTypes() & ~shownTypes);
-        showDirectly(controller.getTypes() & shownTypes);
+        if (shown) {
+            showDirectly(controller.getTypes());
+        } else {
+            hideDirectly(controller.getTypes());
+        }
     }
 
     void notifyControlRevoked(InsetsSourceConsumer consumer) {
@@ -510,58 +584,11 @@
             return;
         }
 
-        WindowInsetsAnimationControlListener listener = new WindowInsetsAnimationControlListener() {
-
-            private WindowInsetsAnimationController mController;
-            private ObjectAnimator mAnimator;
-
-            @Override
-            public void onReady(WindowInsetsAnimationController controller, int types) {
-                mController = controller;
-                if (show) {
-                    showDirectly(types);
-                } else {
-                    hideDirectly(types);
-                }
-                mAnimationDirection = show ? DIRECTION_SHOW : DIRECTION_HIDE;
-                mAnimator = ObjectAnimator.ofObject(
-                        controller,
-                        new InsetsProperty(),
-                        sEvaluator,
-                        show ? controller.getHiddenStateInsets() : controller.getShownStateInsets(),
-                        show ? controller.getShownStateInsets() : controller.getHiddenStateInsets()
-                );
-                mAnimator.setDuration(show
-                        ? ANIMATION_DURATION_SHOW_MS
-                        : ANIMATION_DURATION_HIDE_MS);
-                mAnimator.setInterpolator(INTERPOLATOR);
-                mAnimator.addListener(new AnimatorListenerAdapter() {
-
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        onAnimationFinish();
-                    }
-                });
-                mAnimator.start();
-            }
-
-            @Override
-            public void onCancelled() {
-                // Animator can be null when it is cancelled before onReady() completes.
-                if (mAnimator != null) {
-                    mAnimator.cancel();
-                }
-            }
-
-            private void onAnimationFinish() {
-                mAnimationDirection = DIRECTION_NONE;
-                mController.finish(show ? types : 0);
-            }
-        };
-
+        final DefaultAnimationControlListener listener = new DefaultAnimationControlListener(show);
         // Show/hide animations always need to be relative to the display frame, in order that shown
         // and hidden state insets are correct.
-        controlAnimationUnchecked(types, listener, mState.getDisplayFrame(), fromIme);
+        controlAnimationUnchecked(
+                types, listener, mState.getDisplayFrame(), fromIme, listener.getDurationMs());
     }
 
     private void hideDirectly(@InsetsType int types) {
@@ -592,12 +619,12 @@
     }
 
     @VisibleForTesting
-    public void dispatchAnimationStarted(WindowInsetsAnimationListener.InsetsAnimation animation) {
-        mViewRoot.mView.dispatchWindowInsetsAnimationStarted(animation);
+    public void dispatchAnimationStarted(InsetsAnimation animation, AnimationBounds bounds) {
+        mViewRoot.mView.dispatchWindowInsetsAnimationStarted(animation, bounds);
     }
 
     @VisibleForTesting
-    public void dispatchAnimationFinished(WindowInsetsAnimationListener.InsetsAnimation animation) {
+    public void dispatchAnimationFinished(InsetsAnimation animation) {
         mViewRoot.mView.dispatchWindowInsetsAnimationFinished(animation);
     }
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9d4f3878..2d0b954 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -109,7 +109,8 @@
 import android.view.AccessibilityIterators.TextSegmentIterator;
 import android.view.AccessibilityIterators.WordTextSegmentIterator;
 import android.view.ContextMenu.ContextMenuInfo;
-import android.view.WindowInsetsAnimationListener.InsetsAnimation;
+import android.view.WindowInsetsAnimationCallback.AnimationBounds;
+import android.view.WindowInsetsAnimationCallback.InsetsAnimation;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityEventSource;
 import android.view.accessibility.AccessibilityManager;
@@ -4626,7 +4627,7 @@
 
         private ArrayList<OnUnhandledKeyEventListener> mUnhandledKeyListeners;
 
-        private WindowInsetsAnimationListener mWindowInsetsAnimationListener;
+        private WindowInsetsAnimationCallback mWindowInsetsAnimationCallback;
 
         /**
          * This lives here since it's only valid for interactive views.
@@ -11091,33 +11092,55 @@
     }
 
     /**
-     * Sets a {@link WindowInsetsAnimationListener} to be notified about animations of windows that
+     * Sets a {@link WindowInsetsAnimationCallback} to be notified about animations of windows that
      * cause insets.
      *
      * @param listener The listener to set.
-     * @hide pending unhide
      */
-    public void setWindowInsetsAnimationListener(WindowInsetsAnimationListener listener) {
-        getListenerInfo().mWindowInsetsAnimationListener = listener;
+    public void setWindowInsetsAnimationCallback(@Nullable WindowInsetsAnimationCallback listener) {
+        getListenerInfo().mWindowInsetsAnimationCallback = listener;
     }
 
-    void dispatchWindowInsetsAnimationStarted(InsetsAnimation animation) {
-        if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationListener != null) {
-            mListenerInfo.mWindowInsetsAnimationListener.onStarted(animation);
+    /**
+     * Dispatches {@link WindowInsetsAnimationCallback#onStarted(InsetsAnimation, AnimationBounds)}
+     * when Window Insets animation is started.
+     * @param animation current animation
+     * @param bounds the upper and lower {@link AnimationBounds} that provides range of
+     *  {@link InsetsAnimation}.
+     * @return the upper and lower {@link AnimationBounds}.
+     */
+    @NonNull
+    public AnimationBounds dispatchWindowInsetsAnimationStarted(
+            @NonNull InsetsAnimation animation, @NonNull AnimationBounds bounds) {
+        if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) {
+            return mListenerInfo.mWindowInsetsAnimationCallback.onStarted(animation, bounds);
         }
+        return bounds;
     }
 
-    WindowInsets dispatchWindowInsetsAnimationProgress(WindowInsets insets) {
-        if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationListener != null) {
-            return mListenerInfo.mWindowInsetsAnimationListener.onProgress(insets);
+    /**
+     * Dispatches {@link WindowInsetsAnimationCallback#onProgress(WindowInsets)}
+     * when Window Insets animation makes progress.
+     * @param insets The current {@link WindowInsets}.
+     * @return current {@link WindowInsets}.
+     */
+    @NonNull
+    public WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets) {
+        if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) {
+            return mListenerInfo.mWindowInsetsAnimationCallback.onProgress(insets);
         } else {
             return insets;
         }
     }
 
-    void dispatchWindowInsetsAnimationFinished(InsetsAnimation animation) {
-        if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationListener != null) {
-            mListenerInfo.mWindowInsetsAnimationListener.onFinished(animation);
+    /**
+     * Dispatches {@link WindowInsetsAnimationCallback#onFinished(InsetsAnimation)}
+     * when Window Insets animation finishes.
+     * @param animation The current ongoing {@link InsetsAnimation}.
+     */
+    public void dispatchWindowInsetsAnimationFinished(@NonNull InsetsAnimation animation) {
+        if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) {
+            mListenerInfo.mWindowInsetsAnimationCallback.onFinished(animation);
         }
     }
 
@@ -11253,7 +11276,6 @@
      * @return The {@link WindowInsetsController} or {@code null} if the view isn't attached to a
      *         a window.
      * @see Window#getInsetsController()
-     * @hide pending unhide
      */
     public @Nullable WindowInsetsController getWindowInsetsController() {
         if (mAttachInfo != null) {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 853a302..4334bb5 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -51,7 +51,8 @@
 import android.util.Pools.SynchronizedPool;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
-import android.view.WindowInsetsAnimationListener.InsetsAnimation;
+import android.view.WindowInsetsAnimationCallback.AnimationBounds;
+import android.view.WindowInsetsAnimationCallback.InsetsAnimation;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -7198,16 +7199,20 @@
     }
 
     @Override
-    void dispatchWindowInsetsAnimationStarted(InsetsAnimation animation) {
-        super.dispatchWindowInsetsAnimationStarted(animation);
+    @NonNull
+    public AnimationBounds dispatchWindowInsetsAnimationStarted(
+            @NonNull InsetsAnimation animation, @NonNull AnimationBounds bounds) {
+        super.dispatchWindowInsetsAnimationStarted(animation, bounds);
         final int count = getChildCount();
         for (int i = 0; i < count; i++) {
-            getChildAt(i).dispatchWindowInsetsAnimationStarted(animation);
+            getChildAt(i).dispatchWindowInsetsAnimationStarted(animation, bounds);
         }
+        return bounds;
     }
 
     @Override
-    WindowInsets dispatchWindowInsetsAnimationProgress(WindowInsets insets) {
+    @NonNull
+    public WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets) {
         insets = super.dispatchWindowInsetsAnimationProgress(insets);
         final int count = getChildCount();
         for (int i = 0; i < count; i++) {
@@ -7217,7 +7222,7 @@
     }
 
     @Override
-    void dispatchWindowInsetsAnimationFinished(InsetsAnimation animation) {
+    public void dispatchWindowInsetsAnimationFinished(@NonNull InsetsAnimation animation) {
         super.dispatchWindowInsetsAnimationFinished(animation);
         final int count = getChildCount();
         for (int i = 0; i < count; i++) {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index af1882b..ff31115 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -2573,7 +2573,8 @@
     /**
      * @return The {@link WindowInsetsController} associated with this window
      * @see View#getWindowInsetsController()
-     * @hide pending unhide
      */
-    public abstract @NonNull WindowInsetsController getInsetsController();
+    public @Nullable WindowInsetsController getInsetsController() {
+        return null;
+    }
 }
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index b16a4ca..2404c84 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -177,7 +177,7 @@
      * @return The insets that include system bars indicated by {@code typeMask}, taken from
      *         {@code typeInsetsMap}.
      */
-    private static Insets getInsets(Insets[] typeInsetsMap, @InsetsType int typeMask) {
+    static Insets getInsets(Insets[] typeInsetsMap, @InsetsType int typeMask) {
         Insets result = null;
         for (int i = FIRST; i <= LAST; i = i << 1) {
             if ((typeMask & i) == 0) {
@@ -289,9 +289,8 @@
      *
      * @param typeMask Bit mask of {@link InsetsType}s to query the insets for.
      * @return The insets.
-     *
-     * @hide pending unhide
      */
+    @NonNull
     public Insets getInsets(@InsetsType int typeMask) {
         return getInsets(mTypeInsetsMap, typeMask);
     }
@@ -313,8 +312,8 @@
      *                                  insets are not available for this type as the height of the
      *                                  IME is dynamic depending on the {@link EditorInfo} of the
      *                                  currently focused view, as well as the UI state of the IME.
-     * @hide pending unhide
      */
+    @NonNull
     public Insets getMaxInsets(@InsetsType int typeMask) throws IllegalArgumentException {
         if ((typeMask & IME) != 0) {
             throw new IllegalArgumentException("Unable to query the maximum insets for IME");
@@ -329,7 +328,6 @@
      * @param typeMask Bit mask of {@link Type.InsetsType}s to query visibility status.
      * @return {@code true} if and only if all windows included in {@code typeMask} are currently
      *         visible on screen.
-     * @hide pending unhide
      */
     public boolean isVisible(@InsetsType int typeMask) {
         for (int i = FIRST; i <= LAST; i = i << 1) {
@@ -874,7 +872,7 @@
         return typeInsetsMap;
     }
 
-    private static Insets insetInsets(Insets insets, int left, int top, int right, int bottom) {
+    static Insets insetInsets(Insets insets, int left, int top, int right, int bottom) {
         int newLeft = Math.max(0, insets.left - left);
         int newTop = Math.max(0, insets.top - top);
         int newRight = Math.max(0, insets.right - right);
@@ -1015,7 +1013,6 @@
          * @param insets The insets to set.
          *
          * @return itself
-         * @hide pending unhide
          */
         @NonNull
         public Builder setInsets(@InsetsType int typeMask, @NonNull Insets insets) {
@@ -1046,7 +1043,6 @@
          *                                  the IME is dynamic depending on the {@link EditorInfo}
          *                                  of the currently focused view, as well as the UI
          *                                  state of the IME.
-         * @hide pending unhide
          */
         @NonNull
         public Builder setMaxInsets(@InsetsType int typeMask, @NonNull Insets insets)
@@ -1070,7 +1066,6 @@
          * @param visible Whether to mark the windows as visible or not.
          *
          * @return itself
-         * @hide pending unhide
          */
         @NonNull
         public Builder setVisible(@InsetsType int typeMask, boolean visible) {
@@ -1145,7 +1140,6 @@
 
     /**
      * Class that defines different types of sources causing window insets.
-     * @hide pending unhide
      */
     public static final class Type {
 
diff --git a/core/java/android/view/WindowInsetsAnimationCallback.java b/core/java/android/view/WindowInsetsAnimationCallback.java
new file mode 100644
index 0000000..8ae8520
--- /dev/null
+++ b/core/java/android/view/WindowInsetsAnimationCallback.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2019 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.view;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Insets;
+import android.view.WindowInsets.Type.InsetsType;
+import android.view.animation.Interpolator;
+
+/**
+ * Interface that allows the application to listen to animation events for windows that cause
+ * insets.
+ */
+public interface WindowInsetsAnimationCallback {
+
+    /**
+     * Called when an inset animation gets started.
+     * <p>
+     * Note that, like {@link #onProgress}, dispatch of the animation start event is hierarchical:
+     * It will starts at the root of the view hierarchy and then traverse it and invoke the callback
+     * of the specific {@link View} that is being traversed. The method my return a modified
+     * instance of the bounds by calling {@link AnimationBounds#inset} to indicate that a part of
+     * the insets have been used to offset or clip its children, and the children shouldn't worry
+     * about that part anymore.
+     *
+     * @param animation The animation that is about to start.
+     * @param bounds The bounds in which animation happens.
+     * @return The animation representing the part of the insets that should be dispatched to the
+     *         subtree of the hierarchy.
+     */
+    @NonNull
+    default AnimationBounds onStarted(
+            @NonNull InsetsAnimation animation, @NonNull AnimationBounds bounds) {
+        return bounds;
+    }
+
+    /**
+     * Called when the insets change as part of running an animation. Note that even if multiple
+     * animations for different types are running, there will only be one progress callback per
+     * frame. The {@code insets} passed as an argument represents the overall state and will include
+     * all types, regardless of whether they are animating or not.
+     * <p>
+     * Note that insets dispatch is hierarchical: It will start at the root of the view hierarchy,
+     * and then traverse it and invoke the callback of the specific {@link View} being traversed.
+     * The method may return a modified instance by calling
+     * {@link WindowInsets#inset(int, int, int, int)} to indicate that a part of the insets have
+     * been used to offset or clip its children, and the children shouldn't worry about that part
+     * anymore.
+     * TODO: Introduce a way to map (type -> InsetAnimation) so app developer can query animation
+     *  for a given type e.g. callback.getAnimation(type) OR controller.getAnimation(type).
+     *  Or on the controller directly?
+     * @param insets The current insets.
+     * @return The insets to dispatch to the subtree of the hierarchy.
+     */
+    @NonNull
+    WindowInsets onProgress(@NonNull WindowInsets insets);
+
+    /**
+     * Called when an inset animation has finished.
+     *
+     * @param animation The animation that has finished running. This will be the same instance as
+     *                  passed into {@link #onStarted}
+     */
+    default void onFinished(@NonNull InsetsAnimation animation) {
+    }
+
+    /**
+     * Class representing an animation of a set of windows that cause insets.
+     */
+    final class InsetsAnimation {
+
+        private final @InsetsType int mTypeMask;
+        private float mFraction;
+        @Nullable private final Interpolator mInterpolator;
+        private long mDurationMs;
+
+        public InsetsAnimation(
+                @InsetsType int typeMask, @Nullable Interpolator interpolator, long durationMs) {
+            mTypeMask = typeMask;
+            mInterpolator = interpolator;
+            mDurationMs = durationMs;
+        }
+
+        /**
+         * @return The bitmask of {@link WindowInsets.Type.InsetsType}s that are animating.
+         */
+        public @InsetsType int getTypeMask() {
+            return mTypeMask;
+        }
+
+        /**
+         * Returns the raw fractional progress of this animation between
+         * {@link AnimationBounds#getLowerBound()} and {@link AnimationBounds#getUpperBound()}. Note
+         * that this progress is the global progress of the animation, whereas
+         * {@link WindowInsetsAnimationCallback#onProgress} will only dispatch the insets that may
+         * be inset with {@link WindowInsets#inset} by parents of views in the hierarchy.
+         * Progress per insets animation is global for the entire animation. One animation animates
+         * all things together (in, out, ...). If they don't animate together, we'd have
+         * multiple animations.
+         *
+         * @return The current progress of this animation.
+         */
+        @FloatRange(from = 0f, to = 1f)
+        public float getFraction() {
+            return mFraction;
+        }
+
+        /**
+         * Returns the interpolated fractional progress of this animation between
+         * {@link AnimationBounds#getLowerBound()} and {@link AnimationBounds#getUpperBound()}. Note
+         * that this progress is the global progress of the animation, whereas
+         * {@link WindowInsetsAnimationCallback#onProgress} will only dispatch the insets that may
+         * be inset with {@link WindowInsets#inset} by parents of views in the hierarchy.
+         * Progress per insets animation is global for the entire animation. One animation animates
+         * all things together (in, out, ...). If they don't animate together, we'd have
+         * multiple animations.
+         * @see #getFraction() for raw fraction.
+         * @return The current interpolated progress of this animation. -1 if interpolator isn't
+         * specified.
+         */
+        public float getInterpolatedFraction() {
+            if (mInterpolator != null) {
+                return mInterpolator.getInterpolation(mFraction);
+            }
+            return -1;
+        }
+
+        @Nullable
+        public Interpolator getInterpolator() {
+            return mInterpolator;
+        }
+
+        /**
+         * @return duration of animation in {@link java.util.concurrent.TimeUnit#MILLISECONDS}.
+         */
+        public long getDurationMillis() {
+            return mDurationMs;
+        }
+
+        /**
+         * Set fraction of the progress if {@link WindowInsets.Type.InsetsType} animation is
+         * controlled by the app {@see #getCurrentFraction}.
+         * <p>Note: If app didn't create {@link InsetsAnimation}, it shouldn't set progress either.
+         * Progress would be set by system with the system-default animation.
+         * </p>
+         * @param fraction fractional progress between 0 and 1 where 0 represents hidden and
+         *                zero progress and 1 represent fully shown final state.
+         */
+        public void setFraction(@FloatRange(from = 0f, to = 1f) float fraction) {
+            mFraction = fraction;
+        }
+
+        /**
+         * Set duration of the animation if {@link WindowInsets.Type.InsetsType} animation is
+         * controlled by the app.
+         * <p>Note: If app didn't create {@link InsetsAnimation}, it shouldn't set duration either.
+         * Duration would be set by system with the system-default animation.
+         * </p>
+         * @param durationMs in {@link java.util.concurrent.TimeUnit#MILLISECONDS}
+         */
+        public void setDuration(long durationMs) {
+            mDurationMs = durationMs;
+        }
+    }
+
+    /**
+     * Class representing the range of an {@link InsetsAnimation}
+     */
+    final class AnimationBounds {
+        private final Insets mLowerBound;
+        private final Insets mUpperBound;
+
+        public AnimationBounds(@NonNull Insets lowerBound, @NonNull Insets upperBound) {
+            mLowerBound = lowerBound;
+            mUpperBound = upperBound;
+        }
+
+        /**
+         * Queries the lower inset bound of the animation. If the animation is about showing or
+         * hiding a window that cause insets, the lower bound is {@link Insets#NONE} and the upper
+         * bound is the same as {@link WindowInsets#getInsets(int)} for the fully shown state. This
+         * is the same as {@link WindowInsetsAnimationController#getHiddenStateInsets} and
+         * {@link WindowInsetsAnimationController#getShownStateInsets} in case the listener gets
+         * invoked because of an animation that originates from
+         * {@link WindowInsetsAnimationController}.
+         * <p>
+         * However, if the size of a window that causes insets is changing, these are the
+         * lower/upper bounds of that size animation.
+         * </p>
+         * There are no overlapping animations for a specific type, but there may be multiple
+         * animations running at the same time for different inset types.
+         *
+         * @see #getUpperBound()
+         * @see WindowInsetsAnimationController#getHiddenStateInsets
+         */
+        @NonNull
+        public Insets getLowerBound() {
+            return mLowerBound;
+        }
+
+        /**
+         * Queries the upper inset bound of the animation. If the animation is about showing or
+         * hiding a window that cause insets, the lower bound is {@link Insets#NONE}
+         * nd the upper bound is the same as {@link WindowInsets#getInsets(int)} for the fully
+         * shown state. This is the same as
+         * {@link WindowInsetsAnimationController#getHiddenStateInsets} and
+         * {@link WindowInsetsAnimationController#getShownStateInsets} in case the listener gets
+         * invoked because of an animation that originates from
+         * {@link WindowInsetsAnimationController}.
+         * <p>
+         * However, if the size of a window that causes insets is changing, these are the
+         * lower/upper bounds of that size animation.
+         * <p>
+         * There are no overlapping animations for a specific type, but there may be multiple
+         * animations running at the same time for different inset types.
+         *
+         * @see #getLowerBound()
+         * @see WindowInsetsAnimationController#getShownStateInsets
+         */
+        @NonNull
+        public Insets getUpperBound() {
+            return mUpperBound;
+        }
+
+        /**
+         * Insets both the lower and upper bound by the specified insets. This is to be used in
+         * {@link WindowInsetsAnimationCallback#onStarted} to indicate that a part of the insets has
+         * been used to offset or clip its children, and the children shouldn't worry about that
+         * part anymore.
+         *
+         * @param insets The amount to inset.
+         * @return A copy of this instance inset in the given directions.
+         * @see WindowInsets#inset
+         * @see WindowInsetsAnimationCallback#onStarted
+         */
+        @NonNull
+        public AnimationBounds inset(@NonNull Insets insets) {
+            return new AnimationBounds(
+                    // TODO: refactor so that WindowInsets.insetInsets() is in a more appropriate
+                    //  place eventually.
+                    WindowInsets.insetInsets(
+                            mLowerBound, insets.left, insets.top, insets.right, insets.bottom),
+                    WindowInsets.insetInsets(
+                            mUpperBound, insets.left, insets.top, insets.right, insets.bottom));
+        }
+    }
+}
diff --git a/core/java/android/view/WindowInsetsAnimationControlListener.java b/core/java/android/view/WindowInsetsAnimationControlListener.java
index 33fb327..8a226c1 100644
--- a/core/java/android/view/WindowInsetsAnimationControlListener.java
+++ b/core/java/android/view/WindowInsetsAnimationControlListener.java
@@ -22,19 +22,17 @@
 
 /**
  * Interface that informs the client about {@link WindowInsetsAnimationController} state changes.
- * @hide pending unhide
  */
 public interface WindowInsetsAnimationControlListener {
 
     /**
-     * Gets called as soon as the animation is ready to be controlled. This may be
-     * delayed when the IME needs to redraw because of an {@link EditorInfo} change, or when the
-     * window is starting up.
+     * Called when the animation is ready to be controlled. This may be delayed when the IME needs
+     * to redraw because of an {@link EditorInfo} change, or when the window is starting up.
      *
      * @param controller The controller to control the inset animation.
      * @param types The {@link InsetsType}s it was able to gain control over. Note that this may be
      *              different than the types passed into
-     *              {@link WindowInsetsController#controlWindowInsetsAnimation} in case the window
+     *              {@link WindowInsetsController#controlInputMethodAnimation} in case the window
      *              wasn't able to gain the controls because it wasn't the IME target or not
      *              currently the window that's controlling the system bars.
      */
diff --git a/core/java/android/view/WindowInsetsAnimationController.java b/core/java/android/view/WindowInsetsAnimationController.java
index 5cbf3b8..5149103 100644
--- a/core/java/android/view/WindowInsetsAnimationController.java
+++ b/core/java/android/view/WindowInsetsAnimationController.java
@@ -16,83 +16,127 @@
 
 package android.view;
 
+import android.annotation.FloatRange;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.graphics.Insets;
 import android.view.WindowInsets.Type.InsetsType;
-import android.view.WindowInsetsAnimationListener.InsetsAnimation;
+import android.view.WindowInsetsAnimationCallback.AnimationBounds;
 
 /**
- * Interface to control a window inset animation frame-by-frame.
- * @hide pending unhide
+ * Controller for app-driven animation of system windows.
+ *  <p>
+ *  {@code WindowInsetsAnimationController} lets apps animate system windows such as
+ *  the {@link android.inputmethodservice.InputMethodService IME}. The animation is
+ *  synchronized, such that changes the system windows and the app's current frame
+ *  are rendered at the same time.
+ *  <p>
+ *  Control is obtained through {@link WindowInsetsController#controlInputMethodAnimation}.
  */
+@SuppressLint("NotClosable")
 public interface WindowInsetsAnimationController {
 
     /**
      * Retrieves the {@link Insets} when the windows this animation is controlling are fully hidden.
      * <p>
+     * Note that these insets are always relative to the window, which is the same as being relative
+     * to {@link View#getRootView}
+     * <p>
      * If there are any animation listeners registered, this value is the same as
-     * {@link InsetsAnimation#getLowerBound()} that will be passed into the callbacks.
+     * {@link AnimationBounds#getLowerBound()} that is being be passed into the root view of the
+     * hierarchy.
      *
      * @return Insets when the windows this animation is controlling are fully hidden.
      *
-     * @see InsetsAnimation#getLowerBound()
+     * @see AnimationBounds#getLowerBound()
      */
     @NonNull Insets getHiddenStateInsets();
 
     /**
      * Retrieves the {@link Insets} when the windows this animation is controlling are fully shown.
      * <p>
-     * In case the size of a window causing insets is changing in the middle of the animation, we
-     * execute that height change after this animation has finished.
+     * Note that these insets are always relative to the window, which is the same as being relative
+     * to {@link View#getRootView}
      * <p>
      * If there are any animation listeners registered, this value is the same as
-     * {@link InsetsAnimation#getUpperBound()} that will be passed into the callbacks.
+     * {@link AnimationBounds#getUpperBound()} that is being passed into the root view of hierarchy.
      *
      * @return Insets when the windows this animation is controlling are fully shown.
      *
-     * @see InsetsAnimation#getUpperBound()
+     * @see AnimationBounds#getUpperBound()
      */
     @NonNull Insets getShownStateInsets();
 
     /**
-     * @return The current insets on the window. These will follow any animation changes.
+     * Retrieves the current insets.
+     * <p>
+     * Note that these insets are always relative to the window, which is the same as
+     * being relative
+     * to {@link View#getRootView}
+     * @return The current insets on the currently showing frame. These insets will change as the
+     * animation progresses to reflect the current insets provided by the controlled window.
      */
     @NonNull Insets getCurrentInsets();
 
     /**
+     *  Returns the progress as previously set by {@code fraction} in {@link #setInsetsAndAlpha}
+     *
+     *  @return the progress of the animation, where {@code 0} is fully hidden and {@code 1} is
+     *  fully shown.
+     * <p>
+     *  Note: this value represents raw overall progress of the animation
+     *  i.e. the combined progress of insets and alpha.
+     *  <p>
+     */
+    @FloatRange(from = 0f, to = 1f)
+    float getCurrentFraction();
+
+    /**
      * @return The {@link InsetsType}s this object is currently controlling.
      */
     @InsetsType int getTypes();
 
     /**
-     * Modifies the insets by indirectly moving the windows around in the system that are causing
-     * window insets.
+     * Modifies the insets for the frame being drawn by indirectly moving the windows around in the
+     * system that are causing window insets.
      * <p>
-     * Note that this will <b>not</b> inform the view system of a full inset change via
+     * Note that these insets are always relative to the window, which is the same as being relative
+     * to {@link View#getRootView}
+     * <p>
+     * Also note that this will <b>not</b> inform the view system of a full inset change via
      * {@link View#dispatchApplyWindowInsets} in order to avoid a full layout pass during the
      * animation. If you'd like to animate views during a window inset animation, register a
-     * {@link WindowInsetsAnimationListener} by calling
-     * {@link View#setWindowInsetsAnimationListener(WindowInsetsAnimationListener)} that will be
-     * notified about any insets change via {@link WindowInsetsAnimationListener#onProgress} during
+     * {@link WindowInsetsAnimationCallback} by calling
+     * {@link View#setWindowInsetsAnimationCallback(WindowInsetsAnimationCallback)} that will be
+     * notified about any insets change via {@link WindowInsetsAnimationCallback#onProgress} during
      * the animation.
      * <p>
      * {@link View#dispatchApplyWindowInsets} will instead be called once the animation has
      * finished, i.e. once {@link #finish} has been called.
+     * Note: If there are no insets, alpha animation is still applied.
      *
      * @param insets The new insets to apply. Based on the requested insets, the system will
      *               calculate the positions of the windows in the system causing insets such that
      *               the resulting insets of that configuration will match the passed in parameter.
      *               Note that these insets are being clamped to the range from
-     *               {@link #getHiddenStateInsets} to {@link #getShownStateInsets}
+     *               {@link #getHiddenStateInsets} to {@link #getShownStateInsets}.
+     *               If you intend on changing alpha only, pass null or {@link #getCurrentInsets()}.
+     * @param alpha  The new alpha to apply to the inset side.
+     * @param fraction instantaneous animation progress. This value is dispatched to
+     *                 {@link WindowInsetsAnimationCallback}.
      *
-     * @see WindowInsetsAnimationListener
-     * @see View#setWindowInsetsAnimationListener(WindowInsetsAnimationListener)
+     * @see WindowInsetsAnimationCallback
+     * @see View#setWindowInsetsAnimationCallback(WindowInsetsAnimationCallback)
      */
-    void changeInsets(@NonNull Insets insets);
+    void setInsetsAndAlpha(@Nullable Insets insets, @FloatRange(from = 0f, to = 1f) float alpha,
+            @FloatRange(from = 0f, to = 1f) float fraction);
 
     /**
-     * @param shownTypes The list of windows causing insets that should remain shown after finishing
-     *                   the animation.
+     * Finishes the animation, and leaves the windows shown or hidden. After invoking
+     * {@link #finish(boolean)}, this instance is no longer valid.
+     * @param shown if {@code true}, the windows will be shown after finishing the
+     *              animation. Otherwise they will be hidden.
      */
-    void finish(@InsetsType int shownTypes);
+    void finish(boolean shown);
 }
diff --git a/core/java/android/view/WindowInsetsAnimationListener.java b/core/java/android/view/WindowInsetsAnimationListener.java
deleted file mode 100644
index f734b4b..0000000
--- a/core/java/android/view/WindowInsetsAnimationListener.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view;
-
-import android.graphics.Insets;
-
-/**
- * Interface that allows the application to listen to animation events for windows that cause
- * insets.
- * @hide pending unhide
- */
-public interface WindowInsetsAnimationListener {
-
-    /**
-     * Called when an inset animation gets started.
-     *
-     * @param animation The animation that is about to start.
-     */
-    void onStarted(InsetsAnimation animation);
-
-    /**
-     * Called when the insets change as part of running an animation. Note that even if multiple
-     * animations for different types are running, there will only be one progress callback per
-     * frame. The {@code insets} passed as an argument represents the overall state and will include
-     * all types, regardless of whether they are animating or not.
-     * <p>
-     * Note that insets dispatch is hierarchical: It will start at the root of the view hierarchy,
-     * and then traverse it and invoke the callback of the specific {@link View} being traversed.
-     * The callback may return a modified instance by calling {@link WindowInsets#inset(int, int, int, int)}
-     * to indicate that a part of the insets have been used to offset or clip its children, and the
-     * children shouldn't worry about that part anymore.
-     *
-     * @param insets The current insets.
-     * @return The insets to dispatch to the subtree of the hierarchy.
-     */
-    WindowInsets onProgress(WindowInsets insets);
-
-    /**
-     * Called when an inset animation has finished.
-     *
-     * @param animation The animation that has finished running.
-     */
-    void onFinished(InsetsAnimation animation);
-
-    /**
-     * Class representing an animation of a set of windows that cause insets.
-     */
-    class InsetsAnimation {
-
-        private final @WindowInsets.Type.InsetsType int mTypeMask;
-        private final Insets mLowerBound;
-        private final Insets mUpperBound;
-
-        /**
-         * @hide
-         */
-        InsetsAnimation(int typeMask, Insets lowerBound, Insets upperBound) {
-            mTypeMask = typeMask;
-            mLowerBound = lowerBound;
-            mUpperBound = upperBound;
-        }
-
-        /**
-         * @return The bitmask of {@link WindowInsets.Type.InsetsType}s that are animating.
-         */
-        public @WindowInsets.Type.InsetsType int getTypeMask() {
-            return mTypeMask;
-        }
-
-        /**
-         * Queries the lower inset bound of the animation. If the animation is about showing or
-         * hiding a window that cause insets, the lower bound is {@link Insets#NONE} and the upper
-         * bound is the same as {@link WindowInsets#getInsets(int)} for the fully shown state. This
-         * is the same as {@link WindowInsetsAnimationController#getHiddenStateInsets} and
-         * {@link WindowInsetsAnimationController#getShownStateInsets} in case the listener gets
-         * invoked because of an animation that originates from
-         * {@link WindowInsetsAnimationController}.
-         * <p>
-         * However, if the size of a window that causes insets is changing, these are the
-         * lower/upper bounds of that size animation.
-         * <p>
-         * There are no overlapping animations for a specific type, but there may be two animations
-         * running at the same time for different inset types.
-         *
-         * @see #getUpperBound()
-         * @see WindowInsetsAnimationController#getHiddenStateInsets
-         * TODO: It's a bit weird that these are global per window but onProgress is hierarchical.
-         * TODO: If multiple types are animating, querying the bound per type isn't possible. Should
-         * we:
-         * 1. Offer bounds by type here?
-         * 2. Restrict one animation to one single type only?
-         * Returning WindowInsets here isn't feasible in case of overlapping animations: We can't
-         * fill in the insets for the types from the other animation into the WindowInsets object
-         * as it's changing as well.
-         */
-        public Insets getLowerBound() {
-            return mLowerBound;
-        }
-
-        /**
-         * @see #getLowerBound()
-         * @see WindowInsetsAnimationController#getShownStateInsets
-         */
-        public Insets getUpperBound() {
-            return mUpperBound;
-        }
-    }
-}
diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java
index a045a6a..6de56be 100644
--- a/core/java/android/view/WindowInsetsController.java
+++ b/core/java/android/view/WindowInsetsController.java
@@ -30,7 +30,6 @@
  * Interface to control windows that generate insets.
  *
  * TODO Needs more information and examples once the API is more baked.
- * @hide pending unhide
  */
 public interface WindowInsetsController {
 
@@ -64,7 +63,10 @@
      */
     int APPEARANCE_LIGHT_NAVIGATION_BARS = 1 << 4;
 
-    /** Determines the appearance of system bars. */
+    /**
+     * Determines the appearance of system bars.
+     * @hide
+     */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(flag = true, value = {APPEARANCE_OPAQUE_STATUS_BARS, APPEARANCE_OPAQUE_NAVIGATION_BARS,
             APPEARANCE_LOW_PROFILE_BARS, APPEARANCE_LIGHT_STATUS_BARS,
@@ -75,33 +77,40 @@
     /**
      * The default option for {@link #setSystemBarsBehavior(int)}. System bars will be forcibly
      * shown on any user interaction on the corresponding display if navigation bars are hidden by
-     * {@link #hide(int)} or {@link WindowInsetsAnimationController#changeInsets(Insets)}.
+     * {@link #hide(int)} or
+     * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)}.
+     * @hide
      */
     int BEHAVIOR_SHOW_BARS_BY_TOUCH = 0;
 
     /**
      * Option for {@link #setSystemBarsBehavior(int)}: Window would like to remain interactive when
      * hiding navigation bars by calling {@link #hide(int)} or
-     * {@link WindowInsetsAnimationController#changeInsets(Insets)}.
+     * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)}.
      *
      * <p>When system bars are hidden in this mode, they can be revealed with system gestures, such
      * as swiping from the edge of the screen where the bar is hidden from.</p>
+     * @hide
      */
     int BEHAVIOR_SHOW_BARS_BY_SWIPE = 1;
 
     /**
      * Option for {@link #setSystemBarsBehavior(int)}: Window would like to remain interactive when
      * hiding navigation bars by calling {@link #hide(int)} or
-     * {@link WindowInsetsAnimationController#changeInsets(Insets)}.
+     * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)}.
      *
      * <p>When system bars are hidden in this mode, they can be revealed temporarily with system
      * gestures, such as swiping from the edge of the screen where the bar is hidden from. These
      * transient system bars will overlay app’s content, may have some degree of transparency, and
      * will automatically hide after a short timeout.</p>
+     * @hide
      */
     int BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2;
 
-    /** Determines the behavior of system bars when hiding them by calling {@link #hide}. */
+    /**
+     * Determines the behavior of system bars when hiding them by calling {@link #hide}.
+     * @hide
+     */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(value = {BEHAVIOR_SHOW_BARS_BY_TOUCH, BEHAVIOR_SHOW_BARS_BY_SWIPE,
             BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE})
@@ -139,23 +148,27 @@
      * the position of the windows in the system causing insets directly.
      *
      * @param types The {@link InsetsType}s the application has requested to control.
+     * @param durationMillis duration of animation in
+     *                       {@link java.util.concurrent.TimeUnit#MILLISECONDS}
      * @param listener The {@link WindowInsetsAnimationControlListener} that gets called when the
      *                 windows are ready to be controlled, among other callbacks.
      * @hide
      */
-    void controlWindowInsetsAnimation(@InsetsType int types,
+    void controlWindowInsetsAnimation(@InsetsType int types, long durationMillis,
             @NonNull WindowInsetsAnimationControlListener listener);
 
     /**
      * Lets the application control the animation for showing the IME in a frame-by-frame manner by
      * modifying the position of the IME when it's causing insets.
      *
+     * @param durationMillis duration of the animation in
+     *                       {@link java.util.concurrent.TimeUnit#MILLISECONDS}
      * @param listener The {@link WindowInsetsAnimationControlListener} that gets called when the
      *                 IME are ready to be controlled, among other callbacks.
      */
-    default void controlInputMethodAnimation(
+    default void controlInputMethodAnimation(long durationMillis,
             @NonNull WindowInsetsAnimationControlListener listener) {
-        controlWindowInsetsAnimation(ime(), listener);
+        controlWindowInsetsAnimation(ime(), durationMillis, listener);
     }
 
     /**
@@ -166,7 +179,7 @@
      * the event by observing {@link View#onApplyWindowInsets} and checking visibility with
      * {@link WindowInsets#isVisible}.
      *
-     * @see #controlInputMethodAnimation(WindowInsetsAnimationControlListener)
+     * @see #controlInputMethodAnimation(long, WindowInsetsAnimationControlListener)
      * @see #hideInputMethod()
      */
     default void showInputMethod() {
@@ -181,7 +194,7 @@
      * the event by observing {@link View#onApplyWindowInsets} and checking visibility with
      * {@link WindowInsets#isVisible}.
      *
-     * @see #controlInputMethodAnimation(WindowInsetsAnimationControlListener)
+     * @see #controlInputMethodAnimation(long, WindowInsetsAnimationControlListener)
      * @see #showInputMethod()
      */
     default void hideInputMethod() {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index c571737..a6304b1 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -3473,18 +3473,10 @@
         return applyAsync(context, parent, executor, listener, null);
     }
 
-    private CancellationSignal startTaskOnExecutor(AsyncApplyTask task, Executor executor) {
-        CancellationSignal cancelSignal = new CancellationSignal();
-        cancelSignal.setOnCancelListener(task);
-
-        task.executeOnExecutor(executor == null ? AsyncTask.THREAD_POOL_EXECUTOR : executor);
-        return cancelSignal;
-    }
-
     /** @hide */
     public CancellationSignal applyAsync(Context context, ViewGroup parent,
             Executor executor, OnViewAppliedListener listener, OnClickHandler handler) {
-        return startTaskOnExecutor(getAsyncApplyTask(context, parent, listener, handler), executor);
+        return getAsyncApplyTask(context, parent, listener, handler).startTaskOnExecutor(executor);
     }
 
     private AsyncApplyTask getAsyncApplyTask(Context context, ViewGroup parent,
@@ -3495,6 +3487,7 @@
 
     private class AsyncApplyTask extends AsyncTask<Void, Void, ViewTree>
             implements CancellationSignal.OnCancelListener {
+        final CancellationSignal mCancelSignal = new CancellationSignal();
         final RemoteViews mRV;
         final ViewGroup mParent;
         final Context mContext;
@@ -3545,6 +3538,7 @@
 
         @Override
         protected void onPostExecute(ViewTree viewTree) {
+            mCancelSignal.setOnCancelListener(null);
             if (mError == null) {
                 if (mListener != null) {
                     mListener.onViewInflated(viewTree.mRoot);
@@ -3582,6 +3576,12 @@
         public void onCancel() {
             cancel(true);
         }
+
+        private CancellationSignal startTaskOnExecutor(Executor executor) {
+            mCancelSignal.setOnCancelListener(this);
+            executeOnExecutor(executor == null ? AsyncTask.THREAD_POOL_EXECUTOR : executor);
+            return mCancelSignal;
+        }
     }
 
     /**
@@ -3646,8 +3646,8 @@
             }
         }
 
-        return startTaskOnExecutor(new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(),
-                context, listener, handler, v), executor);
+        return new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(),
+                context, listener, handler, v).startTaskOnExecutor(executor);
     }
 
     private void performApply(View v, ViewGroup parent, OnClickHandler handler) {
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 8856f99..f361784 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -111,6 +111,7 @@
 import com.android.internal.app.ResolverListAdapter.ViewHolder;
 import com.android.internal.app.chooser.ChooserTargetInfo;
 import com.android.internal.app.chooser.DisplayResolveInfo;
+import com.android.internal.app.chooser.MultiDisplayResolveInfo;
 import com.android.internal.app.chooser.NotSelectableTargetInfo;
 import com.android.internal.app.chooser.SelectableTargetInfo;
 import com.android.internal.app.chooser.SelectableTargetInfo.SelectableTargetInfoCommunicator;
@@ -1352,17 +1353,31 @@
         return getIntent().getBooleanExtra(Intent.EXTRA_AUTO_LAUNCH_SINGLE_CHOICE, true);
     }
 
-    @Override
-    public void showTargetDetails(ResolveInfo ri) {
-        if (ri == null) {
+    void showTargetDetails(TargetInfo ti) {
+        if (ti == null) {
             return;
         }
-
-        ComponentName name = ri.activityInfo.getComponentName();
+        ComponentName name = ti.getResolveInfo().activityInfo.getComponentName();
         boolean pinned = mPinnedSharedPrefs.getBoolean(name.flattenToString(), false);
-        ResolverTargetActionsDialogFragment f =
-                new ResolverTargetActionsDialogFragment(ri.loadLabel(getPackageManager()),
-                        name, pinned);
+
+        ResolverTargetActionsDialogFragment f;
+
+        // For multiple targets, include info on all targets
+        if (ti instanceof MultiDisplayResolveInfo) {
+            MultiDisplayResolveInfo mti = (MultiDisplayResolveInfo) ti;
+            List<CharSequence> labels = new ArrayList<>();
+
+            for (TargetInfo innerInfo : mti.getTargets()) {
+                labels.add(innerInfo.getResolveInfo().loadLabel(getPackageManager()));
+            }
+            f = new ResolverTargetActionsDialogFragment(
+                    mti.getResolveInfo().loadLabel(getPackageManager()), name, mti.getTargets(),
+                    labels);
+        } else {
+            f = new ResolverTargetActionsDialogFragment(
+                    ti.getResolveInfo().loadLabel(getPackageManager()), name, pinned);
+        }
+
         f.show(getFragmentManager(), TARGET_DETAILS_FRAGMENT_TAG);
     }
 
@@ -1416,8 +1431,26 @@
         }
 
         final long selectionCost = System.currentTimeMillis() - mChooserShownTime;
+
+        // Stacked apps get a disambiguation first
+        if (targetInfo instanceof MultiDisplayResolveInfo) {
+            MultiDisplayResolveInfo mti = (MultiDisplayResolveInfo) targetInfo;
+            CharSequence[] labels = new CharSequence[mti.getTargets().size()];
+            int i = 0;
+            for (TargetInfo ti : mti.getTargets()) {
+                labels[i++] = ti.getResolveInfo().loadLabel(getPackageManager());
+            }
+            ChooserStackedAppDialogFragment f = new ChooserStackedAppDialogFragment(
+                    targetInfo.getDisplayLabel(),
+                    ((MultiDisplayResolveInfo) targetInfo).getTargets(), labels);
+
+            f.show(getFragmentManager(), TARGET_DETAILS_FRAGMENT_TAG);
+            return;
+        }
+
         super.startSelected(which, always, filtered);
 
+
         if (currentListAdapter.getCount() > 0) {
             // Log the index of which type of target the user picked.
             // Lower values mean the ranking was better.
@@ -2363,7 +2396,7 @@
                 itemView.setOnLongClickListener(v -> {
                     showTargetDetails(
                             mChooserMultiProfilePagerAdapter.getActiveListAdapter()
-                                    .resolveInfoForPosition(mListPosition, /* filtered */ true));
+                                    .targetInfoForPosition(mListPosition, /* filtered */ true));
                     return true;
                 });
             }
@@ -2615,7 +2648,7 @@
                     @Override
                     public boolean onLongClick(View v) {
                         showTargetDetails(
-                                mChooserListAdapter.resolveInfoForPosition(
+                                mChooserListAdapter.targetInfoForPosition(
                                         holder.getItemIndex(column), true));
                         return true;
                     }
diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java
index 4eccf21..a8a676d 100644
--- a/core/java/com/android/internal/app/ChooserListAdapter.java
+++ b/core/java/com/android/internal/app/ChooserListAdapter.java
@@ -38,17 +38,22 @@
 import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
 import com.android.internal.app.chooser.ChooserTargetInfo;
 import com.android.internal.app.chooser.DisplayResolveInfo;
+import com.android.internal.app.chooser.MultiDisplayResolveInfo;
 import com.android.internal.app.chooser.SelectableTargetInfo;
 import com.android.internal.app.chooser.TargetInfo;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 public class ChooserListAdapter extends ResolverListAdapter {
     private static final String TAG = "ChooserListAdapter";
     private static final boolean DEBUG = false;
 
+    private boolean mEnableStackedApps = true;
+
     public static final int NO_POSITION = -1;
     public static final int TARGET_BAD = -1;
     public static final int TARGET_CALLER = 0;
@@ -218,7 +223,25 @@
 
     void updateAlphabeticalList() {
         mSortedList.clear();
-        mSortedList.addAll(mDisplayList);
+        if (mEnableStackedApps) {
+            // Consolidate multiple targets from same app.
+            Map<String, DisplayResolveInfo> consolidated = new HashMap<>();
+            for (DisplayResolveInfo info : mDisplayList) {
+                String packageName = info.getResolvedComponentName().getPackageName();
+                if (consolidated.get(packageName) != null) {
+                    // create consolidated target
+                    MultiDisplayResolveInfo multiDisplayResolveInfo =
+                            new MultiDisplayResolveInfo(packageName, info);
+                    multiDisplayResolveInfo.addTarget(consolidated.get(packageName));
+                    consolidated.put(packageName, multiDisplayResolveInfo);
+                } else {
+                    consolidated.put(packageName, info);
+                }
+            }
+            mSortedList.addAll(consolidated.values());
+        } else {
+            mSortedList.addAll(mDisplayList);
+        }
         Collections.sort(mSortedList, new ChooserActivity.AzInfoComparator(mContext));
     }
 
@@ -270,7 +293,7 @@
     }
 
     int getAlphaTargetCount() {
-        int standardCount = super.getCount();
+        int standardCount = mSortedList.size();
         return standardCount > mChooserListCommunicator.getMaxRankedTargets() ? standardCount : 0;
     }
 
diff --git a/core/java/com/android/internal/app/ChooserStackedAppDialogFragment.java b/core/java/com/android/internal/app/ChooserStackedAppDialogFragment.java
new file mode 100644
index 0000000..ff6582d
--- /dev/null
+++ b/core/java/com/android/internal/app/ChooserStackedAppDialogFragment.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 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.internal.app;
+
+import android.app.AlertDialog.Builder;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.content.res.Configuration;
+import android.os.Bundle;
+
+import com.android.internal.app.chooser.DisplayResolveInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Shows individual actions for a "stacked" app target - such as an app with multiple posting
+ * streams represented in the Sharesheet.
+ */
+public class ChooserStackedAppDialogFragment extends DialogFragment
+        implements DialogInterface.OnClickListener {
+    private static final String TITLE_KEY = "title";
+    private static final String PINNED_KEY = "pinned";
+
+    private List<DisplayResolveInfo> mTargetInfos = new ArrayList<>();
+    private CharSequence[] mLabels;
+
+    public ChooserStackedAppDialogFragment() {
+    }
+
+    public ChooserStackedAppDialogFragment(CharSequence title) {
+        Bundle args = new Bundle();
+        args.putCharSequence(TITLE_KEY, title);
+        setArguments(args);
+    }
+
+    public ChooserStackedAppDialogFragment(CharSequence title,
+            List<DisplayResolveInfo> targets, CharSequence[] labels) {
+        Bundle args = new Bundle();
+        args.putCharSequence(TITLE_KEY, title);
+        mTargetInfos = targets;
+        mLabels = labels;
+        setArguments(args);
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        final Bundle args = getArguments();
+        return new Builder(getContext())
+                .setCancelable(true)
+                .setItems(mLabels, this)
+                .setTitle(args.getCharSequence(TITLE_KEY))
+                .create();
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        final Bundle args = getArguments();
+        mTargetInfos.get(which).start(getActivity(), null);
+        dismiss();
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        // Dismiss on config changed (eg: rotation)
+        // TODO: Maintain state on config change
+        super.onConfigurationChanged(newConfig);
+        dismiss();
+    }
+}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index cb7f2e4..8dc3a07 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1160,7 +1160,7 @@
         return !target.isSuspended();
     }
 
-    public void showTargetDetails(ResolveInfo ri) {
+    void showTargetDetails(ResolveInfo ri) {
         Intent in = new Intent().setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                 .setData(Uri.fromParts("package", ri.activityInfo.packageName, null))
                 .addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
diff --git a/core/java/com/android/internal/app/ResolverTargetActionsDialogFragment.java b/core/java/com/android/internal/app/ResolverTargetActionsDialogFragment.java
index df91c4a..bdbe210 100644
--- a/core/java/com/android/internal/app/ResolverTargetActionsDialogFragment.java
+++ b/core/java/com/android/internal/app/ResolverTargetActionsDialogFragment.java
@@ -24,14 +24,19 @@
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.SharedPreferences;
+import android.content.res.Configuration;
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.Settings;
 
 import com.android.internal.R;
+import com.android.internal.app.chooser.DisplayResolveInfo;
+
+import java.util.ArrayList;
+import java.util.List;
 
 /**
- * Shows a dialog with actions to take on a chooser target
+ * Shows a dialog with actions to take on a chooser target.
  */
 public class ResolverTargetActionsDialogFragment extends DialogFragment
         implements DialogInterface.OnClickListener {
@@ -43,6 +48,10 @@
     private static final int TOGGLE_PIN_INDEX = 0;
     private static final int APP_INFO_INDEX = 1;
 
+    private List<DisplayResolveInfo> mTargetInfos = new ArrayList<>();
+    private List<CharSequence> mLabels = new ArrayList<>();
+    private boolean[] mPinned;
+
     public ResolverTargetActionsDialogFragment() {
     }
 
@@ -55,15 +64,43 @@
         setArguments(args);
     }
 
+    public ResolverTargetActionsDialogFragment(CharSequence title, ComponentName name,
+            List<DisplayResolveInfo> targets, List<CharSequence> labels) {
+        Bundle args = new Bundle();
+        args.putCharSequence(TITLE_KEY, title);
+        args.putParcelable(NAME_KEY, name);
+        mTargetInfos = targets;
+        mLabels = labels;
+        setArguments(args);
+    }
+
     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
         final Bundle args = getArguments();
         final int itemRes = args.getBoolean(PINNED_KEY, false)
                 ? R.array.resolver_target_actions_unpin
                 : R.array.resolver_target_actions_pin;
+        String[] defaultActions = getResources().getStringArray(itemRes);
+        CharSequence[] items;
+
+        if (mTargetInfos == null || mTargetInfos.size() < 2) {
+            items = defaultActions;
+        } else {
+            // Pin item for each sub-item
+            items = new CharSequence[mTargetInfos.size() + 1];
+            for (int i = 0; i < mTargetInfos.size(); i++) {
+                items[i] = mTargetInfos.get(i).isPinned()
+                         ? getResources().getString(R.string.unpin_specific_target, mLabels.get(i))
+                         : getResources().getString(R.string.pin_specific_target, mLabels.get(i));
+            }
+            // "App info"
+            items[mTargetInfos.size()] = defaultActions[1];
+        }
+
+
         return new Builder(getContext())
                 .setCancelable(true)
-                .setItems(itemRes, this)
+                .setItems(items, this)
                 .setTitle(args.getCharSequence(TITLE_KEY))
                 .create();
     }
@@ -72,27 +109,41 @@
     public void onClick(DialogInterface dialog, int which) {
         final Bundle args = getArguments();
         ComponentName name = args.getParcelable(NAME_KEY);
-        switch (which) {
-            case TOGGLE_PIN_INDEX:
-                SharedPreferences sp = ChooserActivity.getPinnedSharedPrefs(getContext());
-                final String key = name.flattenToString();
-                boolean currentVal = sp.getBoolean(name.flattenToString(), false);
-                if (currentVal) {
-                    sp.edit().remove(key).apply();
-                } else {
-                    sp.edit().putBoolean(key, true).apply();
-                }
-
-                // Force the chooser to requery and resort things
-                getActivity().recreate();
-                break;
-            case APP_INFO_INDEX:
-                Intent in = new Intent().setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
-                        .setData(Uri.fromParts("package", name.getPackageName(), null))
-                        .addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
-                startActivity(in);
-                break;
+        if (which == 0 || (mTargetInfos.size() > 0 && which < mTargetInfos.size())) {
+            if (mTargetInfos == null || mTargetInfos.size() == 0) {
+                pinComponent(name);
+            } else {
+                pinComponent(mTargetInfos.get(which).getResolvedComponentName());
+            }
+            // Force the chooser to requery and resort things
+            getActivity().recreate();
+        } else {
+            // Last item in dialog is App Info
+            Intent in = new Intent().setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
+                    .setData(Uri.fromParts("package", name.getPackageName(), null))
+                    .addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+            startActivity(in);
         }
         dismiss();
     }
+
+    private void pinComponent(ComponentName name) {
+        SharedPreferences sp = ChooserActivity.getPinnedSharedPrefs(getContext());
+        final String key = name.flattenToString();
+        boolean currentVal = sp.getBoolean(name.flattenToString(), false);
+        if (currentVal) {
+            sp.edit().remove(key).apply();
+        } else {
+            sp.edit().putBoolean(key, true).apply();
+        }
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        // Dismiss on config changed (eg: rotation)
+        // TODO: Maintain state on config change
+        super.onConfigurationChanged(newConfig);
+        dismiss();
+    }
+
 }
diff --git a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
index f92637c..86a9af3 100644
--- a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
+++ b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
@@ -91,6 +91,16 @@
         mResolveInfoPresentationGetter = resolveInfoPresentationGetter;
     }
 
+    DisplayResolveInfo(DisplayResolveInfo other) {
+        mSourceIntents.addAll(other.getAllSourceIntents());
+        mResolveInfo = other.mResolveInfo;
+        mDisplayLabel = other.mDisplayLabel;
+        mDisplayIcon = other.mDisplayIcon;
+        mExtendedInfo = other.mExtendedInfo;
+        mResolvedIntent = other.mResolvedIntent;
+        mResolveInfoPresentationGetter = other.mResolveInfoPresentationGetter;
+    }
+
     public ResolveInfo getResolveInfo() {
         return mResolveInfo;
     }
@@ -189,4 +199,5 @@
     public void setPinned(boolean pinned) {
         mPinned = pinned;
     }
+
 }
diff --git a/core/java/com/android/internal/app/chooser/MultiDisplayResolveInfo.java b/core/java/com/android/internal/app/chooser/MultiDisplayResolveInfo.java
new file mode 100644
index 0000000..4c52411
--- /dev/null
+++ b/core/java/com/android/internal/app/chooser/MultiDisplayResolveInfo.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2019 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.internal.app.chooser;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a "stack" of chooser targets for various activities within the same component.
+ */
+public class MultiDisplayResolveInfo extends DisplayResolveInfo {
+
+    List<DisplayResolveInfo> mTargetInfos = new ArrayList<>();
+    String mPackageName;
+    // We'll use this DRI for basic presentation info - eg icon, name.
+    final DisplayResolveInfo mBaseInfo;
+
+    /**
+     * @param firstInfo A representative DRI to use for the main icon, title, etc for this Info.
+     */
+    public MultiDisplayResolveInfo(String packageName, DisplayResolveInfo firstInfo) {
+        super(firstInfo);
+        mBaseInfo = firstInfo;
+        mTargetInfos.add(firstInfo);
+    }
+
+    /**
+     * Add another DisplayResolveInfo to the list included for this target.
+     */
+    public void addTarget(DisplayResolveInfo target) {
+        mTargetInfos.add(target);
+    }
+
+    /**
+     * List of all DisplayResolveInfos included in this target.
+     */
+    public List<DisplayResolveInfo> getTargets() {
+        return mTargetInfos;
+    }
+
+}
diff --git a/core/java/com/android/internal/infra/AndroidFuture.java b/core/java/com/android/internal/infra/AndroidFuture.java
index d78bd73..b250578 100644
--- a/core/java/com/android/internal/infra/AndroidFuture.java
+++ b/core/java/com/android/internal/infra/AndroidFuture.java
@@ -531,6 +531,12 @@
                     try {
                         AndroidFuture.this.complete((T) resultContainer.get());
                     } catch (Throwable t) {
+                        // If resultContainer was completed exceptionally, get() wraps the
+                        // underlying exception in an ExecutionException. Unwrap it now to avoid
+                        // double-layering ExecutionExceptions.
+                        if (t instanceof ExecutionException && t.getCause() != null) {
+                            t = t.getCause();
+                        }
                         completeExceptionally(t);
                     }
                 }
diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java
index 4165f20..4dac542 100644
--- a/core/java/com/android/internal/util/CollectionUtils.java
+++ b/core/java/com/android/internal/util/CollectionUtils.java
@@ -308,6 +308,17 @@
     }
 
     /**
+     * @see #add(List, Object)
+     */
+    public static @NonNull <K, V> Map<K, V> add(@Nullable Map<K, V> map, K key, V value) {
+        if (map == null || map == Collections.emptyMap()) {
+            map = new ArrayMap<>();
+        }
+        map.put(key, value);
+        return map;
+    }
+
+    /**
      * Similar to {@link List#remove}, but with support for list values of {@code null} and
      * {@link Collections#emptyList}
      */
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 7562bad..8a59c99 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -25,6 +25,7 @@
 import android.content.pm.PackageManager;
 import android.os.Build;
 import android.os.Environment;
+import android.os.FileUtils;
 import android.os.Process;
 import android.os.SystemProperties;
 import android.os.Trace;
@@ -228,7 +229,7 @@
      * Map of system pre-defined, uniquely named actors; keys are namespace,
      * value maps actor name to package name.
      */
-    private ArrayMap<String, ArrayMap<String, String>> mNamedActors = null;
+    private Map<String, Map<String, String>> mNamedActors = null;
 
     public static SystemConfig getInstance() {
         if (!isSystemProcess()) {
@@ -412,7 +413,7 @@
     }
 
     @NonNull
-    public Map<String, ? extends Map<String, String>> getNamedActors() {
+    public Map<String, Map<String, String>> getNamedActors() {
         return mNamedActors != null ? mNamedActors : Collections.emptyMap();
     }
 
@@ -498,6 +499,19 @@
                 Environment.getSystemExtDirectory(), "etc", "sysconfig"), ALLOW_ALL);
         readPermissions(Environment.buildPath(
                 Environment.getSystemExtDirectory(), "etc", "permissions"), ALLOW_ALL);
+
+        // Skip loading configuration from apex if it is not a system process.
+        if (!isSystemProcess()) {
+            return;
+        }
+        // Read configuration of libs from apex module.
+        // TODO: Use a solid way to filter apex module folders?
+        for (File f: FileUtils.listFilesOrEmpty(Environment.getApexDirectory())) {
+            if (f.isFile() || f.getPath().contains("@")) {
+                continue;
+            }
+            readPermissions(Environment.buildPath(f, "etc", "permissions"), ALLOW_LIBS);
+        }
     }
 
     @VisibleForTesting
@@ -1069,7 +1083,7 @@
                                 mNamedActors = new ArrayMap<>();
                             }
 
-                            ArrayMap<String, String> nameToPkgMap = mNamedActors.get(namespace);
+                            Map<String, String> nameToPkgMap = mNamedActors.get(namespace);
                             if (nameToPkgMap == null) {
                                 nameToPkgMap = new ArrayMap<>();
                                 mNamedActors.put(namespace, nameToPkgMap);
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d6d5c57..e7c3415 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3126,7 +3126,9 @@
 
          The path is assumed to be specified in display coordinates with pixel units and in
          the display's native orientation, with the origin of the coordinate system at the
-         center top of the display.
+         center top of the display. Optionally, you can append either `@left` or `@right` to the
+         end of the path string, in order to change the path origin to either the top left,
+         or top right of the display.
 
          To facilitate writing device-independent emulation overlays, the marker `@dp` can be
          appended after the path string to interpret coordinates in dp instead of px units.
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index de1b5ba..ab10738 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4946,8 +4946,12 @@
     <!-- Resolver target actions strings -->
     <!-- Pin this app to the top of the Sharesheet app list. [CHAR LIMIT=60]-->
     <string name="pin_target">Pin</string>
+    <!-- Pin this app to the top of the Sharesheet app list. [CHAR LIMIT=60]-->
+    <string name="pin_specific_target">Pin <xliff:g id="label" example="Tweet">%1$s</xliff:g></string>
     <!-- Un-pin this app in the Sharesheet, so that it is sorted normally. [CHAR LIMIT=60]-->
-    <string name="unpin_target">Unpin</string>
+    <string name="unpin_target">Unpin </string>
+    <!-- Un-pin this app in the Sharesheet, so that it is sorted normally. [CHAR LIMIT=60]-->
+    <string name="unpin_specific_target">Unpin <xliff:g id="label" example="Tweet">%1$s</xliff:g></string>
     <!-- View application info for a target. -->
     <string name="app_info">App info</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 011dc39..1631e0f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2958,6 +2958,8 @@
   <!-- Resolver target actions -->
   <java-symbol type="array" name="resolver_target_actions_pin" />
   <java-symbol type="array" name="resolver_target_actions_unpin" />
+  <java-symbol type="string" name="pin_specific_target" />
+  <java-symbol type="string" name="unpin_specific_target" />
 
   <java-symbol type="array" name="non_removable_euicc_slots" />
 
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index 1a48260..cce38f6 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -19,11 +19,9 @@
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
 import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
-import static android.view.WindowInsets.Type.navigationBars;
 import static android.view.WindowInsets.Type.systemBars;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.eq;
@@ -118,7 +116,7 @@
         consumers.put(ITYPE_NAVIGATION_BAR, navConsumer);
         mController = new InsetsAnimationControlImpl(consumers,
                 new Rect(0, 0, 500, 500), mInsetsState, mMockListener, systemBars(),
-                () -> mMockTransactionApplier, mMockController);
+                () -> mMockTransactionApplier, mMockController, 10 /* durationMs */);
     }
 
     @Test
@@ -131,7 +129,8 @@
 
     @Test
     public void testChangeInsets() {
-        mController.changeInsets(Insets.of(0, 30, 40, 0));
+        mController.setInsetsAndAlpha(Insets.of(0, 30, 40, 0), 1f /* alpha */,
+                0f /* fraction */);
         mController.applyChangeInsets(new InsetsState());
         assertEquals(Insets.of(0, 30, 40, 0), mController.getCurrentInsets());
 
@@ -150,24 +149,24 @@
     @Test
     public void testFinishing() {
         when(mMockController.getState()).thenReturn(mInsetsState);
-        mController.finish(navigationBars());
+        mController.finish(true /* shown */);
         mController.applyChangeInsets(mInsetsState);
-        assertFalse(mInsetsState.getSource(ITYPE_STATUS_BAR).isVisible());
+        assertTrue(mInsetsState.getSource(ITYPE_STATUS_BAR).isVisible());
         assertTrue(mInsetsState.getSource(ITYPE_NAVIGATION_BAR).isVisible());
-        assertEquals(Insets.of(0, 0, 100, 0), mController.getCurrentInsets());
-        verify(mMockController).notifyFinished(eq(mController), eq(navigationBars()));
+        assertEquals(Insets.of(0, 100, 100, 0), mController.getCurrentInsets());
+        verify(mMockController).notifyFinished(eq(mController), eq(true /* shown */));
     }
 
     @Test
     public void testCancelled() {
         mController.onCancelled();
         try {
-            mController.changeInsets(Insets.NONE);
+            mController.setInsetsAndAlpha(Insets.NONE, 1f /*alpha */, 0f /* fraction */);
             fail("Expected exception to be thrown");
         } catch (IllegalStateException ignored) {
         }
         verify(mMockListener).onCancelled();
-        mController.finish(navigationBars());
+        mController.finish(true /* shown */);
     }
 
     private void assertPosition(Matrix m, Rect original, Rect transformed) {
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index e4d8279..a89fc1e 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -123,7 +123,7 @@
 
         WindowInsetsAnimationControlListener mockListener =
                 mock(WindowInsetsAnimationControlListener.class);
-        mController.controlWindowInsetsAnimation(statusBars(), mockListener);
+        mController.controlWindowInsetsAnimation(statusBars(), 10 /* durationMs */, mockListener);
         verify(mockListener).onReady(any(), anyInt());
         mController.onControlsChanged(new InsetsSourceControl[0]);
         verify(mockListener).onCancelled();
@@ -135,7 +135,7 @@
         mController.getState().setDisplayFrame(new Rect(0, 0, 200, 200));
         WindowInsetsAnimationControlListener controlListener =
                 mock(WindowInsetsAnimationControlListener.class);
-        mController.controlWindowInsetsAnimation(0, controlListener);
+        mController.controlWindowInsetsAnimation(0, 0 /* durationMs */, controlListener);
         verify(controlListener).onCancelled();
         verify(controlListener, never()).onReady(any(), anyInt());
     }
@@ -331,12 +331,13 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             WindowInsetsAnimationControlListener mockListener =
                     mock(WindowInsetsAnimationControlListener.class);
-            mController.controlWindowInsetsAnimation(statusBars(), mockListener);
+            mController.controlWindowInsetsAnimation(statusBars(), 0 /* durationMs */,
+                    mockListener);
 
             ArgumentCaptor<WindowInsetsAnimationController> controllerCaptor =
                     ArgumentCaptor.forClass(WindowInsetsAnimationController.class);
             verify(mockListener).onReady(controllerCaptor.capture(), anyInt());
-            controllerCaptor.getValue().finish(0 /* shownTypes */);
+            controllerCaptor.getValue().finish(false /* shown */);
         });
         waitUntilNextFrame();
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
diff --git a/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java b/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java
index 9002c2c..ffc925f 100644
--- a/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java
+++ b/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java
@@ -111,7 +111,7 @@
     }
 
     @Test
-    public void testWriteToParcel_Exceptionally() throws Exception {
+    public void testWriteToParcel_Exception() throws Exception {
         Parcel parcel = Parcel.obtain();
         AndroidFuture<Integer> future1 = new AndroidFuture<>();
         future1.completeExceptionally(new UnsupportedOperationException());
@@ -123,4 +123,30 @@
                 expectThrows(ExecutionException.class, future2::get);
         assertThat(executionException.getCause()).isInstanceOf(UnsupportedOperationException.class);
     }
+
+    @Test
+    public void testWriteToParcel_Incomplete() throws Exception {
+        Parcel parcel = Parcel.obtain();
+        AndroidFuture<Integer> future1 = new AndroidFuture<>();
+        future1.writeToParcel(parcel, 0);
+
+        parcel.setDataPosition(0);
+        AndroidFuture future2 = AndroidFuture.CREATOR.createFromParcel(parcel);
+        future2.complete(5);
+        assertThat(future1.get()).isEqualTo(5);
+    }
+
+    @Test
+    public void testWriteToParcel_Incomplete_Exception() throws Exception {
+        Parcel parcel = Parcel.obtain();
+        AndroidFuture<Integer> future1 = new AndroidFuture<>();
+        future1.writeToParcel(parcel, 0);
+
+        parcel.setDataPosition(0);
+        AndroidFuture future2 = AndroidFuture.CREATOR.createFromParcel(parcel);
+        future2.completeExceptionally(new UnsupportedOperationException());
+        ExecutionException executionException =
+                expectThrows(ExecutionException.class, future1::get);
+        assertThat(executionException.getCause()).isInstanceOf(UnsupportedOperationException.class);
+    }
 }
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 322cbd7..e07edd4 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -145,7 +145,7 @@
         <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
         <permission name="android.permission.CHANGE_CONFIGURATION"/>
         <permission name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"/>
-        <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
+        <permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
         <permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
         <permission name="android.permission.DUMP"/>
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 572fa8c..048dee6 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -65,6 +65,9 @@
     /** Key prefix for VPN. */
     public static final String VPN = "VPN_";
 
+    /** Key prefix for platform VPNs. */
+    public static final String PLATFORM_VPN = "PLATFORM_VPN_";
+
     /** Key prefix for WIFI. */
     public static final String WIFI = "WIFI_";
 
diff --git a/libs/androidfw/LocaleDataTables.cpp b/libs/androidfw/LocaleDataTables.cpp
index c276a23..c462eb7 100644
--- a/libs/androidfw/LocaleDataTables.cpp
+++ b/libs/androidfw/LocaleDataTables.cpp
@@ -10,1439 +10,1466 @@
     /* 6  */ {'B', 'a', 's', 's'},
     /* 7  */ {'B', 'e', 'n', 'g'},
     /* 8  */ {'B', 'r', 'a', 'h'},
-    /* 9  */ {'C', 'a', 'n', 's'},
-    /* 10 */ {'C', 'a', 'r', 'i'},
-    /* 11 */ {'C', 'h', 'a', 'm'},
-    /* 12 */ {'C', 'h', 'e', 'r'},
-    /* 13 */ {'C', 'o', 'p', 't'},
-    /* 14 */ {'C', 'p', 'r', 't'},
-    /* 15 */ {'C', 'y', 'r', 'l'},
-    /* 16 */ {'D', 'e', 'v', 'a'},
-    /* 17 */ {'E', 'g', 'y', 'p'},
-    /* 18 */ {'E', 't', 'h', 'i'},
-    /* 19 */ {'G', 'e', 'o', 'r'},
-    /* 20 */ {'G', 'o', 't', 'h'},
-    /* 21 */ {'G', 'r', 'e', 'k'},
-    /* 22 */ {'G', 'u', 'j', 'r'},
-    /* 23 */ {'G', 'u', 'r', 'u'},
-    /* 24 */ {'H', 'a', 'n', 's'},
-    /* 25 */ {'H', 'a', 'n', 't'},
-    /* 26 */ {'H', 'a', 't', 'r'},
-    /* 27 */ {'H', 'e', 'b', 'r'},
-    /* 28 */ {'H', 'l', 'u', 'w'},
-    /* 29 */ {'H', 'm', 'n', 'g'},
-    /* 30 */ {'I', 't', 'a', 'l'},
-    /* 31 */ {'J', 'p', 'a', 'n'},
-    /* 32 */ {'K', 'a', 'l', 'i'},
-    /* 33 */ {'K', 'a', 'n', 'a'},
-    /* 34 */ {'K', 'h', 'a', 'r'},
-    /* 35 */ {'K', 'h', 'm', 'r'},
-    /* 36 */ {'K', 'n', 'd', 'a'},
-    /* 37 */ {'K', 'o', 'r', 'e'},
-    /* 38 */ {'L', 'a', 'n', 'a'},
-    /* 39 */ {'L', 'a', 'o', 'o'},
-    /* 40 */ {'L', 'a', 't', 'n'},
-    /* 41 */ {'L', 'e', 'p', 'c'},
-    /* 42 */ {'L', 'i', 'n', 'a'},
-    /* 43 */ {'L', 'i', 's', 'u'},
-    /* 44 */ {'L', 'y', 'c', 'i'},
-    /* 45 */ {'L', 'y', 'd', 'i'},
-    /* 46 */ {'M', 'a', 'n', 'd'},
-    /* 47 */ {'M', 'a', 'n', 'i'},
-    /* 48 */ {'M', 'e', 'r', 'c'},
-    /* 49 */ {'M', 'l', 'y', 'm'},
-    /* 50 */ {'M', 'o', 'n', 'g'},
-    /* 51 */ {'M', 'r', 'o', 'o'},
-    /* 52 */ {'M', 'y', 'm', 'r'},
-    /* 53 */ {'N', 'a', 'r', 'b'},
-    /* 54 */ {'N', 'k', 'o', 'o'},
-    /* 55 */ {'O', 'g', 'a', 'm'},
-    /* 56 */ {'O', 'r', 'k', 'h'},
-    /* 57 */ {'O', 'r', 'y', 'a'},
-    /* 58 */ {'O', 's', 'g', 'e'},
-    /* 59 */ {'P', 'a', 'u', 'c'},
-    /* 60 */ {'P', 'h', 'l', 'i'},
-    /* 61 */ {'P', 'h', 'n', 'x'},
-    /* 62 */ {'P', 'l', 'r', 'd'},
-    /* 63 */ {'P', 'r', 't', 'i'},
-    /* 64 */ {'R', 'u', 'n', 'r'},
-    /* 65 */ {'S', 'a', 'm', 'r'},
-    /* 66 */ {'S', 'a', 'r', 'b'},
-    /* 67 */ {'S', 'a', 'u', 'r'},
-    /* 68 */ {'S', 'g', 'n', 'w'},
-    /* 69 */ {'S', 'i', 'n', 'h'},
-    /* 70 */ {'S', 'o', 'r', 'a'},
-    /* 71 */ {'S', 'y', 'r', 'c'},
-    /* 72 */ {'T', 'a', 'l', 'e'},
-    /* 73 */ {'T', 'a', 'l', 'u'},
-    /* 74 */ {'T', 'a', 'm', 'l'},
-    /* 75 */ {'T', 'a', 'n', 'g'},
-    /* 76 */ {'T', 'a', 'v', 't'},
-    /* 77 */ {'T', 'e', 'l', 'u'},
-    /* 78 */ {'T', 'f', 'n', 'g'},
-    /* 79 */ {'T', 'h', 'a', 'a'},
-    /* 80 */ {'T', 'h', 'a', 'i'},
-    /* 81 */ {'T', 'i', 'b', 't'},
-    /* 82 */ {'U', 'g', 'a', 'r'},
-    /* 83 */ {'V', 'a', 'i', 'i'},
-    /* 84 */ {'X', 'p', 'e', 'o'},
-    /* 85 */ {'X', 's', 'u', 'x'},
-    /* 86 */ {'Y', 'i', 'i', 'i'},
-    /* 87 */ {'~', '~', '~', 'A'},
-    /* 88 */ {'~', '~', '~', 'B'},
+    /* 9  */ {'C', 'a', 'k', 'm'},
+    /* 10 */ {'C', 'a', 'n', 's'},
+    /* 11 */ {'C', 'a', 'r', 'i'},
+    /* 12 */ {'C', 'h', 'a', 'm'},
+    /* 13 */ {'C', 'h', 'e', 'r'},
+    /* 14 */ {'C', 'o', 'p', 't'},
+    /* 15 */ {'C', 'p', 'r', 't'},
+    /* 16 */ {'C', 'y', 'r', 'l'},
+    /* 17 */ {'D', 'e', 'v', 'a'},
+    /* 18 */ {'E', 'g', 'y', 'p'},
+    /* 19 */ {'E', 't', 'h', 'i'},
+    /* 20 */ {'G', 'e', 'o', 'r'},
+    /* 21 */ {'G', 'o', 'n', 'g'},
+    /* 22 */ {'G', 'o', 'n', 'm'},
+    /* 23 */ {'G', 'o', 't', 'h'},
+    /* 24 */ {'G', 'r', 'e', 'k'},
+    /* 25 */ {'G', 'u', 'j', 'r'},
+    /* 26 */ {'G', 'u', 'r', 'u'},
+    /* 27 */ {'H', 'a', 'n', 's'},
+    /* 28 */ {'H', 'a', 'n', 't'},
+    /* 29 */ {'H', 'a', 't', 'r'},
+    /* 30 */ {'H', 'e', 'b', 'r'},
+    /* 31 */ {'H', 'l', 'u', 'w'},
+    /* 32 */ {'H', 'm', 'n', 'g'},
+    /* 33 */ {'H', 'm', 'n', 'p'},
+    /* 34 */ {'I', 't', 'a', 'l'},
+    /* 35 */ {'J', 'p', 'a', 'n'},
+    /* 36 */ {'K', 'a', 'l', 'i'},
+    /* 37 */ {'K', 'a', 'n', 'a'},
+    /* 38 */ {'K', 'h', 'a', 'r'},
+    /* 39 */ {'K', 'h', 'm', 'r'},
+    /* 40 */ {'K', 'n', 'd', 'a'},
+    /* 41 */ {'K', 'o', 'r', 'e'},
+    /* 42 */ {'L', 'a', 'n', 'a'},
+    /* 43 */ {'L', 'a', 'o', 'o'},
+    /* 44 */ {'L', 'a', 't', 'n'},
+    /* 45 */ {'L', 'e', 'p', 'c'},
+    /* 46 */ {'L', 'i', 'n', 'a'},
+    /* 47 */ {'L', 'i', 's', 'u'},
+    /* 48 */ {'L', 'y', 'c', 'i'},
+    /* 49 */ {'L', 'y', 'd', 'i'},
+    /* 50 */ {'M', 'a', 'n', 'd'},
+    /* 51 */ {'M', 'a', 'n', 'i'},
+    /* 52 */ {'M', 'e', 'r', 'c'},
+    /* 53 */ {'M', 'l', 'y', 'm'},
+    /* 54 */ {'M', 'o', 'n', 'g'},
+    /* 55 */ {'M', 'r', 'o', 'o'},
+    /* 56 */ {'M', 'y', 'm', 'r'},
+    /* 57 */ {'N', 'a', 'r', 'b'},
+    /* 58 */ {'N', 'k', 'o', 'o'},
+    /* 59 */ {'N', 's', 'h', 'u'},
+    /* 60 */ {'O', 'g', 'a', 'm'},
+    /* 61 */ {'O', 'r', 'k', 'h'},
+    /* 62 */ {'O', 'r', 'y', 'a'},
+    /* 63 */ {'O', 's', 'g', 'e'},
+    /* 64 */ {'P', 'a', 'u', 'c'},
+    /* 65 */ {'P', 'h', 'l', 'i'},
+    /* 66 */ {'P', 'h', 'n', 'x'},
+    /* 67 */ {'P', 'l', 'r', 'd'},
+    /* 68 */ {'P', 'r', 't', 'i'},
+    /* 69 */ {'R', 'u', 'n', 'r'},
+    /* 70 */ {'S', 'a', 'm', 'r'},
+    /* 71 */ {'S', 'a', 'r', 'b'},
+    /* 72 */ {'S', 'a', 'u', 'r'},
+    /* 73 */ {'S', 'g', 'n', 'w'},
+    /* 74 */ {'S', 'i', 'n', 'h'},
+    /* 75 */ {'S', 'o', 'g', 'd'},
+    /* 76 */ {'S', 'o', 'r', 'a'},
+    /* 77 */ {'S', 'o', 'y', 'o'},
+    /* 78 */ {'S', 'y', 'r', 'c'},
+    /* 79 */ {'T', 'a', 'l', 'e'},
+    /* 80 */ {'T', 'a', 'l', 'u'},
+    /* 81 */ {'T', 'a', 'm', 'l'},
+    /* 82 */ {'T', 'a', 'n', 'g'},
+    /* 83 */ {'T', 'a', 'v', 't'},
+    /* 84 */ {'T', 'e', 'l', 'u'},
+    /* 85 */ {'T', 'f', 'n', 'g'},
+    /* 86 */ {'T', 'h', 'a', 'a'},
+    /* 87 */ {'T', 'h', 'a', 'i'},
+    /* 88 */ {'T', 'i', 'b', 't'},
+    /* 89 */ {'U', 'g', 'a', 'r'},
+    /* 90 */ {'V', 'a', 'i', 'i'},
+    /* 91 */ {'W', 'c', 'h', 'o'},
+    /* 92 */ {'X', 'p', 'e', 'o'},
+    /* 93 */ {'X', 's', 'u', 'x'},
+    /* 94 */ {'Y', 'i', 'i', 'i'},
+    /* 95 */ {'~', '~', '~', 'A'},
+    /* 96 */ {'~', '~', '~', 'B'},
 };
 
 
 const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
-    {0x61610000u, 40u}, // aa -> Latn
-    {0xA0000000u, 40u}, // aai -> Latn
-    {0xA8000000u, 40u}, // aak -> Latn
-    {0xD0000000u, 40u}, // aau -> Latn
-    {0x61620000u, 15u}, // ab -> Cyrl
-    {0xA0200000u, 40u}, // abi -> Latn
-    {0xC4200000u, 40u}, // abr -> Latn
-    {0xCC200000u, 40u}, // abt -> Latn
-    {0xE0200000u, 40u}, // aby -> Latn
-    {0x8C400000u, 40u}, // acd -> Latn
-    {0x90400000u, 40u}, // ace -> Latn
-    {0x9C400000u, 40u}, // ach -> Latn
-    {0x80600000u, 40u}, // ada -> Latn
-    {0x90600000u, 40u}, // ade -> Latn
-    {0xA4600000u, 40u}, // adj -> Latn
-    {0xE0600000u, 15u}, // ady -> Cyrl
-    {0xE4600000u, 40u}, // adz -> Latn
+    {0x61610000u, 44u}, // aa -> Latn
+    {0xA0000000u, 44u}, // aai -> Latn
+    {0xA8000000u, 44u}, // aak -> Latn
+    {0xD0000000u, 44u}, // aau -> Latn
+    {0x61620000u, 16u}, // ab -> Cyrl
+    {0xA0200000u, 44u}, // abi -> Latn
+    {0xC0200000u, 16u}, // abq -> Cyrl
+    {0xC4200000u, 44u}, // abr -> Latn
+    {0xCC200000u, 44u}, // abt -> Latn
+    {0xE0200000u, 44u}, // aby -> Latn
+    {0x8C400000u, 44u}, // acd -> Latn
+    {0x90400000u, 44u}, // ace -> Latn
+    {0x9C400000u, 44u}, // ach -> Latn
+    {0x80600000u, 44u}, // ada -> Latn
+    {0x90600000u, 44u}, // ade -> Latn
+    {0xA4600000u, 44u}, // adj -> Latn
+    {0xE0600000u, 16u}, // ady -> Cyrl
+    {0xE4600000u, 44u}, // adz -> Latn
     {0x61650000u,  4u}, // ae -> Avst
     {0x84800000u,  1u}, // aeb -> Arab
-    {0xE0800000u, 40u}, // aey -> Latn
-    {0x61660000u, 40u}, // af -> Latn
-    {0x88C00000u, 40u}, // agc -> Latn
-    {0x8CC00000u, 40u}, // agd -> Latn
-    {0x98C00000u, 40u}, // agg -> Latn
-    {0xB0C00000u, 40u}, // agm -> Latn
-    {0xB8C00000u, 40u}, // ago -> Latn
-    {0xC0C00000u, 40u}, // agq -> Latn
-    {0x80E00000u, 40u}, // aha -> Latn
-    {0xACE00000u, 40u}, // ahl -> Latn
+    {0xE0800000u, 44u}, // aey -> Latn
+    {0x61660000u, 44u}, // af -> Latn
+    {0x88C00000u, 44u}, // agc -> Latn
+    {0x8CC00000u, 44u}, // agd -> Latn
+    {0x98C00000u, 44u}, // agg -> Latn
+    {0xB0C00000u, 44u}, // agm -> Latn
+    {0xB8C00000u, 44u}, // ago -> Latn
+    {0xC0C00000u, 44u}, // agq -> Latn
+    {0x80E00000u, 44u}, // aha -> Latn
+    {0xACE00000u, 44u}, // ahl -> Latn
     {0xB8E00000u,  0u}, // aho -> Ahom
-    {0x99200000u, 40u}, // ajg -> Latn
-    {0x616B0000u, 40u}, // ak -> Latn
-    {0xA9400000u, 85u}, // akk -> Xsux
-    {0x81600000u, 40u}, // ala -> Latn
-    {0xA1600000u, 40u}, // ali -> Latn
-    {0xB5600000u, 40u}, // aln -> Latn
-    {0xCD600000u, 15u}, // alt -> Cyrl
-    {0x616D0000u, 18u}, // am -> Ethi
-    {0xB1800000u, 40u}, // amm -> Latn
-    {0xB5800000u, 40u}, // amn -> Latn
-    {0xB9800000u, 40u}, // amo -> Latn
-    {0xBD800000u, 40u}, // amp -> Latn
-    {0x89A00000u, 40u}, // anc -> Latn
-    {0xA9A00000u, 40u}, // ank -> Latn
-    {0xB5A00000u, 40u}, // ann -> Latn
-    {0xE1A00000u, 40u}, // any -> Latn
-    {0xA5C00000u, 40u}, // aoj -> Latn
-    {0xB1C00000u, 40u}, // aom -> Latn
-    {0xE5C00000u, 40u}, // aoz -> Latn
+    {0x99200000u, 44u}, // ajg -> Latn
+    {0x616B0000u, 44u}, // ak -> Latn
+    {0xA9400000u, 93u}, // akk -> Xsux
+    {0x81600000u, 44u}, // ala -> Latn
+    {0xA1600000u, 44u}, // ali -> Latn
+    {0xB5600000u, 44u}, // aln -> Latn
+    {0xCD600000u, 16u}, // alt -> Cyrl
+    {0x616D0000u, 19u}, // am -> Ethi
+    {0xB1800000u, 44u}, // amm -> Latn
+    {0xB5800000u, 44u}, // amn -> Latn
+    {0xB9800000u, 44u}, // amo -> Latn
+    {0xBD800000u, 44u}, // amp -> Latn
+    {0x89A00000u, 44u}, // anc -> Latn
+    {0xA9A00000u, 44u}, // ank -> Latn
+    {0xB5A00000u, 44u}, // ann -> Latn
+    {0xE1A00000u, 44u}, // any -> Latn
+    {0xA5C00000u, 44u}, // aoj -> Latn
+    {0xB1C00000u, 44u}, // aom -> Latn
+    {0xE5C00000u, 44u}, // aoz -> Latn
     {0x89E00000u,  1u}, // apc -> Arab
     {0x8DE00000u,  1u}, // apd -> Arab
-    {0x91E00000u, 40u}, // ape -> Latn
-    {0xC5E00000u, 40u}, // apr -> Latn
-    {0xC9E00000u, 40u}, // aps -> Latn
-    {0xE5E00000u, 40u}, // apz -> Latn
+    {0x91E00000u, 44u}, // ape -> Latn
+    {0xC5E00000u, 44u}, // apr -> Latn
+    {0xC9E00000u, 44u}, // aps -> Latn
+    {0xE5E00000u, 44u}, // apz -> Latn
     {0x61720000u,  1u}, // ar -> Arab
-    {0x61725842u, 88u}, // ar-XB -> ~~~B
+    {0x61725842u, 96u}, // ar-XB -> ~~~B
     {0x8A200000u,  2u}, // arc -> Armi
-    {0x9E200000u, 40u}, // arh -> Latn
-    {0xB6200000u, 40u}, // arn -> Latn
-    {0xBA200000u, 40u}, // aro -> Latn
+    {0x9E200000u, 44u}, // arh -> Latn
+    {0xB6200000u, 44u}, // arn -> Latn
+    {0xBA200000u, 44u}, // aro -> Latn
     {0xC2200000u,  1u}, // arq -> Arab
     {0xE2200000u,  1u}, // ary -> Arab
     {0xE6200000u,  1u}, // arz -> Arab
     {0x61730000u,  7u}, // as -> Beng
-    {0x82400000u, 40u}, // asa -> Latn
-    {0x92400000u, 68u}, // ase -> Sgnw
-    {0x9A400000u, 40u}, // asg -> Latn
-    {0xBA400000u, 40u}, // aso -> Latn
-    {0xCE400000u, 40u}, // ast -> Latn
-    {0x82600000u, 40u}, // ata -> Latn
-    {0x9A600000u, 40u}, // atg -> Latn
-    {0xA6600000u, 40u}, // atj -> Latn
-    {0xE2800000u, 40u}, // auy -> Latn
-    {0x61760000u, 15u}, // av -> Cyrl
+    {0x82400000u, 44u}, // asa -> Latn
+    {0x92400000u, 73u}, // ase -> Sgnw
+    {0x9A400000u, 44u}, // asg -> Latn
+    {0xBA400000u, 44u}, // aso -> Latn
+    {0xCE400000u, 44u}, // ast -> Latn
+    {0x82600000u, 44u}, // ata -> Latn
+    {0x9A600000u, 44u}, // atg -> Latn
+    {0xA6600000u, 44u}, // atj -> Latn
+    {0xE2800000u, 44u}, // auy -> Latn
+    {0x61760000u, 16u}, // av -> Cyrl
     {0xAEA00000u,  1u}, // avl -> Arab
-    {0xB6A00000u, 40u}, // avn -> Latn
-    {0xCEA00000u, 40u}, // avt -> Latn
-    {0xD2A00000u, 40u}, // avu -> Latn
-    {0x82C00000u, 16u}, // awa -> Deva
-    {0x86C00000u, 40u}, // awb -> Latn
-    {0xBAC00000u, 40u}, // awo -> Latn
-    {0xDEC00000u, 40u}, // awx -> Latn
-    {0x61790000u, 40u}, // ay -> Latn
-    {0x87000000u, 40u}, // ayb -> Latn
-    {0x617A0000u, 40u}, // az -> Latn
+    {0xB6A00000u, 44u}, // avn -> Latn
+    {0xCEA00000u, 44u}, // avt -> Latn
+    {0xD2A00000u, 44u}, // avu -> Latn
+    {0x82C00000u, 17u}, // awa -> Deva
+    {0x86C00000u, 44u}, // awb -> Latn
+    {0xBAC00000u, 44u}, // awo -> Latn
+    {0xDEC00000u, 44u}, // awx -> Latn
+    {0x61790000u, 44u}, // ay -> Latn
+    {0x87000000u, 44u}, // ayb -> Latn
+    {0x617A0000u, 44u}, // az -> Latn
     {0x617A4951u,  1u}, // az-IQ -> Arab
     {0x617A4952u,  1u}, // az-IR -> Arab
-    {0x617A5255u, 15u}, // az-RU -> Cyrl
-    {0x62610000u, 15u}, // ba -> Cyrl
+    {0x617A5255u, 16u}, // az-RU -> Cyrl
+    {0x62610000u, 16u}, // ba -> Cyrl
     {0xAC010000u,  1u}, // bal -> Arab
-    {0xB4010000u, 40u}, // ban -> Latn
-    {0xBC010000u, 16u}, // bap -> Deva
-    {0xC4010000u, 40u}, // bar -> Latn
-    {0xC8010000u, 40u}, // bas -> Latn
-    {0xD4010000u, 40u}, // bav -> Latn
+    {0xB4010000u, 44u}, // ban -> Latn
+    {0xBC010000u, 17u}, // bap -> Deva
+    {0xC4010000u, 44u}, // bar -> Latn
+    {0xC8010000u, 44u}, // bas -> Latn
+    {0xD4010000u, 44u}, // bav -> Latn
     {0xDC010000u,  5u}, // bax -> Bamu
-    {0x80210000u, 40u}, // bba -> Latn
-    {0x84210000u, 40u}, // bbb -> Latn
-    {0x88210000u, 40u}, // bbc -> Latn
-    {0x8C210000u, 40u}, // bbd -> Latn
-    {0xA4210000u, 40u}, // bbj -> Latn
-    {0xBC210000u, 40u}, // bbp -> Latn
-    {0xC4210000u, 40u}, // bbr -> Latn
-    {0x94410000u, 40u}, // bcf -> Latn
-    {0x9C410000u, 40u}, // bch -> Latn
-    {0xA0410000u, 40u}, // bci -> Latn
-    {0xB0410000u, 40u}, // bcm -> Latn
-    {0xB4410000u, 40u}, // bcn -> Latn
-    {0xB8410000u, 40u}, // bco -> Latn
-    {0xC0410000u, 18u}, // bcq -> Ethi
-    {0xD0410000u, 40u}, // bcu -> Latn
-    {0x8C610000u, 40u}, // bdd -> Latn
-    {0x62650000u, 15u}, // be -> Cyrl
-    {0x94810000u, 40u}, // bef -> Latn
-    {0x9C810000u, 40u}, // beh -> Latn
+    {0x80210000u, 44u}, // bba -> Latn
+    {0x84210000u, 44u}, // bbb -> Latn
+    {0x88210000u, 44u}, // bbc -> Latn
+    {0x8C210000u, 44u}, // bbd -> Latn
+    {0xA4210000u, 44u}, // bbj -> Latn
+    {0xBC210000u, 44u}, // bbp -> Latn
+    {0xC4210000u, 44u}, // bbr -> Latn
+    {0x94410000u, 44u}, // bcf -> Latn
+    {0x9C410000u, 44u}, // bch -> Latn
+    {0xA0410000u, 44u}, // bci -> Latn
+    {0xB0410000u, 44u}, // bcm -> Latn
+    {0xB4410000u, 44u}, // bcn -> Latn
+    {0xB8410000u, 44u}, // bco -> Latn
+    {0xC0410000u, 19u}, // bcq -> Ethi
+    {0xD0410000u, 44u}, // bcu -> Latn
+    {0x8C610000u, 44u}, // bdd -> Latn
+    {0x62650000u, 16u}, // be -> Cyrl
+    {0x94810000u, 44u}, // bef -> Latn
+    {0x9C810000u, 44u}, // beh -> Latn
     {0xA4810000u,  1u}, // bej -> Arab
-    {0xB0810000u, 40u}, // bem -> Latn
-    {0xCC810000u, 40u}, // bet -> Latn
-    {0xD8810000u, 40u}, // bew -> Latn
-    {0xDC810000u, 40u}, // bex -> Latn
-    {0xE4810000u, 40u}, // bez -> Latn
-    {0x8CA10000u, 40u}, // bfd -> Latn
-    {0xC0A10000u, 74u}, // bfq -> Taml
+    {0xB0810000u, 44u}, // bem -> Latn
+    {0xCC810000u, 44u}, // bet -> Latn
+    {0xD8810000u, 44u}, // bew -> Latn
+    {0xDC810000u, 44u}, // bex -> Latn
+    {0xE4810000u, 44u}, // bez -> Latn
+    {0x8CA10000u, 44u}, // bfd -> Latn
+    {0xC0A10000u, 81u}, // bfq -> Taml
     {0xCCA10000u,  1u}, // bft -> Arab
-    {0xE0A10000u, 16u}, // bfy -> Deva
-    {0x62670000u, 15u}, // bg -> Cyrl
-    {0x88C10000u, 16u}, // bgc -> Deva
+    {0xE0A10000u, 17u}, // bfy -> Deva
+    {0x62670000u, 16u}, // bg -> Cyrl
+    {0x88C10000u, 17u}, // bgc -> Deva
     {0xB4C10000u,  1u}, // bgn -> Arab
-    {0xDCC10000u, 21u}, // bgx -> Grek
-    {0x84E10000u, 16u}, // bhb -> Deva
-    {0x98E10000u, 40u}, // bhg -> Latn
-    {0xA0E10000u, 16u}, // bhi -> Deva
-    {0xA8E10000u, 40u}, // bhk -> Latn
-    {0xACE10000u, 40u}, // bhl -> Latn
-    {0xB8E10000u, 16u}, // bho -> Deva
-    {0xE0E10000u, 40u}, // bhy -> Latn
-    {0x62690000u, 40u}, // bi -> Latn
-    {0x85010000u, 40u}, // bib -> Latn
-    {0x99010000u, 40u}, // big -> Latn
-    {0xA9010000u, 40u}, // bik -> Latn
-    {0xB1010000u, 40u}, // bim -> Latn
-    {0xB5010000u, 40u}, // bin -> Latn
-    {0xB9010000u, 40u}, // bio -> Latn
-    {0xC1010000u, 40u}, // biq -> Latn
-    {0x9D210000u, 40u}, // bjh -> Latn
-    {0xA1210000u, 18u}, // bji -> Ethi
-    {0xA5210000u, 16u}, // bjj -> Deva
-    {0xB5210000u, 40u}, // bjn -> Latn
-    {0xB9210000u, 40u}, // bjo -> Latn
-    {0xC5210000u, 40u}, // bjr -> Latn
-    {0xE5210000u, 40u}, // bjz -> Latn
-    {0x89410000u, 40u}, // bkc -> Latn
-    {0xB1410000u, 40u}, // bkm -> Latn
-    {0xC1410000u, 40u}, // bkq -> Latn
-    {0xD1410000u, 40u}, // bku -> Latn
-    {0xD5410000u, 40u}, // bkv -> Latn
-    {0xCD610000u, 76u}, // blt -> Tavt
-    {0x626D0000u, 40u}, // bm -> Latn
-    {0x9D810000u, 40u}, // bmh -> Latn
-    {0xA9810000u, 40u}, // bmk -> Latn
-    {0xC1810000u, 40u}, // bmq -> Latn
-    {0xD1810000u, 40u}, // bmu -> Latn
+    {0xDCC10000u, 24u}, // bgx -> Grek
+    {0x84E10000u, 17u}, // bhb -> Deva
+    {0x98E10000u, 44u}, // bhg -> Latn
+    {0xA0E10000u, 17u}, // bhi -> Deva
+    {0xA8E10000u, 44u}, // bhk -> Latn
+    {0xACE10000u, 44u}, // bhl -> Latn
+    {0xB8E10000u, 17u}, // bho -> Deva
+    {0xE0E10000u, 44u}, // bhy -> Latn
+    {0x62690000u, 44u}, // bi -> Latn
+    {0x85010000u, 44u}, // bib -> Latn
+    {0x99010000u, 44u}, // big -> Latn
+    {0xA9010000u, 44u}, // bik -> Latn
+    {0xB1010000u, 44u}, // bim -> Latn
+    {0xB5010000u, 44u}, // bin -> Latn
+    {0xB9010000u, 44u}, // bio -> Latn
+    {0xC1010000u, 44u}, // biq -> Latn
+    {0x9D210000u, 44u}, // bjh -> Latn
+    {0xA1210000u, 19u}, // bji -> Ethi
+    {0xA5210000u, 17u}, // bjj -> Deva
+    {0xB5210000u, 44u}, // bjn -> Latn
+    {0xB9210000u, 44u}, // bjo -> Latn
+    {0xC5210000u, 44u}, // bjr -> Latn
+    {0xCD210000u, 44u}, // bjt -> Latn
+    {0xE5210000u, 44u}, // bjz -> Latn
+    {0x89410000u, 44u}, // bkc -> Latn
+    {0xB1410000u, 44u}, // bkm -> Latn
+    {0xC1410000u, 44u}, // bkq -> Latn
+    {0xD1410000u, 44u}, // bku -> Latn
+    {0xD5410000u, 44u}, // bkv -> Latn
+    {0xCD610000u, 83u}, // blt -> Tavt
+    {0x626D0000u, 44u}, // bm -> Latn
+    {0x9D810000u, 44u}, // bmh -> Latn
+    {0xA9810000u, 44u}, // bmk -> Latn
+    {0xC1810000u, 44u}, // bmq -> Latn
+    {0xD1810000u, 44u}, // bmu -> Latn
     {0x626E0000u,  7u}, // bn -> Beng
-    {0x99A10000u, 40u}, // bng -> Latn
-    {0xB1A10000u, 40u}, // bnm -> Latn
-    {0xBDA10000u, 40u}, // bnp -> Latn
-    {0x626F0000u, 81u}, // bo -> Tibt
-    {0xA5C10000u, 40u}, // boj -> Latn
-    {0xB1C10000u, 40u}, // bom -> Latn
-    {0xB5C10000u, 40u}, // bon -> Latn
+    {0x99A10000u, 44u}, // bng -> Latn
+    {0xB1A10000u, 44u}, // bnm -> Latn
+    {0xBDA10000u, 44u}, // bnp -> Latn
+    {0x626F0000u, 88u}, // bo -> Tibt
+    {0xA5C10000u, 44u}, // boj -> Latn
+    {0xB1C10000u, 44u}, // bom -> Latn
+    {0xB5C10000u, 44u}, // bon -> Latn
     {0xE1E10000u,  7u}, // bpy -> Beng
-    {0x8A010000u, 40u}, // bqc -> Latn
+    {0x8A010000u, 44u}, // bqc -> Latn
     {0xA2010000u,  1u}, // bqi -> Arab
-    {0xBE010000u, 40u}, // bqp -> Latn
-    {0xD6010000u, 40u}, // bqv -> Latn
-    {0x62720000u, 40u}, // br -> Latn
-    {0x82210000u, 16u}, // bra -> Deva
+    {0xBE010000u, 44u}, // bqp -> Latn
+    {0xD6010000u, 44u}, // bqv -> Latn
+    {0x62720000u, 44u}, // br -> Latn
+    {0x82210000u, 17u}, // bra -> Deva
     {0x9E210000u,  1u}, // brh -> Arab
-    {0xDE210000u, 16u}, // brx -> Deva
-    {0xE6210000u, 40u}, // brz -> Latn
-    {0x62730000u, 40u}, // bs -> Latn
-    {0xA6410000u, 40u}, // bsj -> Latn
+    {0xDE210000u, 17u}, // brx -> Deva
+    {0xE6210000u, 44u}, // brz -> Latn
+    {0x62730000u, 44u}, // bs -> Latn
+    {0xA6410000u, 44u}, // bsj -> Latn
     {0xC2410000u,  6u}, // bsq -> Bass
-    {0xCA410000u, 40u}, // bss -> Latn
-    {0xCE410000u, 18u}, // bst -> Ethi
-    {0xBA610000u, 40u}, // bto -> Latn
-    {0xCE610000u, 40u}, // btt -> Latn
-    {0xD6610000u, 16u}, // btv -> Deva
-    {0x82810000u, 15u}, // bua -> Cyrl
-    {0x8A810000u, 40u}, // buc -> Latn
-    {0x8E810000u, 40u}, // bud -> Latn
-    {0x9A810000u, 40u}, // bug -> Latn
-    {0xAA810000u, 40u}, // buk -> Latn
-    {0xB2810000u, 40u}, // bum -> Latn
-    {0xBA810000u, 40u}, // buo -> Latn
-    {0xCA810000u, 40u}, // bus -> Latn
-    {0xD2810000u, 40u}, // buu -> Latn
-    {0x86A10000u, 40u}, // bvb -> Latn
-    {0x8EC10000u, 40u}, // bwd -> Latn
-    {0xC6C10000u, 40u}, // bwr -> Latn
-    {0x9EE10000u, 40u}, // bxh -> Latn
-    {0x93010000u, 40u}, // bye -> Latn
-    {0xB7010000u, 18u}, // byn -> Ethi
-    {0xC7010000u, 40u}, // byr -> Latn
-    {0xCB010000u, 40u}, // bys -> Latn
-    {0xD7010000u, 40u}, // byv -> Latn
-    {0xDF010000u, 40u}, // byx -> Latn
-    {0x83210000u, 40u}, // bza -> Latn
-    {0x93210000u, 40u}, // bze -> Latn
-    {0x97210000u, 40u}, // bzf -> Latn
-    {0x9F210000u, 40u}, // bzh -> Latn
-    {0xDB210000u, 40u}, // bzw -> Latn
-    {0x63610000u, 40u}, // ca -> Latn
-    {0xB4020000u, 40u}, // can -> Latn
-    {0xA4220000u, 40u}, // cbj -> Latn
-    {0x9C420000u, 40u}, // cch -> Latn
-    {0xBC420000u,  7u}, // ccp -> Beng
-    {0x63650000u, 15u}, // ce -> Cyrl
-    {0x84820000u, 40u}, // ceb -> Latn
-    {0x80A20000u, 40u}, // cfa -> Latn
-    {0x98C20000u, 40u}, // cgg -> Latn
-    {0x63680000u, 40u}, // ch -> Latn
-    {0xA8E20000u, 40u}, // chk -> Latn
-    {0xB0E20000u, 15u}, // chm -> Cyrl
-    {0xB8E20000u, 40u}, // cho -> Latn
-    {0xBCE20000u, 40u}, // chp -> Latn
-    {0xC4E20000u, 12u}, // chr -> Cher
+    {0xCA410000u, 44u}, // bss -> Latn
+    {0xCE410000u, 19u}, // bst -> Ethi
+    {0xBA610000u, 44u}, // bto -> Latn
+    {0xCE610000u, 44u}, // btt -> Latn
+    {0xD6610000u, 17u}, // btv -> Deva
+    {0x82810000u, 16u}, // bua -> Cyrl
+    {0x8A810000u, 44u}, // buc -> Latn
+    {0x8E810000u, 44u}, // bud -> Latn
+    {0x9A810000u, 44u}, // bug -> Latn
+    {0xAA810000u, 44u}, // buk -> Latn
+    {0xB2810000u, 44u}, // bum -> Latn
+    {0xBA810000u, 44u}, // buo -> Latn
+    {0xCA810000u, 44u}, // bus -> Latn
+    {0xD2810000u, 44u}, // buu -> Latn
+    {0x86A10000u, 44u}, // bvb -> Latn
+    {0x8EC10000u, 44u}, // bwd -> Latn
+    {0xC6C10000u, 44u}, // bwr -> Latn
+    {0x9EE10000u, 44u}, // bxh -> Latn
+    {0x93010000u, 44u}, // bye -> Latn
+    {0xB7010000u, 19u}, // byn -> Ethi
+    {0xC7010000u, 44u}, // byr -> Latn
+    {0xCB010000u, 44u}, // bys -> Latn
+    {0xD7010000u, 44u}, // byv -> Latn
+    {0xDF010000u, 44u}, // byx -> Latn
+    {0x83210000u, 44u}, // bza -> Latn
+    {0x93210000u, 44u}, // bze -> Latn
+    {0x97210000u, 44u}, // bzf -> Latn
+    {0x9F210000u, 44u}, // bzh -> Latn
+    {0xDB210000u, 44u}, // bzw -> Latn
+    {0x63610000u, 44u}, // ca -> Latn
+    {0xB4020000u, 44u}, // can -> Latn
+    {0xA4220000u, 44u}, // cbj -> Latn
+    {0x9C420000u, 44u}, // cch -> Latn
+    {0xBC420000u,  9u}, // ccp -> Cakm
+    {0x63650000u, 16u}, // ce -> Cyrl
+    {0x84820000u, 44u}, // ceb -> Latn
+    {0x80A20000u, 44u}, // cfa -> Latn
+    {0x98C20000u, 44u}, // cgg -> Latn
+    {0x63680000u, 44u}, // ch -> Latn
+    {0xA8E20000u, 44u}, // chk -> Latn
+    {0xB0E20000u, 16u}, // chm -> Cyrl
+    {0xB8E20000u, 44u}, // cho -> Latn
+    {0xBCE20000u, 44u}, // chp -> Latn
+    {0xC4E20000u, 13u}, // chr -> Cher
     {0x81220000u,  1u}, // cja -> Arab
-    {0xB1220000u, 11u}, // cjm -> Cham
-    {0xD5220000u, 40u}, // cjv -> Latn
+    {0xB1220000u, 12u}, // cjm -> Cham
+    {0xD5220000u, 44u}, // cjv -> Latn
     {0x85420000u,  1u}, // ckb -> Arab
-    {0xAD420000u, 40u}, // ckl -> Latn
-    {0xB9420000u, 40u}, // cko -> Latn
-    {0xE1420000u, 40u}, // cky -> Latn
-    {0x81620000u, 40u}, // cla -> Latn
-    {0x91820000u, 40u}, // cme -> Latn
-    {0x636F0000u, 40u}, // co -> Latn
-    {0xBDC20000u, 13u}, // cop -> Copt
-    {0xC9E20000u, 40u}, // cps -> Latn
-    {0x63720000u,  9u}, // cr -> Cans
-    {0xA6220000u,  9u}, // crj -> Cans
-    {0xAA220000u,  9u}, // crk -> Cans
-    {0xAE220000u,  9u}, // crl -> Cans
-    {0xB2220000u,  9u}, // crm -> Cans
-    {0xCA220000u, 40u}, // crs -> Latn
-    {0x63730000u, 40u}, // cs -> Latn
-    {0x86420000u, 40u}, // csb -> Latn
-    {0xDA420000u,  9u}, // csw -> Cans
-    {0x8E620000u, 59u}, // ctd -> Pauc
-    {0x63750000u, 15u}, // cu -> Cyrl
-    {0x63760000u, 15u}, // cv -> Cyrl
-    {0x63790000u, 40u}, // cy -> Latn
-    {0x64610000u, 40u}, // da -> Latn
-    {0x8C030000u, 40u}, // dad -> Latn
-    {0x94030000u, 40u}, // daf -> Latn
-    {0x98030000u, 40u}, // dag -> Latn
-    {0x9C030000u, 40u}, // dah -> Latn
-    {0xA8030000u, 40u}, // dak -> Latn
-    {0xC4030000u, 15u}, // dar -> Cyrl
-    {0xD4030000u, 40u}, // dav -> Latn
-    {0x8C230000u, 40u}, // dbd -> Latn
-    {0xC0230000u, 40u}, // dbq -> Latn
+    {0xAD420000u, 44u}, // ckl -> Latn
+    {0xB9420000u, 44u}, // cko -> Latn
+    {0xE1420000u, 44u}, // cky -> Latn
+    {0x81620000u, 44u}, // cla -> Latn
+    {0x91820000u, 44u}, // cme -> Latn
+    {0x99820000u, 77u}, // cmg -> Soyo
+    {0x636F0000u, 44u}, // co -> Latn
+    {0xBDC20000u, 14u}, // cop -> Copt
+    {0xC9E20000u, 44u}, // cps -> Latn
+    {0x63720000u, 10u}, // cr -> Cans
+    {0x9E220000u, 16u}, // crh -> Cyrl
+    {0xA6220000u, 10u}, // crj -> Cans
+    {0xAA220000u, 10u}, // crk -> Cans
+    {0xAE220000u, 10u}, // crl -> Cans
+    {0xB2220000u, 10u}, // crm -> Cans
+    {0xCA220000u, 44u}, // crs -> Latn
+    {0x63730000u, 44u}, // cs -> Latn
+    {0x86420000u, 44u}, // csb -> Latn
+    {0xDA420000u, 10u}, // csw -> Cans
+    {0x8E620000u, 64u}, // ctd -> Pauc
+    {0x63750000u, 16u}, // cu -> Cyrl
+    {0x63760000u, 16u}, // cv -> Cyrl
+    {0x63790000u, 44u}, // cy -> Latn
+    {0x64610000u, 44u}, // da -> Latn
+    {0x8C030000u, 44u}, // dad -> Latn
+    {0x94030000u, 44u}, // daf -> Latn
+    {0x98030000u, 44u}, // dag -> Latn
+    {0x9C030000u, 44u}, // dah -> Latn
+    {0xA8030000u, 44u}, // dak -> Latn
+    {0xC4030000u, 16u}, // dar -> Cyrl
+    {0xD4030000u, 44u}, // dav -> Latn
+    {0x8C230000u, 44u}, // dbd -> Latn
+    {0xC0230000u, 44u}, // dbq -> Latn
     {0x88430000u,  1u}, // dcc -> Arab
-    {0xB4630000u, 40u}, // ddn -> Latn
-    {0x64650000u, 40u}, // de -> Latn
-    {0x8C830000u, 40u}, // ded -> Latn
-    {0xB4830000u, 40u}, // den -> Latn
-    {0x80C30000u, 40u}, // dga -> Latn
-    {0x9CC30000u, 40u}, // dgh -> Latn
-    {0xA0C30000u, 40u}, // dgi -> Latn
+    {0xB4630000u, 44u}, // ddn -> Latn
+    {0x64650000u, 44u}, // de -> Latn
+    {0x8C830000u, 44u}, // ded -> Latn
+    {0xB4830000u, 44u}, // den -> Latn
+    {0x80C30000u, 44u}, // dga -> Latn
+    {0x9CC30000u, 44u}, // dgh -> Latn
+    {0xA0C30000u, 44u}, // dgi -> Latn
     {0xACC30000u,  1u}, // dgl -> Arab
-    {0xC4C30000u, 40u}, // dgr -> Latn
-    {0xE4C30000u, 40u}, // dgz -> Latn
-    {0x81030000u, 40u}, // dia -> Latn
-    {0x91230000u, 40u}, // dje -> Latn
-    {0xA5A30000u, 40u}, // dnj -> Latn
-    {0x85C30000u, 40u}, // dob -> Latn
+    {0xC4C30000u, 44u}, // dgr -> Latn
+    {0xE4C30000u, 44u}, // dgz -> Latn
+    {0x81030000u, 44u}, // dia -> Latn
+    {0x91230000u, 44u}, // dje -> Latn
+    {0xA5A30000u, 44u}, // dnj -> Latn
+    {0x85C30000u, 44u}, // dob -> Latn
     {0xA1C30000u,  1u}, // doi -> Arab
-    {0xBDC30000u, 40u}, // dop -> Latn
-    {0xD9C30000u, 40u}, // dow -> Latn
-    {0xA2230000u, 40u}, // dri -> Latn
-    {0xCA230000u, 18u}, // drs -> Ethi
-    {0x86430000u, 40u}, // dsb -> Latn
-    {0xB2630000u, 40u}, // dtm -> Latn
-    {0xBE630000u, 40u}, // dtp -> Latn
-    {0xCA630000u, 40u}, // dts -> Latn
-    {0xE2630000u, 16u}, // dty -> Deva
-    {0x82830000u, 40u}, // dua -> Latn
-    {0x8A830000u, 40u}, // duc -> Latn
-    {0x8E830000u, 40u}, // dud -> Latn
-    {0x9A830000u, 40u}, // dug -> Latn
-    {0x64760000u, 79u}, // dv -> Thaa
-    {0x82A30000u, 40u}, // dva -> Latn
-    {0xDAC30000u, 40u}, // dww -> Latn
-    {0xBB030000u, 40u}, // dyo -> Latn
-    {0xD3030000u, 40u}, // dyu -> Latn
-    {0x647A0000u, 81u}, // dz -> Tibt
-    {0x9B230000u, 40u}, // dzg -> Latn
-    {0xD0240000u, 40u}, // ebu -> Latn
-    {0x65650000u, 40u}, // ee -> Latn
-    {0xA0A40000u, 40u}, // efi -> Latn
-    {0xACC40000u, 40u}, // egl -> Latn
-    {0xE0C40000u, 17u}, // egy -> Egyp
-    {0xE1440000u, 32u}, // eky -> Kali
-    {0x656C0000u, 21u}, // el -> Grek
-    {0x81840000u, 40u}, // ema -> Latn
-    {0xA1840000u, 40u}, // emi -> Latn
-    {0x656E0000u, 40u}, // en -> Latn
-    {0x656E5841u, 87u}, // en-XA -> ~~~A
-    {0xB5A40000u, 40u}, // enn -> Latn
-    {0xC1A40000u, 40u}, // enq -> Latn
-    {0x656F0000u, 40u}, // eo -> Latn
-    {0xA2240000u, 40u}, // eri -> Latn
-    {0x65730000u, 40u}, // es -> Latn
-    {0xD2440000u, 40u}, // esu -> Latn
-    {0x65740000u, 40u}, // et -> Latn
-    {0xC6640000u, 40u}, // etr -> Latn
-    {0xCE640000u, 30u}, // ett -> Ital
-    {0xD2640000u, 40u}, // etu -> Latn
-    {0xDE640000u, 40u}, // etx -> Latn
-    {0x65750000u, 40u}, // eu -> Latn
-    {0xBAC40000u, 40u}, // ewo -> Latn
-    {0xCEE40000u, 40u}, // ext -> Latn
+    {0xBDC30000u, 44u}, // dop -> Latn
+    {0xD9C30000u, 44u}, // dow -> Latn
+    {0xA2230000u, 44u}, // dri -> Latn
+    {0xCA230000u, 19u}, // drs -> Ethi
+    {0x86430000u, 44u}, // dsb -> Latn
+    {0xB2630000u, 44u}, // dtm -> Latn
+    {0xBE630000u, 44u}, // dtp -> Latn
+    {0xCA630000u, 44u}, // dts -> Latn
+    {0xE2630000u, 17u}, // dty -> Deva
+    {0x82830000u, 44u}, // dua -> Latn
+    {0x8A830000u, 44u}, // duc -> Latn
+    {0x8E830000u, 44u}, // dud -> Latn
+    {0x9A830000u, 44u}, // dug -> Latn
+    {0x64760000u, 86u}, // dv -> Thaa
+    {0x82A30000u, 44u}, // dva -> Latn
+    {0xDAC30000u, 44u}, // dww -> Latn
+    {0xBB030000u, 44u}, // dyo -> Latn
+    {0xD3030000u, 44u}, // dyu -> Latn
+    {0x647A0000u, 88u}, // dz -> Tibt
+    {0x9B230000u, 44u}, // dzg -> Latn
+    {0xD0240000u, 44u}, // ebu -> Latn
+    {0x65650000u, 44u}, // ee -> Latn
+    {0xA0A40000u, 44u}, // efi -> Latn
+    {0xACC40000u, 44u}, // egl -> Latn
+    {0xE0C40000u, 18u}, // egy -> Egyp
+    {0x81440000u, 44u}, // eka -> Latn
+    {0xE1440000u, 36u}, // eky -> Kali
+    {0x656C0000u, 24u}, // el -> Grek
+    {0x81840000u, 44u}, // ema -> Latn
+    {0xA1840000u, 44u}, // emi -> Latn
+    {0x656E0000u, 44u}, // en -> Latn
+    {0x656E5841u, 95u}, // en-XA -> ~~~A
+    {0xB5A40000u, 44u}, // enn -> Latn
+    {0xC1A40000u, 44u}, // enq -> Latn
+    {0x656F0000u, 44u}, // eo -> Latn
+    {0xA2240000u, 44u}, // eri -> Latn
+    {0x65730000u, 44u}, // es -> Latn
+    {0x9A440000u, 22u}, // esg -> Gonm
+    {0xD2440000u, 44u}, // esu -> Latn
+    {0x65740000u, 44u}, // et -> Latn
+    {0xC6640000u, 44u}, // etr -> Latn
+    {0xCE640000u, 34u}, // ett -> Ital
+    {0xD2640000u, 44u}, // etu -> Latn
+    {0xDE640000u, 44u}, // etx -> Latn
+    {0x65750000u, 44u}, // eu -> Latn
+    {0xBAC40000u, 44u}, // ewo -> Latn
+    {0xCEE40000u, 44u}, // ext -> Latn
     {0x66610000u,  1u}, // fa -> Arab
-    {0x80050000u, 40u}, // faa -> Latn
-    {0x84050000u, 40u}, // fab -> Latn
-    {0x98050000u, 40u}, // fag -> Latn
-    {0xA0050000u, 40u}, // fai -> Latn
-    {0xB4050000u, 40u}, // fan -> Latn
-    {0x66660000u, 40u}, // ff -> Latn
-    {0xA0A50000u, 40u}, // ffi -> Latn
-    {0xB0A50000u, 40u}, // ffm -> Latn
-    {0x66690000u, 40u}, // fi -> Latn
+    {0x80050000u, 44u}, // faa -> Latn
+    {0x84050000u, 44u}, // fab -> Latn
+    {0x98050000u, 44u}, // fag -> Latn
+    {0xA0050000u, 44u}, // fai -> Latn
+    {0xB4050000u, 44u}, // fan -> Latn
+    {0x66660000u, 44u}, // ff -> Latn
+    {0xA0A50000u, 44u}, // ffi -> Latn
+    {0xB0A50000u, 44u}, // ffm -> Latn
+    {0x66690000u, 44u}, // fi -> Latn
     {0x81050000u,  1u}, // fia -> Arab
-    {0xAD050000u, 40u}, // fil -> Latn
-    {0xCD050000u, 40u}, // fit -> Latn
-    {0x666A0000u, 40u}, // fj -> Latn
-    {0xC5650000u, 40u}, // flr -> Latn
-    {0xBD850000u, 40u}, // fmp -> Latn
-    {0x666F0000u, 40u}, // fo -> Latn
-    {0x8DC50000u, 40u}, // fod -> Latn
-    {0xB5C50000u, 40u}, // fon -> Latn
-    {0xC5C50000u, 40u}, // for -> Latn
-    {0x91E50000u, 40u}, // fpe -> Latn
-    {0xCA050000u, 40u}, // fqs -> Latn
-    {0x66720000u, 40u}, // fr -> Latn
-    {0x8A250000u, 40u}, // frc -> Latn
-    {0xBE250000u, 40u}, // frp -> Latn
-    {0xC6250000u, 40u}, // frr -> Latn
-    {0xCA250000u, 40u}, // frs -> Latn
+    {0xAD050000u, 44u}, // fil -> Latn
+    {0xCD050000u, 44u}, // fit -> Latn
+    {0x666A0000u, 44u}, // fj -> Latn
+    {0xC5650000u, 44u}, // flr -> Latn
+    {0xBD850000u, 44u}, // fmp -> Latn
+    {0x666F0000u, 44u}, // fo -> Latn
+    {0x8DC50000u, 44u}, // fod -> Latn
+    {0xB5C50000u, 44u}, // fon -> Latn
+    {0xC5C50000u, 44u}, // for -> Latn
+    {0x91E50000u, 44u}, // fpe -> Latn
+    {0xCA050000u, 44u}, // fqs -> Latn
+    {0x66720000u, 44u}, // fr -> Latn
+    {0x8A250000u, 44u}, // frc -> Latn
+    {0xBE250000u, 44u}, // frp -> Latn
+    {0xC6250000u, 44u}, // frr -> Latn
+    {0xCA250000u, 44u}, // frs -> Latn
     {0x86850000u,  1u}, // fub -> Arab
-    {0x8E850000u, 40u}, // fud -> Latn
-    {0x92850000u, 40u}, // fue -> Latn
-    {0x96850000u, 40u}, // fuf -> Latn
-    {0x9E850000u, 40u}, // fuh -> Latn
-    {0xC2850000u, 40u}, // fuq -> Latn
-    {0xC6850000u, 40u}, // fur -> Latn
-    {0xD6850000u, 40u}, // fuv -> Latn
-    {0xE2850000u, 40u}, // fuy -> Latn
-    {0xC6A50000u, 40u}, // fvr -> Latn
-    {0x66790000u, 40u}, // fy -> Latn
-    {0x67610000u, 40u}, // ga -> Latn
-    {0x80060000u, 40u}, // gaa -> Latn
-    {0x94060000u, 40u}, // gaf -> Latn
-    {0x98060000u, 40u}, // gag -> Latn
-    {0x9C060000u, 40u}, // gah -> Latn
-    {0xA4060000u, 40u}, // gaj -> Latn
-    {0xB0060000u, 40u}, // gam -> Latn
-    {0xB4060000u, 24u}, // gan -> Hans
-    {0xD8060000u, 40u}, // gaw -> Latn
-    {0xE0060000u, 40u}, // gay -> Latn
-    {0x94260000u, 40u}, // gbf -> Latn
-    {0xB0260000u, 16u}, // gbm -> Deva
-    {0xE0260000u, 40u}, // gby -> Latn
+    {0x8E850000u, 44u}, // fud -> Latn
+    {0x92850000u, 44u}, // fue -> Latn
+    {0x96850000u, 44u}, // fuf -> Latn
+    {0x9E850000u, 44u}, // fuh -> Latn
+    {0xC2850000u, 44u}, // fuq -> Latn
+    {0xC6850000u, 44u}, // fur -> Latn
+    {0xD6850000u, 44u}, // fuv -> Latn
+    {0xE2850000u, 44u}, // fuy -> Latn
+    {0xC6A50000u, 44u}, // fvr -> Latn
+    {0x66790000u, 44u}, // fy -> Latn
+    {0x67610000u, 44u}, // ga -> Latn
+    {0x80060000u, 44u}, // gaa -> Latn
+    {0x94060000u, 44u}, // gaf -> Latn
+    {0x98060000u, 44u}, // gag -> Latn
+    {0x9C060000u, 44u}, // gah -> Latn
+    {0xA4060000u, 44u}, // gaj -> Latn
+    {0xB0060000u, 44u}, // gam -> Latn
+    {0xB4060000u, 27u}, // gan -> Hans
+    {0xD8060000u, 44u}, // gaw -> Latn
+    {0xE0060000u, 44u}, // gay -> Latn
+    {0x80260000u, 44u}, // gba -> Latn
+    {0x94260000u, 44u}, // gbf -> Latn
+    {0xB0260000u, 17u}, // gbm -> Deva
+    {0xE0260000u, 44u}, // gby -> Latn
     {0xE4260000u,  1u}, // gbz -> Arab
-    {0xC4460000u, 40u}, // gcr -> Latn
-    {0x67640000u, 40u}, // gd -> Latn
-    {0x90660000u, 40u}, // gde -> Latn
-    {0xB4660000u, 40u}, // gdn -> Latn
-    {0xC4660000u, 40u}, // gdr -> Latn
-    {0x84860000u, 40u}, // geb -> Latn
-    {0xA4860000u, 40u}, // gej -> Latn
-    {0xAC860000u, 40u}, // gel -> Latn
-    {0xE4860000u, 18u}, // gez -> Ethi
-    {0xA8A60000u, 40u}, // gfk -> Latn
-    {0xB4C60000u, 16u}, // ggn -> Deva
-    {0xC8E60000u, 40u}, // ghs -> Latn
-    {0xAD060000u, 40u}, // gil -> Latn
-    {0xB1060000u, 40u}, // gim -> Latn
+    {0xC4460000u, 44u}, // gcr -> Latn
+    {0x67640000u, 44u}, // gd -> Latn
+    {0x90660000u, 44u}, // gde -> Latn
+    {0xB4660000u, 44u}, // gdn -> Latn
+    {0xC4660000u, 44u}, // gdr -> Latn
+    {0x84860000u, 44u}, // geb -> Latn
+    {0xA4860000u, 44u}, // gej -> Latn
+    {0xAC860000u, 44u}, // gel -> Latn
+    {0xE4860000u, 19u}, // gez -> Ethi
+    {0xA8A60000u, 44u}, // gfk -> Latn
+    {0xB4C60000u, 17u}, // ggn -> Deva
+    {0xC8E60000u, 44u}, // ghs -> Latn
+    {0xAD060000u, 44u}, // gil -> Latn
+    {0xB1060000u, 44u}, // gim -> Latn
     {0xA9260000u,  1u}, // gjk -> Arab
-    {0xB5260000u, 40u}, // gjn -> Latn
+    {0xB5260000u, 44u}, // gjn -> Latn
     {0xD1260000u,  1u}, // gju -> Arab
-    {0xB5460000u, 40u}, // gkn -> Latn
-    {0xBD460000u, 40u}, // gkp -> Latn
-    {0x676C0000u, 40u}, // gl -> Latn
+    {0xB5460000u, 44u}, // gkn -> Latn
+    {0xBD460000u, 44u}, // gkp -> Latn
+    {0x676C0000u, 44u}, // gl -> Latn
     {0xA9660000u,  1u}, // glk -> Arab
-    {0xB1860000u, 40u}, // gmm -> Latn
-    {0xD5860000u, 18u}, // gmv -> Ethi
-    {0x676E0000u, 40u}, // gn -> Latn
-    {0x8DA60000u, 40u}, // gnd -> Latn
-    {0x99A60000u, 40u}, // gng -> Latn
-    {0x8DC60000u, 40u}, // god -> Latn
-    {0x95C60000u, 18u}, // gof -> Ethi
-    {0xA1C60000u, 40u}, // goi -> Latn
-    {0xB1C60000u, 16u}, // gom -> Deva
-    {0xB5C60000u, 77u}, // gon -> Telu
-    {0xC5C60000u, 40u}, // gor -> Latn
-    {0xC9C60000u, 40u}, // gos -> Latn
-    {0xCDC60000u, 20u}, // got -> Goth
-    {0x8A260000u, 14u}, // grc -> Cprt
+    {0xB1860000u, 44u}, // gmm -> Latn
+    {0xD5860000u, 19u}, // gmv -> Ethi
+    {0x676E0000u, 44u}, // gn -> Latn
+    {0x8DA60000u, 44u}, // gnd -> Latn
+    {0x99A60000u, 44u}, // gng -> Latn
+    {0x8DC60000u, 44u}, // god -> Latn
+    {0x95C60000u, 19u}, // gof -> Ethi
+    {0xA1C60000u, 44u}, // goi -> Latn
+    {0xB1C60000u, 17u}, // gom -> Deva
+    {0xB5C60000u, 84u}, // gon -> Telu
+    {0xC5C60000u, 44u}, // gor -> Latn
+    {0xC9C60000u, 44u}, // gos -> Latn
+    {0xCDC60000u, 23u}, // got -> Goth
+    {0x86260000u, 44u}, // grb -> Latn
+    {0x8A260000u, 15u}, // grc -> Cprt
     {0xCE260000u,  7u}, // grt -> Beng
-    {0xDA260000u, 40u}, // grw -> Latn
-    {0xDA460000u, 40u}, // gsw -> Latn
-    {0x67750000u, 22u}, // gu -> Gujr
-    {0x86860000u, 40u}, // gub -> Latn
-    {0x8A860000u, 40u}, // guc -> Latn
-    {0x8E860000u, 40u}, // gud -> Latn
-    {0xC6860000u, 40u}, // gur -> Latn
-    {0xDA860000u, 40u}, // guw -> Latn
-    {0xDE860000u, 40u}, // gux -> Latn
-    {0xE6860000u, 40u}, // guz -> Latn
-    {0x67760000u, 40u}, // gv -> Latn
-    {0x96A60000u, 40u}, // gvf -> Latn
-    {0xC6A60000u, 16u}, // gvr -> Deva
-    {0xCAA60000u, 40u}, // gvs -> Latn
+    {0xDA260000u, 44u}, // grw -> Latn
+    {0xDA460000u, 44u}, // gsw -> Latn
+    {0x67750000u, 25u}, // gu -> Gujr
+    {0x86860000u, 44u}, // gub -> Latn
+    {0x8A860000u, 44u}, // guc -> Latn
+    {0x8E860000u, 44u}, // gud -> Latn
+    {0xC6860000u, 44u}, // gur -> Latn
+    {0xDA860000u, 44u}, // guw -> Latn
+    {0xDE860000u, 44u}, // gux -> Latn
+    {0xE6860000u, 44u}, // guz -> Latn
+    {0x67760000u, 44u}, // gv -> Latn
+    {0x96A60000u, 44u}, // gvf -> Latn
+    {0xC6A60000u, 17u}, // gvr -> Deva
+    {0xCAA60000u, 44u}, // gvs -> Latn
     {0x8AC60000u,  1u}, // gwc -> Arab
-    {0xA2C60000u, 40u}, // gwi -> Latn
+    {0xA2C60000u, 44u}, // gwi -> Latn
     {0xCEC60000u,  1u}, // gwt -> Arab
-    {0xA3060000u, 40u}, // gyi -> Latn
-    {0x68610000u, 40u}, // ha -> Latn
+    {0xA3060000u, 44u}, // gyi -> Latn
+    {0x68610000u, 44u}, // ha -> Latn
     {0x6861434Du,  1u}, // ha-CM -> Arab
     {0x68615344u,  1u}, // ha-SD -> Arab
-    {0x98070000u, 40u}, // hag -> Latn
-    {0xA8070000u, 24u}, // hak -> Hans
-    {0xB0070000u, 40u}, // ham -> Latn
-    {0xD8070000u, 40u}, // haw -> Latn
+    {0x98070000u, 44u}, // hag -> Latn
+    {0xA8070000u, 27u}, // hak -> Hans
+    {0xB0070000u, 44u}, // ham -> Latn
+    {0xD8070000u, 44u}, // haw -> Latn
     {0xE4070000u,  1u}, // haz -> Arab
-    {0x84270000u, 40u}, // hbb -> Latn
-    {0xE0670000u, 18u}, // hdy -> Ethi
-    {0x68650000u, 27u}, // he -> Hebr
-    {0xE0E70000u, 40u}, // hhy -> Latn
-    {0x68690000u, 16u}, // hi -> Deva
-    {0x81070000u, 40u}, // hia -> Latn
-    {0x95070000u, 40u}, // hif -> Latn
-    {0x99070000u, 40u}, // hig -> Latn
-    {0x9D070000u, 40u}, // hih -> Latn
-    {0xAD070000u, 40u}, // hil -> Latn
-    {0x81670000u, 40u}, // hla -> Latn
-    {0xD1670000u, 28u}, // hlu -> Hluw
-    {0x8D870000u, 62u}, // hmd -> Plrd
-    {0xCD870000u, 40u}, // hmt -> Latn
+    {0x84270000u, 44u}, // hbb -> Latn
+    {0xE0670000u, 19u}, // hdy -> Ethi
+    {0x68650000u, 30u}, // he -> Hebr
+    {0xE0E70000u, 44u}, // hhy -> Latn
+    {0x68690000u, 17u}, // hi -> Deva
+    {0x81070000u, 44u}, // hia -> Latn
+    {0x95070000u, 44u}, // hif -> Latn
+    {0x99070000u, 44u}, // hig -> Latn
+    {0x9D070000u, 44u}, // hih -> Latn
+    {0xAD070000u, 44u}, // hil -> Latn
+    {0x81670000u, 44u}, // hla -> Latn
+    {0xD1670000u, 31u}, // hlu -> Hluw
+    {0x8D870000u, 67u}, // hmd -> Plrd
+    {0xCD870000u, 44u}, // hmt -> Latn
     {0x8DA70000u,  1u}, // hnd -> Arab
-    {0x91A70000u, 16u}, // hne -> Deva
-    {0xA5A70000u, 29u}, // hnj -> Hmng
-    {0xB5A70000u, 40u}, // hnn -> Latn
+    {0x91A70000u, 17u}, // hne -> Deva
+    {0xA5A70000u, 32u}, // hnj -> Hmng
+    {0xB5A70000u, 44u}, // hnn -> Latn
     {0xB9A70000u,  1u}, // hno -> Arab
-    {0x686F0000u, 40u}, // ho -> Latn
-    {0x89C70000u, 16u}, // hoc -> Deva
-    {0xA5C70000u, 16u}, // hoj -> Deva
-    {0xCDC70000u, 40u}, // hot -> Latn
-    {0x68720000u, 40u}, // hr -> Latn
-    {0x86470000u, 40u}, // hsb -> Latn
-    {0xB6470000u, 24u}, // hsn -> Hans
-    {0x68740000u, 40u}, // ht -> Latn
-    {0x68750000u, 40u}, // hu -> Latn
-    {0xA2870000u, 40u}, // hui -> Latn
+    {0x686F0000u, 44u}, // ho -> Latn
+    {0x89C70000u, 17u}, // hoc -> Deva
+    {0xA5C70000u, 17u}, // hoj -> Deva
+    {0xCDC70000u, 44u}, // hot -> Latn
+    {0x68720000u, 44u}, // hr -> Latn
+    {0x86470000u, 44u}, // hsb -> Latn
+    {0xB6470000u, 27u}, // hsn -> Hans
+    {0x68740000u, 44u}, // ht -> Latn
+    {0x68750000u, 44u}, // hu -> Latn
+    {0xA2870000u, 44u}, // hui -> Latn
     {0x68790000u,  3u}, // hy -> Armn
-    {0x687A0000u, 40u}, // hz -> Latn
-    {0x69610000u, 40u}, // ia -> Latn
-    {0xB4080000u, 40u}, // ian -> Latn
-    {0xC4080000u, 40u}, // iar -> Latn
-    {0x80280000u, 40u}, // iba -> Latn
-    {0x84280000u, 40u}, // ibb -> Latn
-    {0xE0280000u, 40u}, // iby -> Latn
-    {0x80480000u, 40u}, // ica -> Latn
-    {0x9C480000u, 40u}, // ich -> Latn
-    {0x69640000u, 40u}, // id -> Latn
-    {0x8C680000u, 40u}, // idd -> Latn
-    {0xA0680000u, 40u}, // idi -> Latn
-    {0xD0680000u, 40u}, // idu -> Latn
-    {0x69670000u, 40u}, // ig -> Latn
-    {0x84C80000u, 40u}, // igb -> Latn
-    {0x90C80000u, 40u}, // ige -> Latn
-    {0x69690000u, 86u}, // ii -> Yiii
-    {0xA5280000u, 40u}, // ijj -> Latn
-    {0x696B0000u, 40u}, // ik -> Latn
-    {0xA9480000u, 40u}, // ikk -> Latn
-    {0xCD480000u, 40u}, // ikt -> Latn
-    {0xD9480000u, 40u}, // ikw -> Latn
-    {0xDD480000u, 40u}, // ikx -> Latn
-    {0xB9680000u, 40u}, // ilo -> Latn
-    {0xB9880000u, 40u}, // imo -> Latn
-    {0x696E0000u, 40u}, // in -> Latn
-    {0x9DA80000u, 15u}, // inh -> Cyrl
-    {0xD1C80000u, 40u}, // iou -> Latn
-    {0xA2280000u, 40u}, // iri -> Latn
-    {0x69730000u, 40u}, // is -> Latn
-    {0x69740000u, 40u}, // it -> Latn
-    {0x69750000u,  9u}, // iu -> Cans
-    {0x69770000u, 27u}, // iw -> Hebr
-    {0xB2C80000u, 40u}, // iwm -> Latn
-    {0xCAC80000u, 40u}, // iws -> Latn
-    {0x9F280000u, 40u}, // izh -> Latn
-    {0xA3280000u, 40u}, // izi -> Latn
-    {0x6A610000u, 31u}, // ja -> Jpan
-    {0x84090000u, 40u}, // jab -> Latn
-    {0xB0090000u, 40u}, // jam -> Latn
-    {0xD0290000u, 40u}, // jbu -> Latn
-    {0xB4890000u, 40u}, // jen -> Latn
-    {0xA8C90000u, 40u}, // jgk -> Latn
-    {0xB8C90000u, 40u}, // jgo -> Latn
-    {0x6A690000u, 27u}, // ji -> Hebr
-    {0x85090000u, 40u}, // jib -> Latn
-    {0x89890000u, 40u}, // jmc -> Latn
-    {0xAD890000u, 16u}, // jml -> Deva
-    {0x82290000u, 40u}, // jra -> Latn
-    {0xCE890000u, 40u}, // jut -> Latn
-    {0x6A760000u, 40u}, // jv -> Latn
-    {0x6A770000u, 40u}, // jw -> Latn
-    {0x6B610000u, 19u}, // ka -> Geor
-    {0x800A0000u, 15u}, // kaa -> Cyrl
-    {0x840A0000u, 40u}, // kab -> Latn
-    {0x880A0000u, 40u}, // kac -> Latn
-    {0x8C0A0000u, 40u}, // kad -> Latn
-    {0xA00A0000u, 40u}, // kai -> Latn
-    {0xA40A0000u, 40u}, // kaj -> Latn
-    {0xB00A0000u, 40u}, // kam -> Latn
-    {0xB80A0000u, 40u}, // kao -> Latn
-    {0x8C2A0000u, 15u}, // kbd -> Cyrl
-    {0xB02A0000u, 40u}, // kbm -> Latn
-    {0xBC2A0000u, 40u}, // kbp -> Latn
-    {0xC02A0000u, 40u}, // kbq -> Latn
-    {0xDC2A0000u, 40u}, // kbx -> Latn
+    {0x687A0000u, 44u}, // hz -> Latn
+    {0x69610000u, 44u}, // ia -> Latn
+    {0xB4080000u, 44u}, // ian -> Latn
+    {0xC4080000u, 44u}, // iar -> Latn
+    {0x80280000u, 44u}, // iba -> Latn
+    {0x84280000u, 44u}, // ibb -> Latn
+    {0xE0280000u, 44u}, // iby -> Latn
+    {0x80480000u, 44u}, // ica -> Latn
+    {0x9C480000u, 44u}, // ich -> Latn
+    {0x69640000u, 44u}, // id -> Latn
+    {0x8C680000u, 44u}, // idd -> Latn
+    {0xA0680000u, 44u}, // idi -> Latn
+    {0xD0680000u, 44u}, // idu -> Latn
+    {0x90A80000u, 44u}, // ife -> Latn
+    {0x69670000u, 44u}, // ig -> Latn
+    {0x84C80000u, 44u}, // igb -> Latn
+    {0x90C80000u, 44u}, // ige -> Latn
+    {0x69690000u, 94u}, // ii -> Yiii
+    {0xA5280000u, 44u}, // ijj -> Latn
+    {0x696B0000u, 44u}, // ik -> Latn
+    {0xA9480000u, 44u}, // ikk -> Latn
+    {0xCD480000u, 44u}, // ikt -> Latn
+    {0xD9480000u, 44u}, // ikw -> Latn
+    {0xDD480000u, 44u}, // ikx -> Latn
+    {0xB9680000u, 44u}, // ilo -> Latn
+    {0xB9880000u, 44u}, // imo -> Latn
+    {0x696E0000u, 44u}, // in -> Latn
+    {0x9DA80000u, 16u}, // inh -> Cyrl
+    {0x696F0000u, 44u}, // io -> Latn
+    {0xD1C80000u, 44u}, // iou -> Latn
+    {0xA2280000u, 44u}, // iri -> Latn
+    {0x69730000u, 44u}, // is -> Latn
+    {0x69740000u, 44u}, // it -> Latn
+    {0x69750000u, 10u}, // iu -> Cans
+    {0x69770000u, 30u}, // iw -> Hebr
+    {0xB2C80000u, 44u}, // iwm -> Latn
+    {0xCAC80000u, 44u}, // iws -> Latn
+    {0x9F280000u, 44u}, // izh -> Latn
+    {0xA3280000u, 44u}, // izi -> Latn
+    {0x6A610000u, 35u}, // ja -> Jpan
+    {0x84090000u, 44u}, // jab -> Latn
+    {0xB0090000u, 44u}, // jam -> Latn
+    {0xB8290000u, 44u}, // jbo -> Latn
+    {0xD0290000u, 44u}, // jbu -> Latn
+    {0xB4890000u, 44u}, // jen -> Latn
+    {0xA8C90000u, 44u}, // jgk -> Latn
+    {0xB8C90000u, 44u}, // jgo -> Latn
+    {0x6A690000u, 30u}, // ji -> Hebr
+    {0x85090000u, 44u}, // jib -> Latn
+    {0x89890000u, 44u}, // jmc -> Latn
+    {0xAD890000u, 17u}, // jml -> Deva
+    {0x82290000u, 44u}, // jra -> Latn
+    {0xCE890000u, 44u}, // jut -> Latn
+    {0x6A760000u, 44u}, // jv -> Latn
+    {0x6A770000u, 44u}, // jw -> Latn
+    {0x6B610000u, 20u}, // ka -> Geor
+    {0x800A0000u, 16u}, // kaa -> Cyrl
+    {0x840A0000u, 44u}, // kab -> Latn
+    {0x880A0000u, 44u}, // kac -> Latn
+    {0x8C0A0000u, 44u}, // kad -> Latn
+    {0xA00A0000u, 44u}, // kai -> Latn
+    {0xA40A0000u, 44u}, // kaj -> Latn
+    {0xB00A0000u, 44u}, // kam -> Latn
+    {0xB80A0000u, 44u}, // kao -> Latn
+    {0x8C2A0000u, 16u}, // kbd -> Cyrl
+    {0xB02A0000u, 44u}, // kbm -> Latn
+    {0xBC2A0000u, 44u}, // kbp -> Latn
+    {0xC02A0000u, 44u}, // kbq -> Latn
+    {0xDC2A0000u, 44u}, // kbx -> Latn
     {0xE02A0000u,  1u}, // kby -> Arab
-    {0x984A0000u, 40u}, // kcg -> Latn
-    {0xA84A0000u, 40u}, // kck -> Latn
-    {0xAC4A0000u, 40u}, // kcl -> Latn
-    {0xCC4A0000u, 40u}, // kct -> Latn
-    {0x906A0000u, 40u}, // kde -> Latn
+    {0x984A0000u, 44u}, // kcg -> Latn
+    {0xA84A0000u, 44u}, // kck -> Latn
+    {0xAC4A0000u, 44u}, // kcl -> Latn
+    {0xCC4A0000u, 44u}, // kct -> Latn
+    {0x906A0000u, 44u}, // kde -> Latn
     {0x9C6A0000u,  1u}, // kdh -> Arab
-    {0xAC6A0000u, 40u}, // kdl -> Latn
-    {0xCC6A0000u, 80u}, // kdt -> Thai
-    {0x808A0000u, 40u}, // kea -> Latn
-    {0xB48A0000u, 40u}, // ken -> Latn
-    {0xE48A0000u, 40u}, // kez -> Latn
-    {0xB8AA0000u, 40u}, // kfo -> Latn
-    {0xC4AA0000u, 16u}, // kfr -> Deva
-    {0xE0AA0000u, 16u}, // kfy -> Deva
-    {0x6B670000u, 40u}, // kg -> Latn
-    {0x90CA0000u, 40u}, // kge -> Latn
-    {0x94CA0000u, 40u}, // kgf -> Latn
-    {0xBCCA0000u, 40u}, // kgp -> Latn
-    {0x80EA0000u, 40u}, // kha -> Latn
-    {0x84EA0000u, 73u}, // khb -> Talu
-    {0xB4EA0000u, 16u}, // khn -> Deva
-    {0xC0EA0000u, 40u}, // khq -> Latn
-    {0xC8EA0000u, 40u}, // khs -> Latn
-    {0xCCEA0000u, 52u}, // kht -> Mymr
+    {0xAC6A0000u, 44u}, // kdl -> Latn
+    {0xCC6A0000u, 87u}, // kdt -> Thai
+    {0x808A0000u, 44u}, // kea -> Latn
+    {0xB48A0000u, 44u}, // ken -> Latn
+    {0xE48A0000u, 44u}, // kez -> Latn
+    {0xB8AA0000u, 44u}, // kfo -> Latn
+    {0xC4AA0000u, 17u}, // kfr -> Deva
+    {0xE0AA0000u, 17u}, // kfy -> Deva
+    {0x6B670000u, 44u}, // kg -> Latn
+    {0x90CA0000u, 44u}, // kge -> Latn
+    {0x94CA0000u, 44u}, // kgf -> Latn
+    {0xBCCA0000u, 44u}, // kgp -> Latn
+    {0x80EA0000u, 44u}, // kha -> Latn
+    {0x84EA0000u, 80u}, // khb -> Talu
+    {0xB4EA0000u, 17u}, // khn -> Deva
+    {0xC0EA0000u, 44u}, // khq -> Latn
+    {0xC8EA0000u, 44u}, // khs -> Latn
+    {0xCCEA0000u, 56u}, // kht -> Mymr
     {0xD8EA0000u,  1u}, // khw -> Arab
-    {0xE4EA0000u, 40u}, // khz -> Latn
-    {0x6B690000u, 40u}, // ki -> Latn
-    {0xA50A0000u, 40u}, // kij -> Latn
-    {0xD10A0000u, 40u}, // kiu -> Latn
-    {0xD90A0000u, 40u}, // kiw -> Latn
-    {0x6B6A0000u, 40u}, // kj -> Latn
-    {0x8D2A0000u, 40u}, // kjd -> Latn
-    {0x992A0000u, 39u}, // kjg -> Laoo
-    {0xC92A0000u, 40u}, // kjs -> Latn
-    {0xE12A0000u, 40u}, // kjy -> Latn
-    {0x6B6B0000u, 15u}, // kk -> Cyrl
+    {0xE4EA0000u, 44u}, // khz -> Latn
+    {0x6B690000u, 44u}, // ki -> Latn
+    {0xA50A0000u, 44u}, // kij -> Latn
+    {0xD10A0000u, 44u}, // kiu -> Latn
+    {0xD90A0000u, 44u}, // kiw -> Latn
+    {0x6B6A0000u, 44u}, // kj -> Latn
+    {0x8D2A0000u, 44u}, // kjd -> Latn
+    {0x992A0000u, 43u}, // kjg -> Laoo
+    {0xC92A0000u, 44u}, // kjs -> Latn
+    {0xE12A0000u, 44u}, // kjy -> Latn
+    {0x6B6B0000u, 16u}, // kk -> Cyrl
     {0x6B6B4146u,  1u}, // kk-AF -> Arab
     {0x6B6B434Eu,  1u}, // kk-CN -> Arab
     {0x6B6B4952u,  1u}, // kk-IR -> Arab
     {0x6B6B4D4Eu,  1u}, // kk-MN -> Arab
-    {0x894A0000u, 40u}, // kkc -> Latn
-    {0xA54A0000u, 40u}, // kkj -> Latn
-    {0x6B6C0000u, 40u}, // kl -> Latn
-    {0xB56A0000u, 40u}, // kln -> Latn
-    {0xC16A0000u, 40u}, // klq -> Latn
-    {0xCD6A0000u, 40u}, // klt -> Latn
-    {0xDD6A0000u, 40u}, // klx -> Latn
-    {0x6B6D0000u, 35u}, // km -> Khmr
-    {0x858A0000u, 40u}, // kmb -> Latn
-    {0x9D8A0000u, 40u}, // kmh -> Latn
-    {0xB98A0000u, 40u}, // kmo -> Latn
-    {0xC98A0000u, 40u}, // kms -> Latn
-    {0xD18A0000u, 40u}, // kmu -> Latn
-    {0xD98A0000u, 40u}, // kmw -> Latn
-    {0x6B6E0000u, 36u}, // kn -> Knda
-    {0xBDAA0000u, 40u}, // knp -> Latn
-    {0x6B6F0000u, 37u}, // ko -> Kore
-    {0xA1CA0000u, 15u}, // koi -> Cyrl
-    {0xA9CA0000u, 16u}, // kok -> Deva
-    {0xADCA0000u, 40u}, // kol -> Latn
-    {0xC9CA0000u, 40u}, // kos -> Latn
-    {0xE5CA0000u, 40u}, // koz -> Latn
-    {0x91EA0000u, 40u}, // kpe -> Latn
-    {0x95EA0000u, 40u}, // kpf -> Latn
-    {0xB9EA0000u, 40u}, // kpo -> Latn
-    {0xC5EA0000u, 40u}, // kpr -> Latn
-    {0xDDEA0000u, 40u}, // kpx -> Latn
-    {0x860A0000u, 40u}, // kqb -> Latn
-    {0x960A0000u, 40u}, // kqf -> Latn
-    {0xCA0A0000u, 40u}, // kqs -> Latn
-    {0xE20A0000u, 18u}, // kqy -> Ethi
-    {0x8A2A0000u, 15u}, // krc -> Cyrl
-    {0xA22A0000u, 40u}, // kri -> Latn
-    {0xA62A0000u, 40u}, // krj -> Latn
-    {0xAE2A0000u, 40u}, // krl -> Latn
-    {0xCA2A0000u, 40u}, // krs -> Latn
-    {0xD22A0000u, 16u}, // kru -> Deva
+    {0x894A0000u, 44u}, // kkc -> Latn
+    {0xA54A0000u, 44u}, // kkj -> Latn
+    {0x6B6C0000u, 44u}, // kl -> Latn
+    {0xB56A0000u, 44u}, // kln -> Latn
+    {0xC16A0000u, 44u}, // klq -> Latn
+    {0xCD6A0000u, 44u}, // klt -> Latn
+    {0xDD6A0000u, 44u}, // klx -> Latn
+    {0x6B6D0000u, 39u}, // km -> Khmr
+    {0x858A0000u, 44u}, // kmb -> Latn
+    {0x9D8A0000u, 44u}, // kmh -> Latn
+    {0xB98A0000u, 44u}, // kmo -> Latn
+    {0xC98A0000u, 44u}, // kms -> Latn
+    {0xD18A0000u, 44u}, // kmu -> Latn
+    {0xD98A0000u, 44u}, // kmw -> Latn
+    {0x6B6E0000u, 40u}, // kn -> Knda
+    {0x95AA0000u, 44u}, // knf -> Latn
+    {0xBDAA0000u, 44u}, // knp -> Latn
+    {0x6B6F0000u, 41u}, // ko -> Kore
+    {0xA1CA0000u, 16u}, // koi -> Cyrl
+    {0xA9CA0000u, 17u}, // kok -> Deva
+    {0xADCA0000u, 44u}, // kol -> Latn
+    {0xC9CA0000u, 44u}, // kos -> Latn
+    {0xE5CA0000u, 44u}, // koz -> Latn
+    {0x91EA0000u, 44u}, // kpe -> Latn
+    {0x95EA0000u, 44u}, // kpf -> Latn
+    {0xB9EA0000u, 44u}, // kpo -> Latn
+    {0xC5EA0000u, 44u}, // kpr -> Latn
+    {0xDDEA0000u, 44u}, // kpx -> Latn
+    {0x860A0000u, 44u}, // kqb -> Latn
+    {0x960A0000u, 44u}, // kqf -> Latn
+    {0xCA0A0000u, 44u}, // kqs -> Latn
+    {0xE20A0000u, 19u}, // kqy -> Ethi
+    {0x6B720000u, 44u}, // kr -> Latn
+    {0x8A2A0000u, 16u}, // krc -> Cyrl
+    {0xA22A0000u, 44u}, // kri -> Latn
+    {0xA62A0000u, 44u}, // krj -> Latn
+    {0xAE2A0000u, 44u}, // krl -> Latn
+    {0xCA2A0000u, 44u}, // krs -> Latn
+    {0xD22A0000u, 17u}, // kru -> Deva
     {0x6B730000u,  1u}, // ks -> Arab
-    {0x864A0000u, 40u}, // ksb -> Latn
-    {0x8E4A0000u, 40u}, // ksd -> Latn
-    {0x964A0000u, 40u}, // ksf -> Latn
-    {0x9E4A0000u, 40u}, // ksh -> Latn
-    {0xA64A0000u, 40u}, // ksj -> Latn
-    {0xC64A0000u, 40u}, // ksr -> Latn
-    {0x866A0000u, 18u}, // ktb -> Ethi
-    {0xB26A0000u, 40u}, // ktm -> Latn
-    {0xBA6A0000u, 40u}, // kto -> Latn
-    {0x6B750000u, 40u}, // ku -> Latn
+    {0x864A0000u, 44u}, // ksb -> Latn
+    {0x8E4A0000u, 44u}, // ksd -> Latn
+    {0x964A0000u, 44u}, // ksf -> Latn
+    {0x9E4A0000u, 44u}, // ksh -> Latn
+    {0xA64A0000u, 44u}, // ksj -> Latn
+    {0xC64A0000u, 44u}, // ksr -> Latn
+    {0x866A0000u, 19u}, // ktb -> Ethi
+    {0xB26A0000u, 44u}, // ktm -> Latn
+    {0xBA6A0000u, 44u}, // kto -> Latn
+    {0x6B750000u, 44u}, // ku -> Latn
     {0x6B754952u,  1u}, // ku-IR -> Arab
     {0x6B754C42u,  1u}, // ku-LB -> Arab
-    {0x868A0000u, 40u}, // kub -> Latn
-    {0x8E8A0000u, 40u}, // kud -> Latn
-    {0x928A0000u, 40u}, // kue -> Latn
-    {0xA68A0000u, 40u}, // kuj -> Latn
-    {0xB28A0000u, 15u}, // kum -> Cyrl
-    {0xB68A0000u, 40u}, // kun -> Latn
-    {0xBE8A0000u, 40u}, // kup -> Latn
-    {0xCA8A0000u, 40u}, // kus -> Latn
-    {0x6B760000u, 15u}, // kv -> Cyrl
-    {0x9AAA0000u, 40u}, // kvg -> Latn
-    {0xC6AA0000u, 40u}, // kvr -> Latn
+    {0x868A0000u, 44u}, // kub -> Latn
+    {0x8E8A0000u, 44u}, // kud -> Latn
+    {0x928A0000u, 44u}, // kue -> Latn
+    {0xA68A0000u, 44u}, // kuj -> Latn
+    {0xB28A0000u, 16u}, // kum -> Cyrl
+    {0xB68A0000u, 44u}, // kun -> Latn
+    {0xBE8A0000u, 44u}, // kup -> Latn
+    {0xCA8A0000u, 44u}, // kus -> Latn
+    {0x6B760000u, 16u}, // kv -> Cyrl
+    {0x9AAA0000u, 44u}, // kvg -> Latn
+    {0xC6AA0000u, 44u}, // kvr -> Latn
     {0xDEAA0000u,  1u}, // kvx -> Arab
-    {0x6B770000u, 40u}, // kw -> Latn
-    {0xA6CA0000u, 40u}, // kwj -> Latn
-    {0xBACA0000u, 40u}, // kwo -> Latn
-    {0x82EA0000u, 40u}, // kxa -> Latn
-    {0x8AEA0000u, 18u}, // kxc -> Ethi
-    {0xB2EA0000u, 80u}, // kxm -> Thai
+    {0x6B770000u, 44u}, // kw -> Latn
+    {0xA6CA0000u, 44u}, // kwj -> Latn
+    {0xBACA0000u, 44u}, // kwo -> Latn
+    {0x82EA0000u, 44u}, // kxa -> Latn
+    {0x8AEA0000u, 19u}, // kxc -> Ethi
+    {0xB2EA0000u, 87u}, // kxm -> Thai
     {0xBEEA0000u,  1u}, // kxp -> Arab
-    {0xDAEA0000u, 40u}, // kxw -> Latn
-    {0xE6EA0000u, 40u}, // kxz -> Latn
-    {0x6B790000u, 15u}, // ky -> Cyrl
+    {0xDAEA0000u, 44u}, // kxw -> Latn
+    {0xE6EA0000u, 44u}, // kxz -> Latn
+    {0x6B790000u, 16u}, // ky -> Cyrl
     {0x6B79434Eu,  1u}, // ky-CN -> Arab
-    {0x6B795452u, 40u}, // ky-TR -> Latn
-    {0x930A0000u, 40u}, // kye -> Latn
-    {0xDF0A0000u, 40u}, // kyx -> Latn
-    {0xC72A0000u, 40u}, // kzr -> Latn
-    {0x6C610000u, 40u}, // la -> Latn
-    {0x840B0000u, 42u}, // lab -> Lina
-    {0x8C0B0000u, 27u}, // lad -> Hebr
-    {0x980B0000u, 40u}, // lag -> Latn
+    {0x6B795452u, 44u}, // ky-TR -> Latn
+    {0x930A0000u, 44u}, // kye -> Latn
+    {0xDF0A0000u, 44u}, // kyx -> Latn
+    {0xC72A0000u, 44u}, // kzr -> Latn
+    {0x6C610000u, 44u}, // la -> Latn
+    {0x840B0000u, 46u}, // lab -> Lina
+    {0x8C0B0000u, 30u}, // lad -> Hebr
+    {0x980B0000u, 44u}, // lag -> Latn
     {0x9C0B0000u,  1u}, // lah -> Arab
-    {0xA40B0000u, 40u}, // laj -> Latn
-    {0xC80B0000u, 40u}, // las -> Latn
-    {0x6C620000u, 40u}, // lb -> Latn
-    {0x902B0000u, 15u}, // lbe -> Cyrl
-    {0xD02B0000u, 40u}, // lbu -> Latn
-    {0xD82B0000u, 40u}, // lbw -> Latn
-    {0xB04B0000u, 40u}, // lcm -> Latn
-    {0xBC4B0000u, 80u}, // lcp -> Thai
-    {0x846B0000u, 40u}, // ldb -> Latn
-    {0x8C8B0000u, 40u}, // led -> Latn
-    {0x908B0000u, 40u}, // lee -> Latn
-    {0xB08B0000u, 40u}, // lem -> Latn
-    {0xBC8B0000u, 41u}, // lep -> Lepc
-    {0xC08B0000u, 40u}, // leq -> Latn
-    {0xD08B0000u, 40u}, // leu -> Latn
-    {0xE48B0000u, 15u}, // lez -> Cyrl
-    {0x6C670000u, 40u}, // lg -> Latn
-    {0x98CB0000u, 40u}, // lgg -> Latn
-    {0x6C690000u, 40u}, // li -> Latn
-    {0x810B0000u, 40u}, // lia -> Latn
-    {0x8D0B0000u, 40u}, // lid -> Latn
-    {0x950B0000u, 16u}, // lif -> Deva
-    {0x990B0000u, 40u}, // lig -> Latn
-    {0x9D0B0000u, 40u}, // lih -> Latn
-    {0xA50B0000u, 40u}, // lij -> Latn
-    {0xC90B0000u, 43u}, // lis -> Lisu
-    {0xBD2B0000u, 40u}, // ljp -> Latn
+    {0xA40B0000u, 44u}, // laj -> Latn
+    {0xC80B0000u, 44u}, // las -> Latn
+    {0x6C620000u, 44u}, // lb -> Latn
+    {0x902B0000u, 16u}, // lbe -> Cyrl
+    {0xD02B0000u, 44u}, // lbu -> Latn
+    {0xD82B0000u, 44u}, // lbw -> Latn
+    {0xB04B0000u, 44u}, // lcm -> Latn
+    {0xBC4B0000u, 87u}, // lcp -> Thai
+    {0x846B0000u, 44u}, // ldb -> Latn
+    {0x8C8B0000u, 44u}, // led -> Latn
+    {0x908B0000u, 44u}, // lee -> Latn
+    {0xB08B0000u, 44u}, // lem -> Latn
+    {0xBC8B0000u, 45u}, // lep -> Lepc
+    {0xC08B0000u, 44u}, // leq -> Latn
+    {0xD08B0000u, 44u}, // leu -> Latn
+    {0xE48B0000u, 16u}, // lez -> Cyrl
+    {0x6C670000u, 44u}, // lg -> Latn
+    {0x98CB0000u, 44u}, // lgg -> Latn
+    {0x6C690000u, 44u}, // li -> Latn
+    {0x810B0000u, 44u}, // lia -> Latn
+    {0x8D0B0000u, 44u}, // lid -> Latn
+    {0x950B0000u, 17u}, // lif -> Deva
+    {0x990B0000u, 44u}, // lig -> Latn
+    {0x9D0B0000u, 44u}, // lih -> Latn
+    {0xA50B0000u, 44u}, // lij -> Latn
+    {0xC90B0000u, 47u}, // lis -> Lisu
+    {0xBD2B0000u, 44u}, // ljp -> Latn
     {0xA14B0000u,  1u}, // lki -> Arab
-    {0xCD4B0000u, 40u}, // lkt -> Latn
-    {0x916B0000u, 40u}, // lle -> Latn
-    {0xB56B0000u, 40u}, // lln -> Latn
-    {0xB58B0000u, 77u}, // lmn -> Telu
-    {0xB98B0000u, 40u}, // lmo -> Latn
-    {0xBD8B0000u, 40u}, // lmp -> Latn
-    {0x6C6E0000u, 40u}, // ln -> Latn
-    {0xC9AB0000u, 40u}, // lns -> Latn
-    {0xD1AB0000u, 40u}, // lnu -> Latn
-    {0x6C6F0000u, 39u}, // lo -> Laoo
-    {0xA5CB0000u, 40u}, // loj -> Latn
-    {0xA9CB0000u, 40u}, // lok -> Latn
-    {0xADCB0000u, 40u}, // lol -> Latn
-    {0xC5CB0000u, 40u}, // lor -> Latn
-    {0xC9CB0000u, 40u}, // los -> Latn
-    {0xE5CB0000u, 40u}, // loz -> Latn
+    {0xCD4B0000u, 44u}, // lkt -> Latn
+    {0x916B0000u, 44u}, // lle -> Latn
+    {0xB56B0000u, 44u}, // lln -> Latn
+    {0xB58B0000u, 84u}, // lmn -> Telu
+    {0xB98B0000u, 44u}, // lmo -> Latn
+    {0xBD8B0000u, 44u}, // lmp -> Latn
+    {0x6C6E0000u, 44u}, // ln -> Latn
+    {0xC9AB0000u, 44u}, // lns -> Latn
+    {0xD1AB0000u, 44u}, // lnu -> Latn
+    {0x6C6F0000u, 43u}, // lo -> Laoo
+    {0xA5CB0000u, 44u}, // loj -> Latn
+    {0xA9CB0000u, 44u}, // lok -> Latn
+    {0xADCB0000u, 44u}, // lol -> Latn
+    {0xC5CB0000u, 44u}, // lor -> Latn
+    {0xC9CB0000u, 44u}, // los -> Latn
+    {0xE5CB0000u, 44u}, // loz -> Latn
     {0x8A2B0000u,  1u}, // lrc -> Arab
-    {0x6C740000u, 40u}, // lt -> Latn
-    {0x9A6B0000u, 40u}, // ltg -> Latn
-    {0x6C750000u, 40u}, // lu -> Latn
-    {0x828B0000u, 40u}, // lua -> Latn
-    {0xBA8B0000u, 40u}, // luo -> Latn
-    {0xE28B0000u, 40u}, // luy -> Latn
+    {0x6C740000u, 44u}, // lt -> Latn
+    {0x9A6B0000u, 44u}, // ltg -> Latn
+    {0x6C750000u, 44u}, // lu -> Latn
+    {0x828B0000u, 44u}, // lua -> Latn
+    {0xBA8B0000u, 44u}, // luo -> Latn
+    {0xE28B0000u, 44u}, // luy -> Latn
     {0xE68B0000u,  1u}, // luz -> Arab
-    {0x6C760000u, 40u}, // lv -> Latn
-    {0xAECB0000u, 80u}, // lwl -> Thai
-    {0x9F2B0000u, 24u}, // lzh -> Hans
-    {0xE72B0000u, 40u}, // lzz -> Latn
-    {0x8C0C0000u, 40u}, // mad -> Latn
-    {0x940C0000u, 40u}, // maf -> Latn
-    {0x980C0000u, 16u}, // mag -> Deva
-    {0xA00C0000u, 16u}, // mai -> Deva
-    {0xA80C0000u, 40u}, // mak -> Latn
-    {0xB40C0000u, 40u}, // man -> Latn
-    {0xB40C474Eu, 54u}, // man-GN -> Nkoo
-    {0xC80C0000u, 40u}, // mas -> Latn
-    {0xD80C0000u, 40u}, // maw -> Latn
-    {0xE40C0000u, 40u}, // maz -> Latn
-    {0x9C2C0000u, 40u}, // mbh -> Latn
-    {0xB82C0000u, 40u}, // mbo -> Latn
-    {0xC02C0000u, 40u}, // mbq -> Latn
-    {0xD02C0000u, 40u}, // mbu -> Latn
-    {0xD82C0000u, 40u}, // mbw -> Latn
-    {0xA04C0000u, 40u}, // mci -> Latn
-    {0xBC4C0000u, 40u}, // mcp -> Latn
-    {0xC04C0000u, 40u}, // mcq -> Latn
-    {0xC44C0000u, 40u}, // mcr -> Latn
-    {0xD04C0000u, 40u}, // mcu -> Latn
-    {0x806C0000u, 40u}, // mda -> Latn
+    {0x6C760000u, 44u}, // lv -> Latn
+    {0xAECB0000u, 87u}, // lwl -> Thai
+    {0x9F2B0000u, 27u}, // lzh -> Hans
+    {0xE72B0000u, 44u}, // lzz -> Latn
+    {0x8C0C0000u, 44u}, // mad -> Latn
+    {0x940C0000u, 44u}, // maf -> Latn
+    {0x980C0000u, 17u}, // mag -> Deva
+    {0xA00C0000u, 17u}, // mai -> Deva
+    {0xA80C0000u, 44u}, // mak -> Latn
+    {0xB40C0000u, 44u}, // man -> Latn
+    {0xB40C474Eu, 58u}, // man-GN -> Nkoo
+    {0xC80C0000u, 44u}, // mas -> Latn
+    {0xD80C0000u, 44u}, // maw -> Latn
+    {0xE40C0000u, 44u}, // maz -> Latn
+    {0x9C2C0000u, 44u}, // mbh -> Latn
+    {0xB82C0000u, 44u}, // mbo -> Latn
+    {0xC02C0000u, 44u}, // mbq -> Latn
+    {0xD02C0000u, 44u}, // mbu -> Latn
+    {0xD82C0000u, 44u}, // mbw -> Latn
+    {0xA04C0000u, 44u}, // mci -> Latn
+    {0xBC4C0000u, 44u}, // mcp -> Latn
+    {0xC04C0000u, 44u}, // mcq -> Latn
+    {0xC44C0000u, 44u}, // mcr -> Latn
+    {0xD04C0000u, 44u}, // mcu -> Latn
+    {0x806C0000u, 44u}, // mda -> Latn
     {0x906C0000u,  1u}, // mde -> Arab
-    {0x946C0000u, 15u}, // mdf -> Cyrl
-    {0x9C6C0000u, 40u}, // mdh -> Latn
-    {0xA46C0000u, 40u}, // mdj -> Latn
-    {0xC46C0000u, 40u}, // mdr -> Latn
-    {0xDC6C0000u, 18u}, // mdx -> Ethi
-    {0x8C8C0000u, 40u}, // med -> Latn
-    {0x908C0000u, 40u}, // mee -> Latn
-    {0xA88C0000u, 40u}, // mek -> Latn
-    {0xB48C0000u, 40u}, // men -> Latn
-    {0xC48C0000u, 40u}, // mer -> Latn
-    {0xCC8C0000u, 40u}, // met -> Latn
-    {0xD08C0000u, 40u}, // meu -> Latn
+    {0x946C0000u, 16u}, // mdf -> Cyrl
+    {0x9C6C0000u, 44u}, // mdh -> Latn
+    {0xA46C0000u, 44u}, // mdj -> Latn
+    {0xC46C0000u, 44u}, // mdr -> Latn
+    {0xDC6C0000u, 19u}, // mdx -> Ethi
+    {0x8C8C0000u, 44u}, // med -> Latn
+    {0x908C0000u, 44u}, // mee -> Latn
+    {0xA88C0000u, 44u}, // mek -> Latn
+    {0xB48C0000u, 44u}, // men -> Latn
+    {0xC48C0000u, 44u}, // mer -> Latn
+    {0xCC8C0000u, 44u}, // met -> Latn
+    {0xD08C0000u, 44u}, // meu -> Latn
     {0x80AC0000u,  1u}, // mfa -> Arab
-    {0x90AC0000u, 40u}, // mfe -> Latn
-    {0xB4AC0000u, 40u}, // mfn -> Latn
-    {0xB8AC0000u, 40u}, // mfo -> Latn
-    {0xC0AC0000u, 40u}, // mfq -> Latn
-    {0x6D670000u, 40u}, // mg -> Latn
-    {0x9CCC0000u, 40u}, // mgh -> Latn
-    {0xACCC0000u, 40u}, // mgl -> Latn
-    {0xB8CC0000u, 40u}, // mgo -> Latn
-    {0xBCCC0000u, 16u}, // mgp -> Deva
-    {0xE0CC0000u, 40u}, // mgy -> Latn
-    {0x6D680000u, 40u}, // mh -> Latn
-    {0xA0EC0000u, 40u}, // mhi -> Latn
-    {0xACEC0000u, 40u}, // mhl -> Latn
-    {0x6D690000u, 40u}, // mi -> Latn
-    {0x950C0000u, 40u}, // mif -> Latn
-    {0xB50C0000u, 40u}, // min -> Latn
-    {0xC90C0000u, 26u}, // mis -> Hatr
-    {0xD90C0000u, 40u}, // miw -> Latn
-    {0x6D6B0000u, 15u}, // mk -> Cyrl
+    {0x90AC0000u, 44u}, // mfe -> Latn
+    {0xB4AC0000u, 44u}, // mfn -> Latn
+    {0xB8AC0000u, 44u}, // mfo -> Latn
+    {0xC0AC0000u, 44u}, // mfq -> Latn
+    {0x6D670000u, 44u}, // mg -> Latn
+    {0x9CCC0000u, 44u}, // mgh -> Latn
+    {0xACCC0000u, 44u}, // mgl -> Latn
+    {0xB8CC0000u, 44u}, // mgo -> Latn
+    {0xBCCC0000u, 17u}, // mgp -> Deva
+    {0xE0CC0000u, 44u}, // mgy -> Latn
+    {0x6D680000u, 44u}, // mh -> Latn
+    {0xA0EC0000u, 44u}, // mhi -> Latn
+    {0xACEC0000u, 44u}, // mhl -> Latn
+    {0x6D690000u, 44u}, // mi -> Latn
+    {0x950C0000u, 44u}, // mif -> Latn
+    {0xB50C0000u, 44u}, // min -> Latn
+    {0xC90C0000u, 29u}, // mis -> Hatr
+    {0xD90C0000u, 44u}, // miw -> Latn
+    {0x6D6B0000u, 16u}, // mk -> Cyrl
     {0xA14C0000u,  1u}, // mki -> Arab
-    {0xAD4C0000u, 40u}, // mkl -> Latn
-    {0xBD4C0000u, 40u}, // mkp -> Latn
-    {0xD94C0000u, 40u}, // mkw -> Latn
-    {0x6D6C0000u, 49u}, // ml -> Mlym
-    {0x916C0000u, 40u}, // mle -> Latn
-    {0xBD6C0000u, 40u}, // mlp -> Latn
-    {0xC96C0000u, 40u}, // mls -> Latn
-    {0xB98C0000u, 40u}, // mmo -> Latn
-    {0xD18C0000u, 40u}, // mmu -> Latn
-    {0xDD8C0000u, 40u}, // mmx -> Latn
-    {0x6D6E0000u, 15u}, // mn -> Cyrl
-    {0x6D6E434Eu, 50u}, // mn-CN -> Mong
-    {0x81AC0000u, 40u}, // mna -> Latn
-    {0x95AC0000u, 40u}, // mnf -> Latn
+    {0xAD4C0000u, 44u}, // mkl -> Latn
+    {0xBD4C0000u, 44u}, // mkp -> Latn
+    {0xD94C0000u, 44u}, // mkw -> Latn
+    {0x6D6C0000u, 53u}, // ml -> Mlym
+    {0x916C0000u, 44u}, // mle -> Latn
+    {0xBD6C0000u, 44u}, // mlp -> Latn
+    {0xC96C0000u, 44u}, // mls -> Latn
+    {0xB98C0000u, 44u}, // mmo -> Latn
+    {0xD18C0000u, 44u}, // mmu -> Latn
+    {0xDD8C0000u, 44u}, // mmx -> Latn
+    {0x6D6E0000u, 16u}, // mn -> Cyrl
+    {0x6D6E434Eu, 54u}, // mn-CN -> Mong
+    {0x81AC0000u, 44u}, // mna -> Latn
+    {0x95AC0000u, 44u}, // mnf -> Latn
     {0xA1AC0000u,  7u}, // mni -> Beng
-    {0xD9AC0000u, 52u}, // mnw -> Mymr
-    {0x81CC0000u, 40u}, // moa -> Latn
-    {0x91CC0000u, 40u}, // moe -> Latn
-    {0x9DCC0000u, 40u}, // moh -> Latn
-    {0xC9CC0000u, 40u}, // mos -> Latn
-    {0xDDCC0000u, 40u}, // mox -> Latn
-    {0xBDEC0000u, 40u}, // mpp -> Latn
-    {0xC9EC0000u, 40u}, // mps -> Latn
-    {0xCDEC0000u, 40u}, // mpt -> Latn
-    {0xDDEC0000u, 40u}, // mpx -> Latn
-    {0xAE0C0000u, 40u}, // mql -> Latn
-    {0x6D720000u, 16u}, // mr -> Deva
-    {0x8E2C0000u, 16u}, // mrd -> Deva
-    {0xA62C0000u, 15u}, // mrj -> Cyrl
-    {0xBA2C0000u, 51u}, // mro -> Mroo
-    {0x6D730000u, 40u}, // ms -> Latn
+    {0xD9AC0000u, 56u}, // mnw -> Mymr
+    {0x81CC0000u, 44u}, // moa -> Latn
+    {0x91CC0000u, 44u}, // moe -> Latn
+    {0x9DCC0000u, 44u}, // moh -> Latn
+    {0xC9CC0000u, 44u}, // mos -> Latn
+    {0xDDCC0000u, 44u}, // mox -> Latn
+    {0xBDEC0000u, 44u}, // mpp -> Latn
+    {0xC9EC0000u, 44u}, // mps -> Latn
+    {0xCDEC0000u, 44u}, // mpt -> Latn
+    {0xDDEC0000u, 44u}, // mpx -> Latn
+    {0xAE0C0000u, 44u}, // mql -> Latn
+    {0x6D720000u, 17u}, // mr -> Deva
+    {0x8E2C0000u, 17u}, // mrd -> Deva
+    {0xA62C0000u, 16u}, // mrj -> Cyrl
+    {0xBA2C0000u, 55u}, // mro -> Mroo
+    {0x6D730000u, 44u}, // ms -> Latn
     {0x6D734343u,  1u}, // ms-CC -> Arab
     {0x6D734944u,  1u}, // ms-ID -> Arab
-    {0x6D740000u, 40u}, // mt -> Latn
-    {0x8A6C0000u, 40u}, // mtc -> Latn
-    {0x966C0000u, 40u}, // mtf -> Latn
-    {0xA26C0000u, 40u}, // mti -> Latn
-    {0xC66C0000u, 16u}, // mtr -> Deva
-    {0x828C0000u, 40u}, // mua -> Latn
-    {0xC68C0000u, 40u}, // mur -> Latn
-    {0xCA8C0000u, 40u}, // mus -> Latn
-    {0x82AC0000u, 40u}, // mva -> Latn
-    {0xB6AC0000u, 40u}, // mvn -> Latn
+    {0x6D740000u, 44u}, // mt -> Latn
+    {0x8A6C0000u, 44u}, // mtc -> Latn
+    {0x966C0000u, 44u}, // mtf -> Latn
+    {0xA26C0000u, 44u}, // mti -> Latn
+    {0xC66C0000u, 17u}, // mtr -> Deva
+    {0x828C0000u, 44u}, // mua -> Latn
+    {0xC68C0000u, 44u}, // mur -> Latn
+    {0xCA8C0000u, 44u}, // mus -> Latn
+    {0x82AC0000u, 44u}, // mva -> Latn
+    {0xB6AC0000u, 44u}, // mvn -> Latn
     {0xE2AC0000u,  1u}, // mvy -> Arab
-    {0xAACC0000u, 40u}, // mwk -> Latn
-    {0xC6CC0000u, 16u}, // mwr -> Deva
-    {0xD6CC0000u, 40u}, // mwv -> Latn
-    {0x8AEC0000u, 40u}, // mxc -> Latn
-    {0xB2EC0000u, 40u}, // mxm -> Latn
-    {0x6D790000u, 52u}, // my -> Mymr
-    {0xAB0C0000u, 40u}, // myk -> Latn
-    {0xB30C0000u, 18u}, // mym -> Ethi
-    {0xD70C0000u, 15u}, // myv -> Cyrl
-    {0xDB0C0000u, 40u}, // myw -> Latn
-    {0xDF0C0000u, 40u}, // myx -> Latn
-    {0xE70C0000u, 46u}, // myz -> Mand
-    {0xAB2C0000u, 40u}, // mzk -> Latn
-    {0xB32C0000u, 40u}, // mzm -> Latn
+    {0xAACC0000u, 44u}, // mwk -> Latn
+    {0xC6CC0000u, 17u}, // mwr -> Deva
+    {0xD6CC0000u, 44u}, // mwv -> Latn
+    {0xDACC0000u, 33u}, // mww -> Hmnp
+    {0x8AEC0000u, 44u}, // mxc -> Latn
+    {0xB2EC0000u, 44u}, // mxm -> Latn
+    {0x6D790000u, 56u}, // my -> Mymr
+    {0xAB0C0000u, 44u}, // myk -> Latn
+    {0xB30C0000u, 19u}, // mym -> Ethi
+    {0xD70C0000u, 16u}, // myv -> Cyrl
+    {0xDB0C0000u, 44u}, // myw -> Latn
+    {0xDF0C0000u, 44u}, // myx -> Latn
+    {0xE70C0000u, 50u}, // myz -> Mand
+    {0xAB2C0000u, 44u}, // mzk -> Latn
+    {0xB32C0000u, 44u}, // mzm -> Latn
     {0xB72C0000u,  1u}, // mzn -> Arab
-    {0xBF2C0000u, 40u}, // mzp -> Latn
-    {0xDB2C0000u, 40u}, // mzw -> Latn
-    {0xE72C0000u, 40u}, // mzz -> Latn
-    {0x6E610000u, 40u}, // na -> Latn
-    {0x880D0000u, 40u}, // nac -> Latn
-    {0x940D0000u, 40u}, // naf -> Latn
-    {0xA80D0000u, 40u}, // nak -> Latn
-    {0xB40D0000u, 24u}, // nan -> Hans
-    {0xBC0D0000u, 40u}, // nap -> Latn
-    {0xC00D0000u, 40u}, // naq -> Latn
-    {0xC80D0000u, 40u}, // nas -> Latn
-    {0x6E620000u, 40u}, // nb -> Latn
-    {0x804D0000u, 40u}, // nca -> Latn
-    {0x904D0000u, 40u}, // nce -> Latn
-    {0x944D0000u, 40u}, // ncf -> Latn
-    {0x9C4D0000u, 40u}, // nch -> Latn
-    {0xB84D0000u, 40u}, // nco -> Latn
-    {0xD04D0000u, 40u}, // ncu -> Latn
-    {0x6E640000u, 40u}, // nd -> Latn
-    {0x886D0000u, 40u}, // ndc -> Latn
-    {0xC86D0000u, 40u}, // nds -> Latn
-    {0x6E650000u, 16u}, // ne -> Deva
-    {0x848D0000u, 40u}, // neb -> Latn
-    {0xD88D0000u, 16u}, // new -> Deva
-    {0xDC8D0000u, 40u}, // nex -> Latn
-    {0xC4AD0000u, 40u}, // nfr -> Latn
-    {0x6E670000u, 40u}, // ng -> Latn
-    {0x80CD0000u, 40u}, // nga -> Latn
-    {0x84CD0000u, 40u}, // ngb -> Latn
-    {0xACCD0000u, 40u}, // ngl -> Latn
-    {0x84ED0000u, 40u}, // nhb -> Latn
-    {0x90ED0000u, 40u}, // nhe -> Latn
-    {0xD8ED0000u, 40u}, // nhw -> Latn
-    {0x950D0000u, 40u}, // nif -> Latn
-    {0xA10D0000u, 40u}, // nii -> Latn
-    {0xA50D0000u, 40u}, // nij -> Latn
-    {0xB50D0000u, 40u}, // nin -> Latn
-    {0xD10D0000u, 40u}, // niu -> Latn
-    {0xE10D0000u, 40u}, // niy -> Latn
-    {0xE50D0000u, 40u}, // niz -> Latn
-    {0xB92D0000u, 40u}, // njo -> Latn
-    {0x994D0000u, 40u}, // nkg -> Latn
-    {0xB94D0000u, 40u}, // nko -> Latn
-    {0x6E6C0000u, 40u}, // nl -> Latn
-    {0x998D0000u, 40u}, // nmg -> Latn
-    {0xE58D0000u, 40u}, // nmz -> Latn
-    {0x6E6E0000u, 40u}, // nn -> Latn
-    {0x95AD0000u, 40u}, // nnf -> Latn
-    {0x9DAD0000u, 40u}, // nnh -> Latn
-    {0xA9AD0000u, 40u}, // nnk -> Latn
-    {0xB1AD0000u, 40u}, // nnm -> Latn
-    {0x6E6F0000u, 40u}, // no -> Latn
-    {0x8DCD0000u, 38u}, // nod -> Lana
-    {0x91CD0000u, 16u}, // noe -> Deva
-    {0xB5CD0000u, 64u}, // non -> Runr
-    {0xBDCD0000u, 40u}, // nop -> Latn
-    {0xD1CD0000u, 40u}, // nou -> Latn
-    {0xBA0D0000u, 54u}, // nqo -> Nkoo
-    {0x6E720000u, 40u}, // nr -> Latn
-    {0x862D0000u, 40u}, // nrb -> Latn
-    {0xAA4D0000u,  9u}, // nsk -> Cans
-    {0xB64D0000u, 40u}, // nsn -> Latn
-    {0xBA4D0000u, 40u}, // nso -> Latn
-    {0xCA4D0000u, 40u}, // nss -> Latn
-    {0xB26D0000u, 40u}, // ntm -> Latn
-    {0xC66D0000u, 40u}, // ntr -> Latn
-    {0xA28D0000u, 40u}, // nui -> Latn
-    {0xBE8D0000u, 40u}, // nup -> Latn
-    {0xCA8D0000u, 40u}, // nus -> Latn
-    {0xD68D0000u, 40u}, // nuv -> Latn
-    {0xDE8D0000u, 40u}, // nux -> Latn
-    {0x6E760000u, 40u}, // nv -> Latn
-    {0x86CD0000u, 40u}, // nwb -> Latn
-    {0xC2ED0000u, 40u}, // nxq -> Latn
-    {0xC6ED0000u, 40u}, // nxr -> Latn
-    {0x6E790000u, 40u}, // ny -> Latn
-    {0xB30D0000u, 40u}, // nym -> Latn
-    {0xB70D0000u, 40u}, // nyn -> Latn
-    {0xA32D0000u, 40u}, // nzi -> Latn
-    {0x6F630000u, 40u}, // oc -> Latn
-    {0x88CE0000u, 40u}, // ogc -> Latn
-    {0xC54E0000u, 40u}, // okr -> Latn
-    {0xD54E0000u, 40u}, // okv -> Latn
-    {0x6F6D0000u, 40u}, // om -> Latn
-    {0x99AE0000u, 40u}, // ong -> Latn
-    {0xB5AE0000u, 40u}, // onn -> Latn
-    {0xC9AE0000u, 40u}, // ons -> Latn
-    {0xB1EE0000u, 40u}, // opm -> Latn
-    {0x6F720000u, 57u}, // or -> Orya
-    {0xBA2E0000u, 40u}, // oro -> Latn
+    {0xBF2C0000u, 44u}, // mzp -> Latn
+    {0xDB2C0000u, 44u}, // mzw -> Latn
+    {0xE72C0000u, 44u}, // mzz -> Latn
+    {0x6E610000u, 44u}, // na -> Latn
+    {0x880D0000u, 44u}, // nac -> Latn
+    {0x940D0000u, 44u}, // naf -> Latn
+    {0xA80D0000u, 44u}, // nak -> Latn
+    {0xB40D0000u, 27u}, // nan -> Hans
+    {0xBC0D0000u, 44u}, // nap -> Latn
+    {0xC00D0000u, 44u}, // naq -> Latn
+    {0xC80D0000u, 44u}, // nas -> Latn
+    {0x6E620000u, 44u}, // nb -> Latn
+    {0x804D0000u, 44u}, // nca -> Latn
+    {0x904D0000u, 44u}, // nce -> Latn
+    {0x944D0000u, 44u}, // ncf -> Latn
+    {0x9C4D0000u, 44u}, // nch -> Latn
+    {0xB84D0000u, 44u}, // nco -> Latn
+    {0xD04D0000u, 44u}, // ncu -> Latn
+    {0x6E640000u, 44u}, // nd -> Latn
+    {0x886D0000u, 44u}, // ndc -> Latn
+    {0xC86D0000u, 44u}, // nds -> Latn
+    {0x6E650000u, 17u}, // ne -> Deva
+    {0x848D0000u, 44u}, // neb -> Latn
+    {0xD88D0000u, 17u}, // new -> Deva
+    {0xDC8D0000u, 44u}, // nex -> Latn
+    {0xC4AD0000u, 44u}, // nfr -> Latn
+    {0x6E670000u, 44u}, // ng -> Latn
+    {0x80CD0000u, 44u}, // nga -> Latn
+    {0x84CD0000u, 44u}, // ngb -> Latn
+    {0xACCD0000u, 44u}, // ngl -> Latn
+    {0x84ED0000u, 44u}, // nhb -> Latn
+    {0x90ED0000u, 44u}, // nhe -> Latn
+    {0xD8ED0000u, 44u}, // nhw -> Latn
+    {0x950D0000u, 44u}, // nif -> Latn
+    {0xA10D0000u, 44u}, // nii -> Latn
+    {0xA50D0000u, 44u}, // nij -> Latn
+    {0xB50D0000u, 44u}, // nin -> Latn
+    {0xD10D0000u, 44u}, // niu -> Latn
+    {0xE10D0000u, 44u}, // niy -> Latn
+    {0xE50D0000u, 44u}, // niz -> Latn
+    {0xB92D0000u, 44u}, // njo -> Latn
+    {0x994D0000u, 44u}, // nkg -> Latn
+    {0xB94D0000u, 44u}, // nko -> Latn
+    {0x6E6C0000u, 44u}, // nl -> Latn
+    {0x998D0000u, 44u}, // nmg -> Latn
+    {0xE58D0000u, 44u}, // nmz -> Latn
+    {0x6E6E0000u, 44u}, // nn -> Latn
+    {0x95AD0000u, 44u}, // nnf -> Latn
+    {0x9DAD0000u, 44u}, // nnh -> Latn
+    {0xA9AD0000u, 44u}, // nnk -> Latn
+    {0xB1AD0000u, 44u}, // nnm -> Latn
+    {0xBDAD0000u, 91u}, // nnp -> Wcho
+    {0x6E6F0000u, 44u}, // no -> Latn
+    {0x8DCD0000u, 42u}, // nod -> Lana
+    {0x91CD0000u, 17u}, // noe -> Deva
+    {0xB5CD0000u, 69u}, // non -> Runr
+    {0xBDCD0000u, 44u}, // nop -> Latn
+    {0xD1CD0000u, 44u}, // nou -> Latn
+    {0xBA0D0000u, 58u}, // nqo -> Nkoo
+    {0x6E720000u, 44u}, // nr -> Latn
+    {0x862D0000u, 44u}, // nrb -> Latn
+    {0xAA4D0000u, 10u}, // nsk -> Cans
+    {0xB64D0000u, 44u}, // nsn -> Latn
+    {0xBA4D0000u, 44u}, // nso -> Latn
+    {0xCA4D0000u, 44u}, // nss -> Latn
+    {0xB26D0000u, 44u}, // ntm -> Latn
+    {0xC66D0000u, 44u}, // ntr -> Latn
+    {0xA28D0000u, 44u}, // nui -> Latn
+    {0xBE8D0000u, 44u}, // nup -> Latn
+    {0xCA8D0000u, 44u}, // nus -> Latn
+    {0xD68D0000u, 44u}, // nuv -> Latn
+    {0xDE8D0000u, 44u}, // nux -> Latn
+    {0x6E760000u, 44u}, // nv -> Latn
+    {0x86CD0000u, 44u}, // nwb -> Latn
+    {0xC2ED0000u, 44u}, // nxq -> Latn
+    {0xC6ED0000u, 44u}, // nxr -> Latn
+    {0x6E790000u, 44u}, // ny -> Latn
+    {0xB30D0000u, 44u}, // nym -> Latn
+    {0xB70D0000u, 44u}, // nyn -> Latn
+    {0xA32D0000u, 44u}, // nzi -> Latn
+    {0x6F630000u, 44u}, // oc -> Latn
+    {0x88CE0000u, 44u}, // ogc -> Latn
+    {0xC54E0000u, 44u}, // okr -> Latn
+    {0xD54E0000u, 44u}, // okv -> Latn
+    {0x6F6D0000u, 44u}, // om -> Latn
+    {0x99AE0000u, 44u}, // ong -> Latn
+    {0xB5AE0000u, 44u}, // onn -> Latn
+    {0xC9AE0000u, 44u}, // ons -> Latn
+    {0xB1EE0000u, 44u}, // opm -> Latn
+    {0x6F720000u, 62u}, // or -> Orya
+    {0xBA2E0000u, 44u}, // oro -> Latn
     {0xD22E0000u,  1u}, // oru -> Arab
-    {0x6F730000u, 15u}, // os -> Cyrl
-    {0x824E0000u, 58u}, // osa -> Osge
+    {0x6F730000u, 16u}, // os -> Cyrl
+    {0x824E0000u, 63u}, // osa -> Osge
     {0x826E0000u,  1u}, // ota -> Arab
-    {0xAA6E0000u, 56u}, // otk -> Orkh
-    {0xB32E0000u, 40u}, // ozm -> Latn
-    {0x70610000u, 23u}, // pa -> Guru
+    {0xAA6E0000u, 61u}, // otk -> Orkh
+    {0xB32E0000u, 44u}, // ozm -> Latn
+    {0x70610000u, 26u}, // pa -> Guru
     {0x7061504Bu,  1u}, // pa-PK -> Arab
-    {0x980F0000u, 40u}, // pag -> Latn
-    {0xAC0F0000u, 60u}, // pal -> Phli
-    {0xB00F0000u, 40u}, // pam -> Latn
-    {0xBC0F0000u, 40u}, // pap -> Latn
-    {0xD00F0000u, 40u}, // pau -> Latn
-    {0xA02F0000u, 40u}, // pbi -> Latn
-    {0x8C4F0000u, 40u}, // pcd -> Latn
-    {0xB04F0000u, 40u}, // pcm -> Latn
-    {0x886F0000u, 40u}, // pdc -> Latn
-    {0xCC6F0000u, 40u}, // pdt -> Latn
-    {0x8C8F0000u, 40u}, // ped -> Latn
-    {0xB88F0000u, 84u}, // peo -> Xpeo
-    {0xDC8F0000u, 40u}, // pex -> Latn
-    {0xACAF0000u, 40u}, // pfl -> Latn
+    {0x980F0000u, 44u}, // pag -> Latn
+    {0xAC0F0000u, 65u}, // pal -> Phli
+    {0xB00F0000u, 44u}, // pam -> Latn
+    {0xBC0F0000u, 44u}, // pap -> Latn
+    {0xD00F0000u, 44u}, // pau -> Latn
+    {0xA02F0000u, 44u}, // pbi -> Latn
+    {0x8C4F0000u, 44u}, // pcd -> Latn
+    {0xB04F0000u, 44u}, // pcm -> Latn
+    {0x886F0000u, 44u}, // pdc -> Latn
+    {0xCC6F0000u, 44u}, // pdt -> Latn
+    {0x8C8F0000u, 44u}, // ped -> Latn
+    {0xB88F0000u, 92u}, // peo -> Xpeo
+    {0xDC8F0000u, 44u}, // pex -> Latn
+    {0xACAF0000u, 44u}, // pfl -> Latn
     {0xACEF0000u,  1u}, // phl -> Arab
-    {0xB4EF0000u, 61u}, // phn -> Phnx
-    {0xAD0F0000u, 40u}, // pil -> Latn
-    {0xBD0F0000u, 40u}, // pip -> Latn
+    {0xB4EF0000u, 66u}, // phn -> Phnx
+    {0xAD0F0000u, 44u}, // pil -> Latn
+    {0xBD0F0000u, 44u}, // pip -> Latn
     {0x814F0000u,  8u}, // pka -> Brah
-    {0xB94F0000u, 40u}, // pko -> Latn
-    {0x706C0000u, 40u}, // pl -> Latn
-    {0x816F0000u, 40u}, // pla -> Latn
-    {0xC98F0000u, 40u}, // pms -> Latn
-    {0x99AF0000u, 40u}, // png -> Latn
-    {0xB5AF0000u, 40u}, // pnn -> Latn
-    {0xCDAF0000u, 21u}, // pnt -> Grek
-    {0xB5CF0000u, 40u}, // pon -> Latn
-    {0xB9EF0000u, 40u}, // ppo -> Latn
-    {0x822F0000u, 34u}, // pra -> Khar
+    {0xB94F0000u, 44u}, // pko -> Latn
+    {0x706C0000u, 44u}, // pl -> Latn
+    {0x816F0000u, 44u}, // pla -> Latn
+    {0xC98F0000u, 44u}, // pms -> Latn
+    {0x99AF0000u, 44u}, // png -> Latn
+    {0xB5AF0000u, 44u}, // pnn -> Latn
+    {0xCDAF0000u, 24u}, // pnt -> Grek
+    {0xB5CF0000u, 44u}, // pon -> Latn
+    {0xB9EF0000u, 44u}, // ppo -> Latn
+    {0x822F0000u, 38u}, // pra -> Khar
     {0x8E2F0000u,  1u}, // prd -> Arab
-    {0x9A2F0000u, 40u}, // prg -> Latn
+    {0x9A2F0000u, 44u}, // prg -> Latn
     {0x70730000u,  1u}, // ps -> Arab
-    {0xCA4F0000u, 40u}, // pss -> Latn
-    {0x70740000u, 40u}, // pt -> Latn
-    {0xBE6F0000u, 40u}, // ptp -> Latn
-    {0xD28F0000u, 40u}, // puu -> Latn
-    {0x82CF0000u, 40u}, // pwa -> Latn
-    {0x71750000u, 40u}, // qu -> Latn
-    {0x8A900000u, 40u}, // quc -> Latn
-    {0x9A900000u, 40u}, // qug -> Latn
-    {0xA0110000u, 40u}, // rai -> Latn
-    {0xA4110000u, 16u}, // raj -> Deva
-    {0xB8110000u, 40u}, // rao -> Latn
-    {0x94510000u, 40u}, // rcf -> Latn
-    {0xA4910000u, 40u}, // rej -> Latn
-    {0xAC910000u, 40u}, // rel -> Latn
-    {0xC8910000u, 40u}, // res -> Latn
-    {0xB4D10000u, 40u}, // rgn -> Latn
+    {0xCA4F0000u, 44u}, // pss -> Latn
+    {0x70740000u, 44u}, // pt -> Latn
+    {0xBE6F0000u, 44u}, // ptp -> Latn
+    {0xD28F0000u, 44u}, // puu -> Latn
+    {0x82CF0000u, 44u}, // pwa -> Latn
+    {0x71750000u, 44u}, // qu -> Latn
+    {0x8A900000u, 44u}, // quc -> Latn
+    {0x9A900000u, 44u}, // qug -> Latn
+    {0xA0110000u, 44u}, // rai -> Latn
+    {0xA4110000u, 17u}, // raj -> Deva
+    {0xB8110000u, 44u}, // rao -> Latn
+    {0x94510000u, 44u}, // rcf -> Latn
+    {0xA4910000u, 44u}, // rej -> Latn
+    {0xAC910000u, 44u}, // rel -> Latn
+    {0xC8910000u, 44u}, // res -> Latn
+    {0xB4D10000u, 44u}, // rgn -> Latn
     {0x98F10000u,  1u}, // rhg -> Arab
-    {0x81110000u, 40u}, // ria -> Latn
-    {0x95110000u, 78u}, // rif -> Tfng
-    {0x95114E4Cu, 40u}, // rif-NL -> Latn
-    {0xC9310000u, 16u}, // rjs -> Deva
+    {0x81110000u, 44u}, // ria -> Latn
+    {0x95110000u, 85u}, // rif -> Tfng
+    {0x95114E4Cu, 44u}, // rif-NL -> Latn
+    {0xC9310000u, 17u}, // rjs -> Deva
     {0xCD510000u,  7u}, // rkt -> Beng
-    {0x726D0000u, 40u}, // rm -> Latn
-    {0x95910000u, 40u}, // rmf -> Latn
-    {0xB9910000u, 40u}, // rmo -> Latn
+    {0x726D0000u, 44u}, // rm -> Latn
+    {0x95910000u, 44u}, // rmf -> Latn
+    {0xB9910000u, 44u}, // rmo -> Latn
     {0xCD910000u,  1u}, // rmt -> Arab
-    {0xD1910000u, 40u}, // rmu -> Latn
-    {0x726E0000u, 40u}, // rn -> Latn
-    {0x81B10000u, 40u}, // rna -> Latn
-    {0x99B10000u, 40u}, // rng -> Latn
-    {0x726F0000u, 40u}, // ro -> Latn
-    {0x85D10000u, 40u}, // rob -> Latn
-    {0x95D10000u, 40u}, // rof -> Latn
-    {0xB9D10000u, 40u}, // roo -> Latn
-    {0xBA310000u, 40u}, // rro -> Latn
-    {0xB2710000u, 40u}, // rtm -> Latn
-    {0x72750000u, 15u}, // ru -> Cyrl
-    {0x92910000u, 15u}, // rue -> Cyrl
-    {0x9A910000u, 40u}, // rug -> Latn
-    {0x72770000u, 40u}, // rw -> Latn
-    {0xAAD10000u, 40u}, // rwk -> Latn
-    {0xBAD10000u, 40u}, // rwo -> Latn
-    {0xD3110000u, 33u}, // ryu -> Kana
-    {0x73610000u, 16u}, // sa -> Deva
-    {0x94120000u, 40u}, // saf -> Latn
-    {0x9C120000u, 15u}, // sah -> Cyrl
-    {0xC0120000u, 40u}, // saq -> Latn
-    {0xC8120000u, 40u}, // sas -> Latn
-    {0xCC120000u, 40u}, // sat -> Latn
-    {0xE4120000u, 67u}, // saz -> Saur
-    {0x80320000u, 40u}, // sba -> Latn
-    {0x90320000u, 40u}, // sbe -> Latn
-    {0xBC320000u, 40u}, // sbp -> Latn
-    {0x73630000u, 40u}, // sc -> Latn
-    {0xA8520000u, 16u}, // sck -> Deva
+    {0xD1910000u, 44u}, // rmu -> Latn
+    {0x726E0000u, 44u}, // rn -> Latn
+    {0x81B10000u, 44u}, // rna -> Latn
+    {0x99B10000u, 44u}, // rng -> Latn
+    {0x726F0000u, 44u}, // ro -> Latn
+    {0x85D10000u, 44u}, // rob -> Latn
+    {0x95D10000u, 44u}, // rof -> Latn
+    {0xB9D10000u, 44u}, // roo -> Latn
+    {0xBA310000u, 44u}, // rro -> Latn
+    {0xB2710000u, 44u}, // rtm -> Latn
+    {0x72750000u, 16u}, // ru -> Cyrl
+    {0x92910000u, 16u}, // rue -> Cyrl
+    {0x9A910000u, 44u}, // rug -> Latn
+    {0x72770000u, 44u}, // rw -> Latn
+    {0xAAD10000u, 44u}, // rwk -> Latn
+    {0xBAD10000u, 44u}, // rwo -> Latn
+    {0xD3110000u, 37u}, // ryu -> Kana
+    {0x73610000u, 17u}, // sa -> Deva
+    {0x94120000u, 44u}, // saf -> Latn
+    {0x9C120000u, 16u}, // sah -> Cyrl
+    {0xC0120000u, 44u}, // saq -> Latn
+    {0xC8120000u, 44u}, // sas -> Latn
+    {0xCC120000u, 44u}, // sat -> Latn
+    {0xD4120000u, 44u}, // sav -> Latn
+    {0xE4120000u, 72u}, // saz -> Saur
+    {0x80320000u, 44u}, // sba -> Latn
+    {0x90320000u, 44u}, // sbe -> Latn
+    {0xBC320000u, 44u}, // sbp -> Latn
+    {0x73630000u, 44u}, // sc -> Latn
+    {0xA8520000u, 17u}, // sck -> Deva
     {0xAC520000u,  1u}, // scl -> Arab
-    {0xB4520000u, 40u}, // scn -> Latn
-    {0xB8520000u, 40u}, // sco -> Latn
-    {0xC8520000u, 40u}, // scs -> Latn
+    {0xB4520000u, 44u}, // scn -> Latn
+    {0xB8520000u, 44u}, // sco -> Latn
+    {0xC8520000u, 44u}, // scs -> Latn
     {0x73640000u,  1u}, // sd -> Arab
-    {0x88720000u, 40u}, // sdc -> Latn
+    {0x88720000u, 44u}, // sdc -> Latn
     {0x9C720000u,  1u}, // sdh -> Arab
-    {0x73650000u, 40u}, // se -> Latn
-    {0x94920000u, 40u}, // sef -> Latn
-    {0x9C920000u, 40u}, // seh -> Latn
-    {0xA0920000u, 40u}, // sei -> Latn
-    {0xC8920000u, 40u}, // ses -> Latn
-    {0x73670000u, 40u}, // sg -> Latn
-    {0x80D20000u, 55u}, // sga -> Ogam
-    {0xC8D20000u, 40u}, // sgs -> Latn
-    {0xD8D20000u, 18u}, // sgw -> Ethi
-    {0xE4D20000u, 40u}, // sgz -> Latn
-    {0x73680000u, 40u}, // sh -> Latn
-    {0xA0F20000u, 78u}, // shi -> Tfng
-    {0xA8F20000u, 40u}, // shk -> Latn
-    {0xB4F20000u, 52u}, // shn -> Mymr
+    {0x73650000u, 44u}, // se -> Latn
+    {0x94920000u, 44u}, // sef -> Latn
+    {0x9C920000u, 44u}, // seh -> Latn
+    {0xA0920000u, 44u}, // sei -> Latn
+    {0xC8920000u, 44u}, // ses -> Latn
+    {0x73670000u, 44u}, // sg -> Latn
+    {0x80D20000u, 60u}, // sga -> Ogam
+    {0xC8D20000u, 44u}, // sgs -> Latn
+    {0xD8D20000u, 19u}, // sgw -> Ethi
+    {0xE4D20000u, 44u}, // sgz -> Latn
+    {0x73680000u, 44u}, // sh -> Latn
+    {0xA0F20000u, 85u}, // shi -> Tfng
+    {0xA8F20000u, 44u}, // shk -> Latn
+    {0xB4F20000u, 56u}, // shn -> Mymr
     {0xD0F20000u,  1u}, // shu -> Arab
-    {0x73690000u, 69u}, // si -> Sinh
-    {0x8D120000u, 40u}, // sid -> Latn
-    {0x99120000u, 40u}, // sig -> Latn
-    {0xAD120000u, 40u}, // sil -> Latn
-    {0xB1120000u, 40u}, // sim -> Latn
-    {0xC5320000u, 40u}, // sjr -> Latn
-    {0x736B0000u, 40u}, // sk -> Latn
-    {0x89520000u, 40u}, // skc -> Latn
+    {0x73690000u, 74u}, // si -> Sinh
+    {0x8D120000u, 44u}, // sid -> Latn
+    {0x99120000u, 44u}, // sig -> Latn
+    {0xAD120000u, 44u}, // sil -> Latn
+    {0xB1120000u, 44u}, // sim -> Latn
+    {0xC5320000u, 44u}, // sjr -> Latn
+    {0x736B0000u, 44u}, // sk -> Latn
+    {0x89520000u, 44u}, // skc -> Latn
     {0xC5520000u,  1u}, // skr -> Arab
-    {0xC9520000u, 40u}, // sks -> Latn
-    {0x736C0000u, 40u}, // sl -> Latn
-    {0x8D720000u, 40u}, // sld -> Latn
-    {0xA1720000u, 40u}, // sli -> Latn
-    {0xAD720000u, 40u}, // sll -> Latn
-    {0xE1720000u, 40u}, // sly -> Latn
-    {0x736D0000u, 40u}, // sm -> Latn
-    {0x81920000u, 40u}, // sma -> Latn
-    {0xA5920000u, 40u}, // smj -> Latn
-    {0xB5920000u, 40u}, // smn -> Latn
-    {0xBD920000u, 65u}, // smp -> Samr
-    {0xC1920000u, 40u}, // smq -> Latn
-    {0xC9920000u, 40u}, // sms -> Latn
-    {0x736E0000u, 40u}, // sn -> Latn
-    {0x89B20000u, 40u}, // snc -> Latn
-    {0xA9B20000u, 40u}, // snk -> Latn
-    {0xBDB20000u, 40u}, // snp -> Latn
-    {0xDDB20000u, 40u}, // snx -> Latn
-    {0xE1B20000u, 40u}, // sny -> Latn
-    {0x736F0000u, 40u}, // so -> Latn
-    {0xA9D20000u, 40u}, // sok -> Latn
-    {0xC1D20000u, 40u}, // soq -> Latn
-    {0xD1D20000u, 80u}, // sou -> Thai
-    {0xE1D20000u, 40u}, // soy -> Latn
-    {0x8DF20000u, 40u}, // spd -> Latn
-    {0xADF20000u, 40u}, // spl -> Latn
-    {0xC9F20000u, 40u}, // sps -> Latn
-    {0x73710000u, 40u}, // sq -> Latn
-    {0x73720000u, 15u}, // sr -> Cyrl
-    {0x73724D45u, 40u}, // sr-ME -> Latn
-    {0x7372524Fu, 40u}, // sr-RO -> Latn
-    {0x73725255u, 40u}, // sr-RU -> Latn
-    {0x73725452u, 40u}, // sr-TR -> Latn
-    {0x86320000u, 70u}, // srb -> Sora
-    {0xB6320000u, 40u}, // srn -> Latn
-    {0xC6320000u, 40u}, // srr -> Latn
-    {0xDE320000u, 16u}, // srx -> Deva
-    {0x73730000u, 40u}, // ss -> Latn
-    {0x8E520000u, 40u}, // ssd -> Latn
-    {0x9A520000u, 40u}, // ssg -> Latn
-    {0xE2520000u, 40u}, // ssy -> Latn
-    {0x73740000u, 40u}, // st -> Latn
-    {0xAA720000u, 40u}, // stk -> Latn
-    {0xC2720000u, 40u}, // stq -> Latn
-    {0x73750000u, 40u}, // su -> Latn
-    {0x82920000u, 40u}, // sua -> Latn
-    {0x92920000u, 40u}, // sue -> Latn
-    {0xAA920000u, 40u}, // suk -> Latn
-    {0xC6920000u, 40u}, // sur -> Latn
-    {0xCA920000u, 40u}, // sus -> Latn
-    {0x73760000u, 40u}, // sv -> Latn
-    {0x73770000u, 40u}, // sw -> Latn
+    {0xC9520000u, 44u}, // sks -> Latn
+    {0x736C0000u, 44u}, // sl -> Latn
+    {0x8D720000u, 44u}, // sld -> Latn
+    {0xA1720000u, 44u}, // sli -> Latn
+    {0xAD720000u, 44u}, // sll -> Latn
+    {0xE1720000u, 44u}, // sly -> Latn
+    {0x736D0000u, 44u}, // sm -> Latn
+    {0x81920000u, 44u}, // sma -> Latn
+    {0xA5920000u, 44u}, // smj -> Latn
+    {0xB5920000u, 44u}, // smn -> Latn
+    {0xBD920000u, 70u}, // smp -> Samr
+    {0xC1920000u, 44u}, // smq -> Latn
+    {0xC9920000u, 44u}, // sms -> Latn
+    {0x736E0000u, 44u}, // sn -> Latn
+    {0x89B20000u, 44u}, // snc -> Latn
+    {0xA9B20000u, 44u}, // snk -> Latn
+    {0xBDB20000u, 44u}, // snp -> Latn
+    {0xDDB20000u, 44u}, // snx -> Latn
+    {0xE1B20000u, 44u}, // sny -> Latn
+    {0x736F0000u, 44u}, // so -> Latn
+    {0x99D20000u, 75u}, // sog -> Sogd
+    {0xA9D20000u, 44u}, // sok -> Latn
+    {0xC1D20000u, 44u}, // soq -> Latn
+    {0xD1D20000u, 87u}, // sou -> Thai
+    {0xE1D20000u, 44u}, // soy -> Latn
+    {0x8DF20000u, 44u}, // spd -> Latn
+    {0xADF20000u, 44u}, // spl -> Latn
+    {0xC9F20000u, 44u}, // sps -> Latn
+    {0x73710000u, 44u}, // sq -> Latn
+    {0x73720000u, 16u}, // sr -> Cyrl
+    {0x73724D45u, 44u}, // sr-ME -> Latn
+    {0x7372524Fu, 44u}, // sr-RO -> Latn
+    {0x73725255u, 44u}, // sr-RU -> Latn
+    {0x73725452u, 44u}, // sr-TR -> Latn
+    {0x86320000u, 76u}, // srb -> Sora
+    {0xB6320000u, 44u}, // srn -> Latn
+    {0xC6320000u, 44u}, // srr -> Latn
+    {0xDE320000u, 17u}, // srx -> Deva
+    {0x73730000u, 44u}, // ss -> Latn
+    {0x8E520000u, 44u}, // ssd -> Latn
+    {0x9A520000u, 44u}, // ssg -> Latn
+    {0xE2520000u, 44u}, // ssy -> Latn
+    {0x73740000u, 44u}, // st -> Latn
+    {0xAA720000u, 44u}, // stk -> Latn
+    {0xC2720000u, 44u}, // stq -> Latn
+    {0x73750000u, 44u}, // su -> Latn
+    {0x82920000u, 44u}, // sua -> Latn
+    {0x92920000u, 44u}, // sue -> Latn
+    {0xAA920000u, 44u}, // suk -> Latn
+    {0xC6920000u, 44u}, // sur -> Latn
+    {0xCA920000u, 44u}, // sus -> Latn
+    {0x73760000u, 44u}, // sv -> Latn
+    {0x73770000u, 44u}, // sw -> Latn
     {0x86D20000u,  1u}, // swb -> Arab
-    {0x8AD20000u, 40u}, // swc -> Latn
-    {0x9AD20000u, 40u}, // swg -> Latn
-    {0xBED20000u, 40u}, // swp -> Latn
-    {0xD6D20000u, 16u}, // swv -> Deva
-    {0xB6F20000u, 40u}, // sxn -> Latn
-    {0xDAF20000u, 40u}, // sxw -> Latn
+    {0x8AD20000u, 44u}, // swc -> Latn
+    {0x9AD20000u, 44u}, // swg -> Latn
+    {0xBED20000u, 44u}, // swp -> Latn
+    {0xD6D20000u, 17u}, // swv -> Deva
+    {0xB6F20000u, 44u}, // sxn -> Latn
+    {0xDAF20000u, 44u}, // sxw -> Latn
     {0xAF120000u,  7u}, // syl -> Beng
-    {0xC7120000u, 71u}, // syr -> Syrc
-    {0xAF320000u, 40u}, // szl -> Latn
-    {0x74610000u, 74u}, // ta -> Taml
-    {0xA4130000u, 16u}, // taj -> Deva
-    {0xAC130000u, 40u}, // tal -> Latn
-    {0xB4130000u, 40u}, // tan -> Latn
-    {0xC0130000u, 40u}, // taq -> Latn
-    {0x88330000u, 40u}, // tbc -> Latn
-    {0x8C330000u, 40u}, // tbd -> Latn
-    {0x94330000u, 40u}, // tbf -> Latn
-    {0x98330000u, 40u}, // tbg -> Latn
-    {0xB8330000u, 40u}, // tbo -> Latn
-    {0xD8330000u, 40u}, // tbw -> Latn
-    {0xE4330000u, 40u}, // tbz -> Latn
-    {0xA0530000u, 40u}, // tci -> Latn
-    {0xE0530000u, 36u}, // tcy -> Knda
-    {0x8C730000u, 72u}, // tdd -> Tale
-    {0x98730000u, 16u}, // tdg -> Deva
-    {0x9C730000u, 16u}, // tdh -> Deva
-    {0x74650000u, 77u}, // te -> Telu
-    {0x8C930000u, 40u}, // ted -> Latn
-    {0xB0930000u, 40u}, // tem -> Latn
-    {0xB8930000u, 40u}, // teo -> Latn
-    {0xCC930000u, 40u}, // tet -> Latn
-    {0xA0B30000u, 40u}, // tfi -> Latn
-    {0x74670000u, 15u}, // tg -> Cyrl
+    {0xC7120000u, 78u}, // syr -> Syrc
+    {0xAF320000u, 44u}, // szl -> Latn
+    {0x74610000u, 81u}, // ta -> Taml
+    {0xA4130000u, 17u}, // taj -> Deva
+    {0xAC130000u, 44u}, // tal -> Latn
+    {0xB4130000u, 44u}, // tan -> Latn
+    {0xC0130000u, 44u}, // taq -> Latn
+    {0x88330000u, 44u}, // tbc -> Latn
+    {0x8C330000u, 44u}, // tbd -> Latn
+    {0x94330000u, 44u}, // tbf -> Latn
+    {0x98330000u, 44u}, // tbg -> Latn
+    {0xB8330000u, 44u}, // tbo -> Latn
+    {0xD8330000u, 44u}, // tbw -> Latn
+    {0xE4330000u, 44u}, // tbz -> Latn
+    {0xA0530000u, 44u}, // tci -> Latn
+    {0xE0530000u, 40u}, // tcy -> Knda
+    {0x8C730000u, 79u}, // tdd -> Tale
+    {0x98730000u, 17u}, // tdg -> Deva
+    {0x9C730000u, 17u}, // tdh -> Deva
+    {0x74650000u, 84u}, // te -> Telu
+    {0x8C930000u, 44u}, // ted -> Latn
+    {0xB0930000u, 44u}, // tem -> Latn
+    {0xB8930000u, 44u}, // teo -> Latn
+    {0xCC930000u, 44u}, // tet -> Latn
+    {0xA0B30000u, 44u}, // tfi -> Latn
+    {0x74670000u, 16u}, // tg -> Cyrl
     {0x7467504Bu,  1u}, // tg-PK -> Arab
-    {0x88D30000u, 40u}, // tgc -> Latn
-    {0xB8D30000u, 40u}, // tgo -> Latn
-    {0xD0D30000u, 40u}, // tgu -> Latn
-    {0x74680000u, 80u}, // th -> Thai
-    {0xACF30000u, 16u}, // thl -> Deva
-    {0xC0F30000u, 16u}, // thq -> Deva
-    {0xC4F30000u, 16u}, // thr -> Deva
-    {0x74690000u, 18u}, // ti -> Ethi
-    {0x95130000u, 40u}, // tif -> Latn
-    {0x99130000u, 18u}, // tig -> Ethi
-    {0xA9130000u, 40u}, // tik -> Latn
-    {0xB1130000u, 40u}, // tim -> Latn
-    {0xB9130000u, 40u}, // tio -> Latn
-    {0xD5130000u, 40u}, // tiv -> Latn
-    {0x746B0000u, 40u}, // tk -> Latn
-    {0xAD530000u, 40u}, // tkl -> Latn
-    {0xC5530000u, 40u}, // tkr -> Latn
-    {0xCD530000u, 16u}, // tkt -> Deva
-    {0x746C0000u, 40u}, // tl -> Latn
-    {0x95730000u, 40u}, // tlf -> Latn
-    {0xDD730000u, 40u}, // tlx -> Latn
-    {0xE1730000u, 40u}, // tly -> Latn
-    {0x9D930000u, 40u}, // tmh -> Latn
-    {0xE1930000u, 40u}, // tmy -> Latn
-    {0x746E0000u, 40u}, // tn -> Latn
-    {0x9DB30000u, 40u}, // tnh -> Latn
-    {0x746F0000u, 40u}, // to -> Latn
-    {0x95D30000u, 40u}, // tof -> Latn
-    {0x99D30000u, 40u}, // tog -> Latn
-    {0xC1D30000u, 40u}, // toq -> Latn
-    {0xA1F30000u, 40u}, // tpi -> Latn
-    {0xB1F30000u, 40u}, // tpm -> Latn
-    {0xE5F30000u, 40u}, // tpz -> Latn
-    {0xBA130000u, 40u}, // tqo -> Latn
-    {0x74720000u, 40u}, // tr -> Latn
-    {0xD2330000u, 40u}, // tru -> Latn
-    {0xD6330000u, 40u}, // trv -> Latn
+    {0x88D30000u, 44u}, // tgc -> Latn
+    {0xB8D30000u, 44u}, // tgo -> Latn
+    {0xD0D30000u, 44u}, // tgu -> Latn
+    {0x74680000u, 87u}, // th -> Thai
+    {0xACF30000u, 17u}, // thl -> Deva
+    {0xC0F30000u, 17u}, // thq -> Deva
+    {0xC4F30000u, 17u}, // thr -> Deva
+    {0x74690000u, 19u}, // ti -> Ethi
+    {0x95130000u, 44u}, // tif -> Latn
+    {0x99130000u, 19u}, // tig -> Ethi
+    {0xA9130000u, 44u}, // tik -> Latn
+    {0xB1130000u, 44u}, // tim -> Latn
+    {0xB9130000u, 44u}, // tio -> Latn
+    {0xD5130000u, 44u}, // tiv -> Latn
+    {0x746B0000u, 44u}, // tk -> Latn
+    {0xAD530000u, 44u}, // tkl -> Latn
+    {0xC5530000u, 44u}, // tkr -> Latn
+    {0xCD530000u, 17u}, // tkt -> Deva
+    {0x746C0000u, 44u}, // tl -> Latn
+    {0x95730000u, 44u}, // tlf -> Latn
+    {0xDD730000u, 44u}, // tlx -> Latn
+    {0xE1730000u, 44u}, // tly -> Latn
+    {0x9D930000u, 44u}, // tmh -> Latn
+    {0xE1930000u, 44u}, // tmy -> Latn
+    {0x746E0000u, 44u}, // tn -> Latn
+    {0x9DB30000u, 44u}, // tnh -> Latn
+    {0x746F0000u, 44u}, // to -> Latn
+    {0x95D30000u, 44u}, // tof -> Latn
+    {0x99D30000u, 44u}, // tog -> Latn
+    {0xC1D30000u, 44u}, // toq -> Latn
+    {0xA1F30000u, 44u}, // tpi -> Latn
+    {0xB1F30000u, 44u}, // tpm -> Latn
+    {0xE5F30000u, 44u}, // tpz -> Latn
+    {0xBA130000u, 44u}, // tqo -> Latn
+    {0x74720000u, 44u}, // tr -> Latn
+    {0xD2330000u, 44u}, // tru -> Latn
+    {0xD6330000u, 44u}, // trv -> Latn
     {0xDA330000u,  1u}, // trw -> Arab
-    {0x74730000u, 40u}, // ts -> Latn
-    {0x8E530000u, 21u}, // tsd -> Grek
-    {0x96530000u, 16u}, // tsf -> Deva
-    {0x9A530000u, 40u}, // tsg -> Latn
-    {0xA6530000u, 81u}, // tsj -> Tibt
-    {0xDA530000u, 40u}, // tsw -> Latn
-    {0x74740000u, 15u}, // tt -> Cyrl
-    {0x8E730000u, 40u}, // ttd -> Latn
-    {0x92730000u, 40u}, // tte -> Latn
-    {0xA6730000u, 40u}, // ttj -> Latn
-    {0xC6730000u, 40u}, // ttr -> Latn
-    {0xCA730000u, 80u}, // tts -> Thai
-    {0xCE730000u, 40u}, // ttt -> Latn
-    {0x9E930000u, 40u}, // tuh -> Latn
-    {0xAE930000u, 40u}, // tul -> Latn
-    {0xB2930000u, 40u}, // tum -> Latn
-    {0xC2930000u, 40u}, // tuq -> Latn
-    {0x8EB30000u, 40u}, // tvd -> Latn
-    {0xAEB30000u, 40u}, // tvl -> Latn
-    {0xD2B30000u, 40u}, // tvu -> Latn
-    {0x9ED30000u, 40u}, // twh -> Latn
-    {0xC2D30000u, 40u}, // twq -> Latn
-    {0x9AF30000u, 75u}, // txg -> Tang
-    {0x74790000u, 40u}, // ty -> Latn
-    {0x83130000u, 40u}, // tya -> Latn
-    {0xD7130000u, 15u}, // tyv -> Cyrl
-    {0xB3330000u, 40u}, // tzm -> Latn
-    {0xD0340000u, 40u}, // ubu -> Latn
-    {0xB0740000u, 15u}, // udm -> Cyrl
+    {0x74730000u, 44u}, // ts -> Latn
+    {0x8E530000u, 24u}, // tsd -> Grek
+    {0x96530000u, 17u}, // tsf -> Deva
+    {0x9A530000u, 44u}, // tsg -> Latn
+    {0xA6530000u, 88u}, // tsj -> Tibt
+    {0xDA530000u, 44u}, // tsw -> Latn
+    {0x74740000u, 16u}, // tt -> Cyrl
+    {0x8E730000u, 44u}, // ttd -> Latn
+    {0x92730000u, 44u}, // tte -> Latn
+    {0xA6730000u, 44u}, // ttj -> Latn
+    {0xC6730000u, 44u}, // ttr -> Latn
+    {0xCA730000u, 87u}, // tts -> Thai
+    {0xCE730000u, 44u}, // ttt -> Latn
+    {0x9E930000u, 44u}, // tuh -> Latn
+    {0xAE930000u, 44u}, // tul -> Latn
+    {0xB2930000u, 44u}, // tum -> Latn
+    {0xC2930000u, 44u}, // tuq -> Latn
+    {0x8EB30000u, 44u}, // tvd -> Latn
+    {0xAEB30000u, 44u}, // tvl -> Latn
+    {0xD2B30000u, 44u}, // tvu -> Latn
+    {0x9ED30000u, 44u}, // twh -> Latn
+    {0xC2D30000u, 44u}, // twq -> Latn
+    {0x9AF30000u, 82u}, // txg -> Tang
+    {0x74790000u, 44u}, // ty -> Latn
+    {0x83130000u, 44u}, // tya -> Latn
+    {0xD7130000u, 16u}, // tyv -> Cyrl
+    {0xB3330000u, 44u}, // tzm -> Latn
+    {0xD0340000u, 44u}, // ubu -> Latn
+    {0xB0740000u, 16u}, // udm -> Cyrl
     {0x75670000u,  1u}, // ug -> Arab
-    {0x75674B5Au, 15u}, // ug-KZ -> Cyrl
-    {0x75674D4Eu, 15u}, // ug-MN -> Cyrl
-    {0x80D40000u, 82u}, // uga -> Ugar
-    {0x756B0000u, 15u}, // uk -> Cyrl
-    {0xA1740000u, 40u}, // uli -> Latn
-    {0x85940000u, 40u}, // umb -> Latn
+    {0x75674B5Au, 16u}, // ug-KZ -> Cyrl
+    {0x75674D4Eu, 16u}, // ug-MN -> Cyrl
+    {0x80D40000u, 89u}, // uga -> Ugar
+    {0x756B0000u, 16u}, // uk -> Cyrl
+    {0xA1740000u, 44u}, // uli -> Latn
+    {0x85940000u, 44u}, // umb -> Latn
     {0xC5B40000u,  7u}, // unr -> Beng
-    {0xC5B44E50u, 16u}, // unr-NP -> Deva
+    {0xC5B44E50u, 17u}, // unr-NP -> Deva
     {0xDDB40000u,  7u}, // unx -> Beng
     {0x75720000u,  1u}, // ur -> Arab
-    {0xA2340000u, 40u}, // uri -> Latn
-    {0xCE340000u, 40u}, // urt -> Latn
-    {0xDA340000u, 40u}, // urw -> Latn
-    {0x82540000u, 40u}, // usa -> Latn
-    {0xC6740000u, 40u}, // utr -> Latn
-    {0x9EB40000u, 40u}, // uvh -> Latn
-    {0xAEB40000u, 40u}, // uvl -> Latn
-    {0x757A0000u, 40u}, // uz -> Latn
+    {0xA2340000u, 44u}, // uri -> Latn
+    {0xCE340000u, 44u}, // urt -> Latn
+    {0xDA340000u, 44u}, // urw -> Latn
+    {0x82540000u, 44u}, // usa -> Latn
+    {0xC6740000u, 44u}, // utr -> Latn
+    {0x9EB40000u, 44u}, // uvh -> Latn
+    {0xAEB40000u, 44u}, // uvl -> Latn
+    {0x757A0000u, 44u}, // uz -> Latn
     {0x757A4146u,  1u}, // uz-AF -> Arab
-    {0x757A434Eu, 15u}, // uz-CN -> Cyrl
-    {0x98150000u, 40u}, // vag -> Latn
-    {0xA0150000u, 83u}, // vai -> Vaii
-    {0xB4150000u, 40u}, // van -> Latn
-    {0x76650000u, 40u}, // ve -> Latn
-    {0x88950000u, 40u}, // vec -> Latn
-    {0xBC950000u, 40u}, // vep -> Latn
-    {0x76690000u, 40u}, // vi -> Latn
-    {0x89150000u, 40u}, // vic -> Latn
-    {0xD5150000u, 40u}, // viv -> Latn
-    {0xC9750000u, 40u}, // vls -> Latn
-    {0x95950000u, 40u}, // vmf -> Latn
-    {0xD9950000u, 40u}, // vmw -> Latn
-    {0x766F0000u, 40u}, // vo -> Latn
-    {0xCDD50000u, 40u}, // vot -> Latn
-    {0xBA350000u, 40u}, // vro -> Latn
-    {0xB6950000u, 40u}, // vun -> Latn
-    {0xCE950000u, 40u}, // vut -> Latn
-    {0x77610000u, 40u}, // wa -> Latn
-    {0x90160000u, 40u}, // wae -> Latn
-    {0xA4160000u, 40u}, // waj -> Latn
-    {0xAC160000u, 18u}, // wal -> Ethi
-    {0xB4160000u, 40u}, // wan -> Latn
-    {0xC4160000u, 40u}, // war -> Latn
-    {0xBC360000u, 40u}, // wbp -> Latn
-    {0xC0360000u, 77u}, // wbq -> Telu
-    {0xC4360000u, 16u}, // wbr -> Deva
-    {0xA0560000u, 40u}, // wci -> Latn
-    {0xC4960000u, 40u}, // wer -> Latn
-    {0xA0D60000u, 40u}, // wgi -> Latn
-    {0x98F60000u, 40u}, // whg -> Latn
-    {0x85160000u, 40u}, // wib -> Latn
-    {0xD1160000u, 40u}, // wiu -> Latn
-    {0xD5160000u, 40u}, // wiv -> Latn
-    {0x81360000u, 40u}, // wja -> Latn
-    {0xA1360000u, 40u}, // wji -> Latn
-    {0xC9760000u, 40u}, // wls -> Latn
-    {0xB9960000u, 40u}, // wmo -> Latn
-    {0x89B60000u, 40u}, // wnc -> Latn
+    {0x757A434Eu, 16u}, // uz-CN -> Cyrl
+    {0x98150000u, 44u}, // vag -> Latn
+    {0xA0150000u, 90u}, // vai -> Vaii
+    {0xB4150000u, 44u}, // van -> Latn
+    {0x76650000u, 44u}, // ve -> Latn
+    {0x88950000u, 44u}, // vec -> Latn
+    {0xBC950000u, 44u}, // vep -> Latn
+    {0x76690000u, 44u}, // vi -> Latn
+    {0x89150000u, 44u}, // vic -> Latn
+    {0xD5150000u, 44u}, // viv -> Latn
+    {0xC9750000u, 44u}, // vls -> Latn
+    {0x95950000u, 44u}, // vmf -> Latn
+    {0xD9950000u, 44u}, // vmw -> Latn
+    {0x766F0000u, 44u}, // vo -> Latn
+    {0xCDD50000u, 44u}, // vot -> Latn
+    {0xBA350000u, 44u}, // vro -> Latn
+    {0xB6950000u, 44u}, // vun -> Latn
+    {0xCE950000u, 44u}, // vut -> Latn
+    {0x77610000u, 44u}, // wa -> Latn
+    {0x90160000u, 44u}, // wae -> Latn
+    {0xA4160000u, 44u}, // waj -> Latn
+    {0xAC160000u, 19u}, // wal -> Ethi
+    {0xB4160000u, 44u}, // wan -> Latn
+    {0xC4160000u, 44u}, // war -> Latn
+    {0xBC360000u, 44u}, // wbp -> Latn
+    {0xC0360000u, 84u}, // wbq -> Telu
+    {0xC4360000u, 17u}, // wbr -> Deva
+    {0xA0560000u, 44u}, // wci -> Latn
+    {0xC4960000u, 44u}, // wer -> Latn
+    {0xA0D60000u, 44u}, // wgi -> Latn
+    {0x98F60000u, 44u}, // whg -> Latn
+    {0x85160000u, 44u}, // wib -> Latn
+    {0xD1160000u, 44u}, // wiu -> Latn
+    {0xD5160000u, 44u}, // wiv -> Latn
+    {0x81360000u, 44u}, // wja -> Latn
+    {0xA1360000u, 44u}, // wji -> Latn
+    {0xC9760000u, 44u}, // wls -> Latn
+    {0xB9960000u, 44u}, // wmo -> Latn
+    {0x89B60000u, 44u}, // wnc -> Latn
     {0xA1B60000u,  1u}, // wni -> Arab
-    {0xD1B60000u, 40u}, // wnu -> Latn
-    {0x776F0000u, 40u}, // wo -> Latn
-    {0x85D60000u, 40u}, // wob -> Latn
-    {0xC9D60000u, 40u}, // wos -> Latn
-    {0xCA360000u, 40u}, // wrs -> Latn
-    {0xAA560000u, 40u}, // wsk -> Latn
-    {0xB2760000u, 16u}, // wtm -> Deva
-    {0xD2960000u, 24u}, // wuu -> Hans
-    {0xD6960000u, 40u}, // wuv -> Latn
-    {0x82D60000u, 40u}, // wwa -> Latn
-    {0xD4170000u, 40u}, // xav -> Latn
-    {0xA0370000u, 40u}, // xbi -> Latn
-    {0xC4570000u, 10u}, // xcr -> Cari
-    {0xC8970000u, 40u}, // xes -> Latn
-    {0x78680000u, 40u}, // xh -> Latn
-    {0x81770000u, 40u}, // xla -> Latn
-    {0x89770000u, 44u}, // xlc -> Lyci
-    {0x8D770000u, 45u}, // xld -> Lydi
-    {0x95970000u, 19u}, // xmf -> Geor
-    {0xB5970000u, 47u}, // xmn -> Mani
-    {0xC5970000u, 48u}, // xmr -> Merc
-    {0x81B70000u, 53u}, // xna -> Narb
-    {0xC5B70000u, 16u}, // xnr -> Deva
-    {0x99D70000u, 40u}, // xog -> Latn
-    {0xB5D70000u, 40u}, // xon -> Latn
-    {0xC5F70000u, 63u}, // xpr -> Prti
-    {0x86370000u, 40u}, // xrb -> Latn
-    {0x82570000u, 66u}, // xsa -> Sarb
-    {0xA2570000u, 40u}, // xsi -> Latn
-    {0xB2570000u, 40u}, // xsm -> Latn
-    {0xC6570000u, 16u}, // xsr -> Deva
-    {0x92D70000u, 40u}, // xwe -> Latn
-    {0xB0180000u, 40u}, // yam -> Latn
-    {0xB8180000u, 40u}, // yao -> Latn
-    {0xBC180000u, 40u}, // yap -> Latn
-    {0xC8180000u, 40u}, // yas -> Latn
-    {0xCC180000u, 40u}, // yat -> Latn
-    {0xD4180000u, 40u}, // yav -> Latn
-    {0xE0180000u, 40u}, // yay -> Latn
-    {0xE4180000u, 40u}, // yaz -> Latn
-    {0x80380000u, 40u}, // yba -> Latn
-    {0x84380000u, 40u}, // ybb -> Latn
-    {0xE0380000u, 40u}, // yby -> Latn
-    {0xC4980000u, 40u}, // yer -> Latn
-    {0xC4D80000u, 40u}, // ygr -> Latn
-    {0xD8D80000u, 40u}, // ygw -> Latn
-    {0x79690000u, 27u}, // yi -> Hebr
-    {0xB9580000u, 40u}, // yko -> Latn
-    {0x91780000u, 40u}, // yle -> Latn
-    {0x99780000u, 40u}, // ylg -> Latn
-    {0xAD780000u, 40u}, // yll -> Latn
-    {0xAD980000u, 40u}, // yml -> Latn
-    {0x796F0000u, 40u}, // yo -> Latn
-    {0xB5D80000u, 40u}, // yon -> Latn
-    {0x86380000u, 40u}, // yrb -> Latn
-    {0x92380000u, 40u}, // yre -> Latn
-    {0xAE380000u, 40u}, // yrl -> Latn
-    {0xCA580000u, 40u}, // yss -> Latn
-    {0x82980000u, 40u}, // yua -> Latn
-    {0x92980000u, 25u}, // yue -> Hant
-    {0x9298434Eu, 24u}, // yue-CN -> Hans
-    {0xA6980000u, 40u}, // yuj -> Latn
-    {0xCE980000u, 40u}, // yut -> Latn
-    {0xDA980000u, 40u}, // yuw -> Latn
-    {0x7A610000u, 40u}, // za -> Latn
-    {0x98190000u, 40u}, // zag -> Latn
+    {0xD1B60000u, 44u}, // wnu -> Latn
+    {0x776F0000u, 44u}, // wo -> Latn
+    {0x85D60000u, 44u}, // wob -> Latn
+    {0xC9D60000u, 44u}, // wos -> Latn
+    {0xCA360000u, 44u}, // wrs -> Latn
+    {0x9A560000u, 21u}, // wsg -> Gong
+    {0xAA560000u, 44u}, // wsk -> Latn
+    {0xB2760000u, 17u}, // wtm -> Deva
+    {0xD2960000u, 27u}, // wuu -> Hans
+    {0xD6960000u, 44u}, // wuv -> Latn
+    {0x82D60000u, 44u}, // wwa -> Latn
+    {0xD4170000u, 44u}, // xav -> Latn
+    {0xA0370000u, 44u}, // xbi -> Latn
+    {0xC4570000u, 11u}, // xcr -> Cari
+    {0xC8970000u, 44u}, // xes -> Latn
+    {0x78680000u, 44u}, // xh -> Latn
+    {0x81770000u, 44u}, // xla -> Latn
+    {0x89770000u, 48u}, // xlc -> Lyci
+    {0x8D770000u, 49u}, // xld -> Lydi
+    {0x95970000u, 20u}, // xmf -> Geor
+    {0xB5970000u, 51u}, // xmn -> Mani
+    {0xC5970000u, 52u}, // xmr -> Merc
+    {0x81B70000u, 57u}, // xna -> Narb
+    {0xC5B70000u, 17u}, // xnr -> Deva
+    {0x99D70000u, 44u}, // xog -> Latn
+    {0xB5D70000u, 44u}, // xon -> Latn
+    {0xC5F70000u, 68u}, // xpr -> Prti
+    {0x86370000u, 44u}, // xrb -> Latn
+    {0x82570000u, 71u}, // xsa -> Sarb
+    {0xA2570000u, 44u}, // xsi -> Latn
+    {0xB2570000u, 44u}, // xsm -> Latn
+    {0xC6570000u, 17u}, // xsr -> Deva
+    {0x92D70000u, 44u}, // xwe -> Latn
+    {0xB0180000u, 44u}, // yam -> Latn
+    {0xB8180000u, 44u}, // yao -> Latn
+    {0xBC180000u, 44u}, // yap -> Latn
+    {0xC8180000u, 44u}, // yas -> Latn
+    {0xCC180000u, 44u}, // yat -> Latn
+    {0xD4180000u, 44u}, // yav -> Latn
+    {0xE0180000u, 44u}, // yay -> Latn
+    {0xE4180000u, 44u}, // yaz -> Latn
+    {0x80380000u, 44u}, // yba -> Latn
+    {0x84380000u, 44u}, // ybb -> Latn
+    {0xE0380000u, 44u}, // yby -> Latn
+    {0xC4980000u, 44u}, // yer -> Latn
+    {0xC4D80000u, 44u}, // ygr -> Latn
+    {0xD8D80000u, 44u}, // ygw -> Latn
+    {0x79690000u, 30u}, // yi -> Hebr
+    {0xB9580000u, 44u}, // yko -> Latn
+    {0x91780000u, 44u}, // yle -> Latn
+    {0x99780000u, 44u}, // ylg -> Latn
+    {0xAD780000u, 44u}, // yll -> Latn
+    {0xAD980000u, 44u}, // yml -> Latn
+    {0x796F0000u, 44u}, // yo -> Latn
+    {0xB5D80000u, 44u}, // yon -> Latn
+    {0x86380000u, 44u}, // yrb -> Latn
+    {0x92380000u, 44u}, // yre -> Latn
+    {0xAE380000u, 44u}, // yrl -> Latn
+    {0xCA580000u, 44u}, // yss -> Latn
+    {0x82980000u, 44u}, // yua -> Latn
+    {0x92980000u, 28u}, // yue -> Hant
+    {0x9298434Eu, 27u}, // yue-CN -> Hans
+    {0xA6980000u, 44u}, // yuj -> Latn
+    {0xCE980000u, 44u}, // yut -> Latn
+    {0xDA980000u, 44u}, // yuw -> Latn
+    {0x7A610000u, 44u}, // za -> Latn
+    {0x98190000u, 44u}, // zag -> Latn
     {0xA4790000u,  1u}, // zdj -> Arab
-    {0x80990000u, 40u}, // zea -> Latn
-    {0x9CD90000u, 78u}, // zgh -> Tfng
-    {0x7A680000u, 24u}, // zh -> Hans
-    {0x7A684155u, 25u}, // zh-AU -> Hant
-    {0x7A68424Eu, 25u}, // zh-BN -> Hant
-    {0x7A684742u, 25u}, // zh-GB -> Hant
-    {0x7A684746u, 25u}, // zh-GF -> Hant
-    {0x7A68484Bu, 25u}, // zh-HK -> Hant
-    {0x7A684944u, 25u}, // zh-ID -> Hant
-    {0x7A684D4Fu, 25u}, // zh-MO -> Hant
-    {0x7A684D59u, 25u}, // zh-MY -> Hant
-    {0x7A685041u, 25u}, // zh-PA -> Hant
-    {0x7A685046u, 25u}, // zh-PF -> Hant
-    {0x7A685048u, 25u}, // zh-PH -> Hant
-    {0x7A685352u, 25u}, // zh-SR -> Hant
-    {0x7A685448u, 25u}, // zh-TH -> Hant
-    {0x7A685457u, 25u}, // zh-TW -> Hant
-    {0x7A685553u, 25u}, // zh-US -> Hant
-    {0x7A68564Eu, 25u}, // zh-VN -> Hant
-    {0x81190000u, 40u}, // zia -> Latn
-    {0xB1790000u, 40u}, // zlm -> Latn
-    {0xA1990000u, 40u}, // zmi -> Latn
-    {0x91B90000u, 40u}, // zne -> Latn
-    {0x7A750000u, 40u}, // zu -> Latn
-    {0x83390000u, 40u}, // zza -> Latn
+    {0x80990000u, 44u}, // zea -> Latn
+    {0x9CD90000u, 85u}, // zgh -> Tfng
+    {0x7A680000u, 27u}, // zh -> Hans
+    {0x7A684155u, 28u}, // zh-AU -> Hant
+    {0x7A68424Eu, 28u}, // zh-BN -> Hant
+    {0x7A684742u, 28u}, // zh-GB -> Hant
+    {0x7A684746u, 28u}, // zh-GF -> Hant
+    {0x7A68484Bu, 28u}, // zh-HK -> Hant
+    {0x7A684944u, 28u}, // zh-ID -> Hant
+    {0x7A684D4Fu, 28u}, // zh-MO -> Hant
+    {0x7A684D59u, 28u}, // zh-MY -> Hant
+    {0x7A685041u, 28u}, // zh-PA -> Hant
+    {0x7A685046u, 28u}, // zh-PF -> Hant
+    {0x7A685048u, 28u}, // zh-PH -> Hant
+    {0x7A685352u, 28u}, // zh-SR -> Hant
+    {0x7A685448u, 28u}, // zh-TH -> Hant
+    {0x7A685457u, 28u}, // zh-TW -> Hant
+    {0x7A685553u, 28u}, // zh-US -> Hant
+    {0x7A68564Eu, 28u}, // zh-VN -> Hant
+    {0xDCF90000u, 59u}, // zhx -> Nshu
+    {0x81190000u, 44u}, // zia -> Latn
+    {0xB1790000u, 44u}, // zlm -> Latn
+    {0xA1990000u, 44u}, // zmi -> Latn
+    {0x91B90000u, 44u}, // zne -> Latn
+    {0x7A750000u, 44u}, // zu -> Latn
+    {0x83390000u, 44u}, // zza -> Latn
 });
 
 std::unordered_set<uint64_t> REPRESENTATIVE_LOCALES({
@@ -1517,6 +1544,7 @@
     0xB5014E474C61746ELLU, // bin_Latn_NG
     0xA521494E44657661LLU, // bjj_Deva_IN
     0xB52149444C61746ELLU, // bjn_Latn_ID
+    0xCD21534E4C61746ELLU, // bjt_Latn_SN
     0xB141434D4C61746ELLU, // bkm_Latn_CM
     0xD14150484C61746ELLU, // bku_Latn_PH
     0xCD61564E54617674LLU, // blt_Tavt_VN
@@ -1546,7 +1574,6 @@
     0x93214D4C4C61746ELLU, // bze_Latn_ML
     0x636145534C61746ELLU, // ca_Latn_ES
     0x9C424E474C61746ELLU, // cch_Latn_NG
-    0xBC42494E42656E67LLU, // ccp_Beng_IN
     0xBC42424443616B6DLLU, // ccp_Cakm_BD
     0x636552554379726CLLU, // ce_Cyrl_RU
     0x848250484C61746ELLU, // ceb_Latn_PH
@@ -1560,10 +1587,12 @@
     0x81224B4841726162LLU, // cja_Arab_KH
     0xB122564E4368616DLLU, // cjm_Cham_VN
     0x8542495141726162LLU, // ckb_Arab_IQ
+    0x99824D4E536F796FLLU, // cmg_Soyo_MN
     0x636F46524C61746ELLU, // co_Latn_FR
     0xBDC24547436F7074LLU, // cop_Copt_EG
     0xC9E250484C61746ELLU, // cps_Latn_PH
     0x6372434143616E73LLU, // cr_Cans_CA
+    0x9E2255414379726CLLU, // crh_Cyrl_UA
     0xA622434143616E73LLU, // crj_Cans_CA
     0xAA22434143616E73LLU, // crk_Cans_CA
     0xAE22434143616E73LLU, // crl_Cans_CA
@@ -1610,6 +1639,7 @@
     0x657345534C61746ELLU, // es_Latn_ES
     0x65734D584C61746ELLU, // es_Latn_MX
     0x657355534C61746ELLU, // es_Latn_US
+    0x9A44494E476F6E6DLLU, // esg_Gonm_IN
     0xD24455534C61746ELLU, // esu_Latn_US
     0x657445454C61746ELLU, // et_Latn_EE
     0xCE6449544974616CLLU, // ett_Ital_IT
@@ -1700,10 +1730,10 @@
     0x687548554C61746ELLU, // hu_Latn_HU
     0x6879414D41726D6ELLU, // hy_Armn_AM
     0x687A4E414C61746ELLU, // hz_Latn_NA
-    0x696146524C61746ELLU, // ia_Latn_FR
     0x80284D594C61746ELLU, // iba_Latn_MY
     0x84284E474C61746ELLU, // ibb_Latn_NG
     0x696449444C61746ELLU, // id_Latn_ID
+    0x90A854474C61746ELLU, // ife_Latn_TG
     0x69674E474C61746ELLU, // ig_Latn_NG
     0x6969434E59696969LLU, // ii_Yiii_CN
     0x696B55534C61746ELLU, // ik_Latn_US
@@ -1764,6 +1794,7 @@
     0x6B6D4B484B686D72LLU, // km_Khmr_KH
     0x858A414F4C61746ELLU, // kmb_Latn_AO
     0x6B6E494E4B6E6461LLU, // kn_Knda_IN
+    0x95AA47574C61746ELLU, // knf_Latn_GW
     0x6B6F4B524B6F7265LLU, // ko_Kore_KR
     0xA1CA52554379726CLLU, // koi_Cyrl_RU
     0xA9CA494E44657661LLU, // kok_Deva_IN
@@ -1854,6 +1885,7 @@
     0x6D694E5A4C61746ELLU, // mi_Latn_NZ
     0xB50C49444C61746ELLU, // min_Latn_ID
     0xC90C495148617472LLU, // mis_Hatr_IQ
+    0xC90C4E474D656466LLU, // mis_Medf_NG
     0x6D6B4D4B4379726CLLU, // mk_Cyrl_MK
     0x6D6C494E4D6C796DLLU, // ml_Mlym_IN
     0xC96C53444C61746ELLU, // mls_Latn_SD
@@ -1877,6 +1909,7 @@
     0xAACC4D4C4C61746ELLU, // mwk_Latn_ML
     0xC6CC494E44657661LLU, // mwr_Deva_IN
     0xD6CC49444C61746ELLU, // mwv_Latn_ID
+    0xDACC5553486D6E70LLU, // mww_Hmnp_US
     0x8AEC5A574C61746ELLU, // mxc_Latn_ZW
     0x6D794D4D4D796D72LLU, // my_Mymr_MM
     0xD70C52554379726CLLU, // myv_Cyrl_RU
@@ -1905,6 +1938,7 @@
     0x998D434D4C61746ELLU, // nmg_Latn_CM
     0x6E6E4E4F4C61746ELLU, // nn_Latn_NO
     0x9DAD434D4C61746ELLU, // nnh_Latn_CM
+    0xBDAD494E5763686FLLU, // nnp_Wcho_IN
     0x6E6F4E4F4C61746ELLU, // no_Latn_NO
     0x8DCD54484C616E61LLU, // nod_Lana_TH
     0x91CD494E44657661LLU, // noe_Deva_IN
@@ -1959,6 +1993,7 @@
     0x945152454C61746ELLU, // rcf_Latn_RE
     0xA49149444C61746ELLU, // rej_Latn_ID
     0xB4D149544C61746ELLU, // rgn_Latn_IT
+    0x98F14D4D41726162LLU, // rhg_Arab_MM
     0x8111494E4C61746ELLU, // ria_Latn_IN
     0x95114D4154666E67LLU, // rif_Tfng_MA
     0xC9314E5044657661LLU, // rjs_Deva_NP
@@ -1986,6 +2021,7 @@
     0xC0124B454C61746ELLU, // saq_Latn_KE
     0xC81249444C61746ELLU, // sas_Latn_ID
     0xCC12494E4C61746ELLU, // sat_Latn_IN
+    0xD412534E4C61746ELLU, // sav_Latn_SN
     0xE412494E53617572LLU, // saz_Saur_IN
     0xBC32545A4C61746ELLU, // sbp_Latn_TZ
     0x736349544C61746ELLU, // sc_Latn_IT
@@ -2025,6 +2061,7 @@
     0x736E5A574C61746ELLU, // sn_Latn_ZW
     0xA9B24D4C4C61746ELLU, // snk_Latn_ML
     0x736F534F4C61746ELLU, // so_Latn_SO
+    0x99D2555A536F6764LLU, // sog_Sogd_UZ
     0xD1D2544854686169LLU, // sou_Thai_TH
     0x7371414C4C61746ELLU, // sq_Latn_AL
     0x737252534379726CLLU, // sr_Cyrl_RS
@@ -2135,6 +2172,7 @@
     0xC97657464C61746ELLU, // wls_Latn_WF
     0xA1B64B4D41726162LLU, // wni_Arab_KM
     0x776F534E4C61746ELLU, // wo_Latn_SN
+    0x9A56494E476F6E67LLU, // wsg_Gong_IN
     0xB276494E44657661LLU, // wtm_Deva_IN
     0xD296434E48616E73LLU, // wuu_Hans_CN
     0xD41742524C61746ELLU, // xav_Latn_BR
@@ -2169,6 +2207,7 @@
     0x7A68545748616E62LLU, // zh_Hanb_TW
     0x7A68434E48616E73LLU, // zh_Hans_CN
     0x7A68545748616E74LLU, // zh_Hant_TW
+    0xDCF9434E4E736875LLU, // zhx_Nshu_CN
     0xB17954474C61746ELLU, // zlm_Latn_TG
     0xA1994D594C61746ELLU, // zmi_Latn_MY
     0x7A755A414C61746ELLU, // zu_Latn_ZA
@@ -2194,7 +2233,7 @@
     {0x656E4154u, 0x656E80A1u}, // en-AT -> en-150
     {0x656E4155u, 0x656E8400u}, // en-AU -> en-001
     {0x656E4242u, 0x656E8400u}, // en-BB -> en-001
-    {0x656E4245u, 0x656E8400u}, // en-BE -> en-001
+    {0x656E4245u, 0x656E80A1u}, // en-BE -> en-150
     {0x656E424Du, 0x656E8400u}, // en-BM -> en-001
     {0x656E4253u, 0x656E8400u}, // en-BS -> en-001
     {0x656E4257u, 0x656E8400u}, // en-BW -> en-001
@@ -2285,6 +2324,7 @@
     {0x65734152u, 0x6573A424u}, // es-AR -> es-419
     {0x6573424Fu, 0x6573A424u}, // es-BO -> es-419
     {0x65734252u, 0x6573A424u}, // es-BR -> es-419
+    {0x6573425Au, 0x6573A424u}, // es-BZ -> es-419
     {0x6573434Cu, 0x6573A424u}, // es-CL -> es-419
     {0x6573434Fu, 0x6573A424u}, // es-CO -> es-419
     {0x65734352u, 0x6573A424u}, // es-CR -> es-419
@@ -2315,6 +2355,10 @@
     {0x7074544Cu, 0x70745054u}, // pt-TL -> pt-PT
 });
 
+const std::unordered_map<uint32_t, uint32_t> ___B_PARENTS({
+    {0x61725842u, 0x61729420u}, // ar-XB -> ar-015
+});
+
 const struct {
     const char script[4];
     const std::unordered_map<uint32_t, uint32_t>* map;
@@ -2322,6 +2366,7 @@
     {{'A', 'r', 'a', 'b'}, &ARAB_PARENTS},
     {{'H', 'a', 'n', 't'}, &HANT_PARENTS},
     {{'L', 'a', 't', 'n'}, &LATN_PARENTS},
+    {{'~', '~', '~', 'B'}, &___B_PARENTS},
 };
 
 const size_t MAX_PARENT_DEPTH = 3;
diff --git a/media/java/android/media/session/ICallback.aidl b/media/java/android/media/session/ICallback.aidl
deleted file mode 100644
index 322bffa..0000000
--- a/media/java/android/media/session/ICallback.aidl
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.session;
-
-import android.app.PendingIntent;
-import android.content.ComponentName;
-import android.media.session.MediaSession;
-import android.view.KeyEvent;
-
-/**
- * @hide
- */
-oneway interface ICallback {
-    void onMediaKeyEventDispatchedToMediaSession(in KeyEvent event,
-            in MediaSession.Token sessionToken);
-    void onMediaKeyEventDispatchedToMediaButtonReceiver(in KeyEvent event,
-            in ComponentName mediaButtonReceiver);
-
-    void onAddressedPlayerChangedToMediaSession(in MediaSession.Token sessionToken);
-    void onAddressedPlayerChangedToMediaButtonReceiver(in ComponentName mediaButtonReceiver);
-}
-
diff --git a/media/java/android/media/session/IOnMediaKeyEventDispatchedListener.aidl b/media/java/android/media/session/IOnMediaKeyEventDispatchedListener.aidl
new file mode 100644
index 0000000..90d9134
--- /dev/null
+++ b/media/java/android/media/session/IOnMediaKeyEventDispatchedListener.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.media.session.MediaSession;
+import android.view.KeyEvent;
+
+/**
+ * @hide
+ */
+oneway interface IOnMediaKeyEventDispatchedListener {
+    void onMediaKeyEventDispatched(in KeyEvent event, in String packageName,
+            in MediaSession.Token sessionToken);
+}
diff --git a/media/java/android/media/session/IOnMediaKeyEventSessionChangedListener.aidl b/media/java/android/media/session/IOnMediaKeyEventSessionChangedListener.aidl
new file mode 100644
index 0000000..9566e75
--- /dev/null
+++ b/media/java/android/media/session/IOnMediaKeyEventSessionChangedListener.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.media.session.MediaSession;
+
+/**
+ * @hide
+ */
+oneway interface IOnMediaKeyEventSessionChangedListener {
+    void onMediaKeyEventSessionChanged(in String packageName,
+            in MediaSession.Token mediaKeyEventSessionToken);
+}
+
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 01e6ed5..c8502a5 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -20,7 +20,8 @@
 import android.media.IRemoteVolumeController;
 import android.media.Session2Token;
 import android.media.session.IActiveSessionsListener;
-import android.media.session.ICallback;
+import android.media.session.IOnMediaKeyEventDispatchedListener;
+import android.media.session.IOnMediaKeyEventSessionChangedListener;
 import android.media.session.IOnMediaKeyListener;
 import android.media.session.IOnVolumeKeyLongPressListener;
 import android.media.session.ISession;
@@ -62,8 +63,12 @@
     // For PhoneWindowManager to precheck media keys
     boolean isGlobalPriorityActive();
 
-    void registerCallback(in ICallback callback);
-    void unregisterCallback(in ICallback callback);
+    void addOnMediaKeyEventDispatchedListener(in IOnMediaKeyEventDispatchedListener listener);
+    void removeOnMediaKeyEventDispatchedListener(in IOnMediaKeyEventDispatchedListener listener);
+    void addOnMediaKeyEventSessionChangedListener(
+            in IOnMediaKeyEventSessionChangedListener listener);
+    void removeOnMediaKeyEventSessionChangedListener(
+            in IOnMediaKeyEventSessionChangedListener listener);
     void setOnVolumeKeyLongPressListener(in IOnVolumeKeyLongPressListener listener);
     void setOnMediaKeyListener(in IOnMediaKeyListener listener);
 
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 92fb31b..a89dc5f 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -32,7 +32,6 @@
 import android.media.Session2Token;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.HandlerExecutor;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
@@ -78,29 +77,33 @@
      */
     public static final int RESULT_MEDIA_KEY_HANDLED = 1;
     private final ISessionManager mService;
+    private final OnMediaKeyEventDispatchedListenerStub mOnMediaKeyEventDispatchedListenerStub =
+            new OnMediaKeyEventDispatchedListenerStub();
+    private final OnMediaKeyEventSessionChangedListenerStub
+            mOnMediaKeyEventSessionChangedListenerStub =
+            new OnMediaKeyEventSessionChangedListenerStub();
 
     private final Object mLock = new Object();
     @GuardedBy("mLock")
-    private final ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper> mListeners
-            = new ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper>();
+    private final ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper> mListeners =
+            new ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper>();
     @GuardedBy("mLock")
     private final ArrayMap<OnSession2TokensChangedListener, Session2TokensChangedWrapper>
             mSession2TokensListeners = new ArrayMap<>();
     @GuardedBy("mLock")
-    private final CallbackStub mCbStub = new CallbackStub();
+    private final Map<OnMediaKeyEventDispatchedListener, Executor>
+            mOnMediaKeyEventDispatchedListeners = new HashMap<>();
     @GuardedBy("mLock")
-    private final Map<Callback, Executor> mCallbacks = new HashMap<>();
+    private final Map<OnMediaKeyEventSessionChangedListener, Executor>
+            mMediaKeyEventSessionChangedCallbacks = new HashMap<>();
     @GuardedBy("mLock")
-    private MediaSession.Token mCurMediaButtonSession;
+    private String mCurMediaKeyEventSessionPackage;
     @GuardedBy("mLock")
-    private ComponentName mCurMediaButtonReceiver;
+    private MediaSession.Token mCurMediaKeyEventSession;
 
     private Context mContext;
     private OnVolumeKeyLongPressListenerImpl mOnVolumeKeyLongPressListener;
     private OnMediaKeyListenerImpl mOnMediaKeyListener;
-    // TODO: Remove mLegacyCallback once Bluetooth app stop calling setCallback() method.
-    @GuardedBy("mLock")
-    private Callback mLegacyCallback;
 
     /**
      * @hide
@@ -756,89 +759,118 @@
     }
 
     /**
-     * Set a {@link Callback}.
-     *
-     * <p>System can only have a single callback, and the callback can only be set by
-     * Bluetooth service process.
-     *
-     * @param callback A {@link Callback}. {@code null} to reset.
-     * @param handler The handler on which the callback should be invoked, or {@code null}
-     *            if the callback should be invoked on the calling thread's looper.
-     * @hide
-     */
-    // TODO: Remove this method once Bluetooth app stop calling it.
-    public void setCallback(@Nullable Callback callback, @Nullable Handler handler) {
-        if (handler == null) {
-            handler = new Handler();
-        }
-        synchronized (mLock) {
-            if (mLegacyCallback != null) {
-                unregisterCallback(mLegacyCallback);
-            }
-            mLegacyCallback = callback;
-            if (callback != null) {
-                registerCallback(new HandlerExecutor(handler), callback);
-            }
-        }
-    }
-
-    /**
-     * Register a {@link Callback}.
+     * Add a {@link OnMediaKeyEventDispatchedListener}.
      *
      * @param executor The executor on which the callback should be invoked
-     * @param callback A {@link Callback}.
+     * @param listener A {@link OnMediaKeyEventDispatchedListener}.
      * @hide
      */
     @SystemApi
     @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
-    public void registerCallback(@NonNull @CallbackExecutor Executor executor,
-            @NonNull Callback callback) {
+    public void addOnMediaKeyEventDispatchedListener(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnMediaKeyEventDispatchedListener listener) {
         if (executor == null) {
             throw new NullPointerException("executor shouldn't be null");
         }
-        if (callback == null) {
-            throw new NullPointerException("callback shouldn't be null");
+        if (listener == null) {
+            throw new NullPointerException("listener shouldn't be null");
         }
         synchronized (mLock) {
             try {
-                mCallbacks.put(callback, executor);
-                if (mCurMediaButtonSession != null) {
-                    executor.execute(
-                            () -> callback.onAddressedPlayerChanged(mCurMediaButtonSession));
-                } else if (mCurMediaButtonReceiver != null) {
-                    executor.execute(
-                            () -> callback.onAddressedPlayerChanged(mCurMediaButtonReceiver));
-                }
-
-                if (mCallbacks.size() == 1) {
-                    mService.registerCallback(mCbStub);
+                mOnMediaKeyEventDispatchedListeners.put(listener, executor);
+                if (mOnMediaKeyEventDispatchedListeners.size() == 1) {
+                    mService.addOnMediaKeyEventDispatchedListener(
+                            mOnMediaKeyEventDispatchedListenerStub);
                 }
             } catch (RemoteException e) {
-                Log.e(TAG, "Failed to set media key callback", e);
+                Log.e(TAG, "Failed to set media key listener", e);
             }
         }
     }
 
     /**
-     * Unregister a {@link Callback}.
+     * Remove a {@link OnMediaKeyEventDispatchedListener}.
      *
-     * @param callback A {@link Callback}.
+     * @param listener A {@link OnMediaKeyEventDispatchedListener}.
      * @hide
      */
     @SystemApi
     @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
-    public void unregisterCallback(@NonNull Callback callback) {
-        if (callback == null) {
-            throw new NullPointerException("callback shouldn't be null");
+    public void removeOnMediaKeyEventDispatchedListener(
+            @NonNull OnMediaKeyEventDispatchedListener listener) {
+        if (listener == null) {
+            throw new NullPointerException("listener shouldn't be null");
         }
         synchronized (mLock) {
             try {
-                mCallbacks.remove(callback);
-                if (mCallbacks.size() == 0) {
-                    mService.unregisterCallback(mCbStub);
+                mOnMediaKeyEventDispatchedListeners.remove(listener);
+                if (mOnMediaKeyEventDispatchedListeners.size() == 0) {
+                    mService.removeOnMediaKeyEventDispatchedListener(
+                            mOnMediaKeyEventDispatchedListenerStub);
                 }
             } catch (RemoteException e) {
-                Log.e(TAG, "Failed to set media key callback", e);
+                Log.e(TAG, "Failed to set media key event dispatched listener", e);
+            }
+        }
+    }
+
+    /**
+     * Add a {@link OnMediaKeyEventDispatchedListener}.
+     *
+     * @param executor The executor on which the callback should be invoked
+     * @param listener A {@link OnMediaKeyEventSessionChangedListener}.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void addOnMediaKeyEventSessionChangedListener(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnMediaKeyEventSessionChangedListener listener) {
+        if (executor == null) {
+            throw new NullPointerException("executor shouldn't be null");
+        }
+        if (listener == null) {
+            throw new NullPointerException("listener shouldn't be null");
+        }
+        synchronized (mLock) {
+            try {
+                mMediaKeyEventSessionChangedCallbacks.put(listener, executor);
+                executor.execute(
+                        () -> listener.onMediaKeyEventSessionChanged(
+                                mCurMediaKeyEventSessionPackage, mCurMediaKeyEventSession));
+                if (mMediaKeyEventSessionChangedCallbacks.size() == 1) {
+                    mService.addOnMediaKeyEventSessionChangedListener(
+                            mOnMediaKeyEventSessionChangedListenerStub);
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to set media key listener", e);
+            }
+        }
+    }
+
+    /**
+     * Remove a {@link OnMediaKeyEventSessionChangedListener}.
+     *
+     * @param listener A {@link OnMediaKeyEventSessionChangedListener}.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void removeOnMediaKeyEventSessionChangedListener(
+            @NonNull OnMediaKeyEventSessionChangedListener listener) {
+        if (listener == null) {
+            throw new NullPointerException("listener shouldn't be null");
+        }
+        synchronized (mLock) {
+            try {
+                mMediaKeyEventSessionChangedCallbacks.remove(listener);
+                if (mMediaKeyEventSessionChangedCallbacks.size() == 0) {
+                    mService.removeOnMediaKeyEventSessionChangedListener(
+                            mOnMediaKeyEventSessionChangedListenerStub);
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to set media key listener", e);
             }
         }
     }
@@ -900,54 +932,46 @@
     }
 
     /**
-     * Callbacks for the media session service.
-     *
-     * <p>Called when a media key event is dispatched or the addressed player is changed.
-     * The addressed player is either the media session or the media button receiver that will
-     * receive media key events.
+     * Listener to receive when the media session service
      * @hide
      */
     @SystemApi
-    public static abstract class Callback {
+    public interface OnMediaKeyEventDispatchedListener {
         /**
-         * Called when a media key event is dispatched to the media session
-         * through the media session service.
+         * Called when a media key event is dispatched through the media session service. The
+         * session token can be {@link null} if the framework has sent the media key event to the
+         * media button receiver to revive the media app's playback.
+         *
+         * the session is dead when , but the framework sent
          *
          * @param event Dispatched media key event.
-         * @param sessionToken The media session's token.
+         * @param packageName Package
+         * @param sessionToken The media session's token. Can be {@code null}.
          */
-        public abstract void onMediaKeyEventDispatched(KeyEvent event,
-                MediaSession.Token sessionToken);
+        default void onMediaKeyEventDispatched(@NonNull KeyEvent event, @NonNull String packageName,
+                @NonNull MediaSession.Token sessionToken) { }
+    }
 
+    /**
+     * Listener to receive changes in the media key event session, which would receive the media key
+     * event unless specified.
+     * @hide
+     */
+    @SystemApi
+    public interface OnMediaKeyEventSessionChangedListener {
         /**
-         * Called when a media key event is dispatched to the media button receiver
-         * through the media session service.
-         * <p>MediaSessionService may broadcast key events to the media button receiver
-         * when reviving playback after the media session is released.
+         * Called when the media key session is changed to the given media session. The key event
+         * session is the media session which would receive key event by default, unless the caller
+         * has specified the target.
+         * <p>
+         * The session token can be {@link null} if the media button session is unset. In that case,
+         * framework would dispatch to the last sessions's media button receiver.
          *
-         * @param event Dispatched media key event.
-         * @param mediaButtonReceiver The media button receiver.
+         * @param packageName The package name who would receive the media key event. Can be empty.
+         * @param sessionToken The media session's token. Can be {@code null.}
          */
-        public abstract void onMediaKeyEventDispatched(KeyEvent event,
-                ComponentName mediaButtonReceiver);
-
-        /**
-         * Called when the addressed player is changed to a media session.
-         * <p>One of the {@ #onAddressedPlayerChanged} will be also called immediately after
-         * {@link #registerCallback} if the addressed player exists.
-         *
-         * @param sessionToken The media session's token.
-         */
-        public abstract void onAddressedPlayerChanged(MediaSession.Token sessionToken);
-
-        /**
-         * Called when the addressed player is changed to the media button receiver.
-         * <p>One of the {@ #onAddressedPlayerChanged} will be also called immediately after
-         * {@link #registerCallback} if the addressed player exists.
-         *
-         * @param mediaButtonReceiver The media button receiver.
-         */
-        public abstract void onAddressedPlayerChanged(ComponentName mediaButtonReceiver);
+        default void onMediaKeyEventSessionChanged(@NonNull String packageName,
+                @Nullable MediaSession.Token sessionToken) { }
     }
 
     /**
@@ -1149,50 +1173,35 @@
         }
     }
 
-    private final class CallbackStub extends ICallback.Stub {
+    private final class OnMediaKeyEventDispatchedListenerStub
+            extends IOnMediaKeyEventDispatchedListener.Stub {
 
         @Override
-        public void onMediaKeyEventDispatchedToMediaSession(KeyEvent event,
+        public void onMediaKeyEventDispatched(KeyEvent event, String packageName,
                 MediaSession.Token sessionToken) {
             synchronized (mLock) {
-                for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) {
+                for (Map.Entry<OnMediaKeyEventDispatchedListener, Executor> e
+                        : mOnMediaKeyEventDispatchedListeners.entrySet()) {
                     e.getValue().execute(
-                            () -> e.getKey().onMediaKeyEventDispatched(event, sessionToken));
+                            () -> e.getKey().onMediaKeyEventDispatched(event, packageName,
+                                    sessionToken));
                 }
             }
         }
+    }
 
+    private final class OnMediaKeyEventSessionChangedListenerStub
+            extends IOnMediaKeyEventSessionChangedListener.Stub {
         @Override
-        public void onMediaKeyEventDispatchedToMediaButtonReceiver(KeyEvent event,
-                ComponentName mediaButtonReceiver) {
+        public void onMediaKeyEventSessionChanged(String packageName,
+                MediaSession.Token sessionToken) {
             synchronized (mLock) {
-                for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) {
-                    e.getValue().execute(
-                            () -> e.getKey().onMediaKeyEventDispatched(event, mediaButtonReceiver));
-                }
-            }
-        }
-
-        @Override
-        public void onAddressedPlayerChangedToMediaSession(MediaSession.Token sessionToken) {
-            synchronized (mLock) {
-                mCurMediaButtonSession = sessionToken;
-                mCurMediaButtonReceiver = null;
-                for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) {
-                    e.getValue().execute(() -> e.getKey().onAddressedPlayerChanged(sessionToken));
-                }
-            }
-        }
-
-        @Override
-        public void onAddressedPlayerChangedToMediaButtonReceiver(
-                ComponentName mediaButtonReceiver) {
-            synchronized (mLock) {
-                mCurMediaButtonSession = null;
-                mCurMediaButtonReceiver = mediaButtonReceiver;
-                for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) {
-                    e.getValue().execute(() -> e.getKey().onAddressedPlayerChanged(
-                            mediaButtonReceiver));
+                mCurMediaKeyEventSessionPackage = packageName;
+                mCurMediaKeyEventSession = sessionToken;
+                for (Map.Entry<OnMediaKeyEventSessionChangedListener, Executor> e
+                        : mMediaKeyEventSessionChangedCallbacks.entrySet()) {
+                    e.getValue().execute(() -> e.getKey().onMediaKeyEventSessionChanged(packageName,
+                            sessionToken));
                 }
             }
         }
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 16ba63b..0f402eb 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -577,7 +577,7 @@
         try {
             // note - we are relying on a special case in MediaProvider.update() to update
             // the paths for all children in the case where this is a directory.
-            final Uri objectsUri = MediaStore.Files.getMtpObjectsUri(obj.getVolumeName());
+            final Uri objectsUri = MediaStore.Files.getContentUri(obj.getVolumeName());
             mMediaProvider.update(objectsUri, values, PATH_WHERE, whereArgs);
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in mMediaProvider.update", e);
@@ -658,7 +658,7 @@
                 // Old parent exists in MediaProvider - perform a move
                 // note - we are relying on a special case in MediaProvider.update() to update
                 // the paths for all children in the case where this is a directory.
-                final Uri objectsUri = MediaStore.Files.getMtpObjectsUri(obj.getVolumeName());
+                final Uri objectsUri = MediaStore.Files.getContentUri(obj.getVolumeName());
                 mMediaProvider.update(objectsUri, values, PATH_WHERE, whereArgs);
             } else {
                 // Old parent doesn't exist - add the object
@@ -873,7 +873,7 @@
     }
 
     private int findInMedia(MtpStorageManager.MtpObject obj, Path path) {
-        final Uri objectsUri = MediaStore.Files.getMtpObjectsUri(obj.getVolumeName());
+        final Uri objectsUri = MediaStore.Files.getContentUri(obj.getVolumeName());
 
         int ret = -1;
         Cursor c = null;
@@ -893,7 +893,7 @@
     }
 
     private void deleteFromMedia(MtpStorageManager.MtpObject obj, Path path, boolean isDir) {
-        final Uri objectsUri = MediaStore.Files.getMtpObjectsUri(obj.getVolumeName());
+        final Uri objectsUri = MediaStore.Files.getContentUri(obj.getVolumeName());
         try {
             // Delete the object(s) from MediaProvider, but ignore errors.
             if (isDir) {
@@ -921,71 +921,12 @@
 
     @VisibleForNative
     private int[] getObjectReferences(int handle) {
-        MtpStorageManager.MtpObject obj = mManager.getObject(handle);
-        if (obj == null)
-            return null;
-        // Translate this handle to the MediaProvider Handle
-        handle = findInMedia(obj, obj.getPath());
-        if (handle == -1)
-            return null;
-        Uri uri = Files.getMtpReferencesUri(obj.getVolumeName(), handle);
-        Cursor c = null;
-        try {
-            c = mMediaProvider.query(uri, PATH_PROJECTION, null, null, null, null);
-            if (c == null) {
-                return null;
-            }
-                ArrayList<Integer> result = new ArrayList<>();
-                while (c.moveToNext()) {
-                    // Translate result handles back into handles for this session.
-                    String refPath = c.getString(0);
-                    MtpStorageManager.MtpObject refObj = mManager.getByPath(refPath);
-                    if (refObj != null) {
-                        result.add(refObj.getId());
-                    }
-                }
-                return result.stream().mapToInt(Integer::intValue).toArray();
-        } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in getObjectList", e);
-        } finally {
-            if (c != null) {
-                c.close();
-            }
-        }
         return null;
     }
 
     @VisibleForNative
     private int setObjectReferences(int handle, int[] references) {
-        MtpStorageManager.MtpObject obj = mManager.getObject(handle);
-        if (obj == null)
-            return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
-        // Translate this handle to the MediaProvider Handle
-        handle = findInMedia(obj, obj.getPath());
-        if (handle == -1)
-            return MtpConstants.RESPONSE_GENERAL_ERROR;
-        Uri uri = Files.getMtpReferencesUri(obj.getVolumeName(), handle);
-        ArrayList<ContentValues> valuesList = new ArrayList<>();
-        for (int id : references) {
-            // Translate each reference id to the MediaProvider Id
-            MtpStorageManager.MtpObject refObj = mManager.getObject(id);
-            if (refObj == null)
-                continue;
-            int refHandle = findInMedia(refObj, refObj.getPath());
-            if (refHandle == -1)
-                continue;
-            ContentValues values = new ContentValues();
-            values.put(Files.FileColumns._ID, refHandle);
-            valuesList.add(values);
-        }
-        try {
-            if (mMediaProvider.bulkInsert(uri, valuesList.toArray(new ContentValues[0])) > 0) {
-                return MtpConstants.RESPONSE_OK;
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in setObjectReferences", e);
-        }
-        return MtpConstants.RESPONSE_GENERAL_ERROR;
+        return MtpConstants.RESPONSE_OPERATION_NOT_SUPPORTED;
     }
 
     @VisibleForNative
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
index 3258d57..2697a10 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
@@ -29,6 +29,7 @@
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
+
 import com.android.internal.telephony.PhoneConstants;
 
 /**
@@ -138,7 +139,7 @@
                 SubscriptionManager.getDefaultVoiceSubscriptionId());
         logd("onRegisterDefaultNetworkAvail subId: " + subId);
         final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
-        telephonyMgr.carrierActionReportDefaultNetworkStatus(subId, true);
+        telephonyMgr.createForSubscriptionId(subId).reportDefaultNetworkStatus(true);
     }
 
     private static void onDeregisterDefaultNetworkAvail(Intent intent, Context context) {
@@ -146,7 +147,7 @@
                 SubscriptionManager.getDefaultVoiceSubscriptionId());
         logd("onDeregisterDefaultNetworkAvail subId: " + subId);
         final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
-        telephonyMgr.carrierActionReportDefaultNetworkStatus(subId, false);
+        telephonyMgr.createForSubscriptionId(subId).reportDefaultNetworkStatus(false);
     }
 
     private static void onDisableRadio(Intent intent, Context context) {
@@ -154,7 +155,7 @@
                 SubscriptionManager.getDefaultVoiceSubscriptionId());
         logd("onDisableRadio subId: " + subId);
         final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
-        telephonyMgr.carrierActionSetRadioEnabled(subId, !ENABLE);
+        telephonyMgr.createForSubscriptionId(subId).setRadioEnabled(!ENABLE);
     }
 
     private static void onEnableRadio(Intent intent, Context context) {
@@ -162,7 +163,7 @@
                 SubscriptionManager.getDefaultVoiceSubscriptionId());
         logd("onEnableRadio subId: " + subId);
         final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
-        telephonyMgr.carrierActionSetRadioEnabled(subId, ENABLE);
+        telephonyMgr.createForSubscriptionId(subId).setRadioEnabled(ENABLE);
     }
 
     private static void onShowCaptivePortalNotification(Intent intent, Context context) {
@@ -205,7 +206,7 @@
                 SubscriptionManager.getDefaultVoiceSubscriptionId());
         logd("onResetAllCarrierActions subId: " + subId);
         final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
-        telephonyMgr.carrierActionResetAll(subId);
+        telephonyMgr.createForSubscriptionId(subId).resetAllCarrierActions();
     }
 
     private static Notification getNotification(Context context, int titleId, int textId,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
index 9c896c8..bc03c34 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
@@ -164,13 +164,13 @@
         }
     }
 
-    boolean isA2dpPlaying() {
+    boolean isAudioPlaying() {
         if (mService == null) {
             return false;
         }
         List<BluetoothDevice> srcs = mService.getConnectedDevices();
         if (!srcs.isEmpty()) {
-            if (mService.isA2dpPlaying(srcs.get(0))) {
+            if (mService.isAudioPlaying(srcs.get(0))) {
                 return true;
             }
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
index 8f40ab4..80b03a4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
@@ -175,7 +175,7 @@
                     return;
                 }
                 A2dpSinkProfile a2dpSink = mProfileManager.getA2dpSinkProfile();
-                if ((a2dpSink != null) && (a2dpSink.isA2dpPlaying())){
+                if ((a2dpSink != null) && (a2dpSink.isAudioPlaying())) {
                     return;
                 }
             }
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 4a10e85..5d0db01 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -734,7 +734,8 @@
                  Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE,
                  Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE,
                  Settings.Secure.FACE_UNLOCK_RE_ENROLL,
-                 Settings.Secure.TAP_GESTURE);
+                 Settings.Secure.TAP_GESTURE,
+                 Settings.Secure.WINDOW_MAGNIFICATION);
 
     @Test
     public void systemSettingsBackedUpOrBlacklisted() {
diff --git a/packages/SystemUI/res/drawable/ic_control_magnification_grey.xml b/packages/SystemUI/res/drawable/ic_control_magnification_grey.xml
new file mode 100644
index 0000000..80ce8c1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_control_magnification_grey.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2019 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<vector android:height="96dp" android:viewportHeight="24"
+    android:viewportWidth="24" android:width="96dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#757575" android:pathData="M15.54,5.54L13.77,7.3 12,5.54 10.23,7.3 8.46,5.54 12,2zM18.46,15.54l-1.76,-1.77L18.46,12l-1.76,-1.77 1.76,-1.77L22,12zM8.46,18.46l1.77,-1.76L12,18.46l1.77,-1.76 1.77,1.76L12,22zM5.54,8.46l1.76,1.77L5.54,12l1.76,1.77 -1.76,1.77L2,12z"/>
+    <path android:fillColor="#757575" android:pathData="M12,12m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/magnifier_controllers.xml b/packages/SystemUI/res/layout/magnifier_controllers.xml
new file mode 100644
index 0000000..0203cd4
--- /dev/null
+++ b/packages/SystemUI/res/layout/magnifier_controllers.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/magnification_controls_size"
+    android:layout_alignParentBottom="true"
+    android:layout_alignParentEnd="true"
+    android:layout_height="@dimen/magnification_controls_size"
+    android:gravity="center">
+
+  <RelativeLayout
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content">
+
+    <ImageView
+        android:focusable="true"
+        android:id="@+id/controller"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/ic_control_magnification_grey" />
+
+    <View
+        android:id="@+id/left_control"
+        android:layout_width="@dimen/magnifier_left_right_controls_width"
+        android:layout_height="@dimen/magnifier_left_right_controls_height"
+        android:layout_alignLeft="@+id/controller"
+        android:layout_centerVertical="true" />
+
+    <View
+        android:id="@+id/up_control"
+        android:layout_width="@dimen/magnifier_up_down_controls_width"
+        android:layout_height="@dimen/magnifier_up_down_controls_height"
+        android:layout_alignTop="@+id/controller"
+        android:layout_centerHorizontal="true" />
+
+    <View
+        android:id="@+id/right_control"
+        android:layout_width="@dimen/magnifier_left_right_controls_width"
+        android:layout_height="@dimen/magnifier_left_right_controls_height"
+        android:layout_alignRight="@+id/controller"
+        android:layout_centerVertical="true" />
+
+    <View
+        android:id="@+id/down_control"
+        android:layout_width="@dimen/magnifier_up_down_controls_width"
+        android:layout_height="@dimen/magnifier_up_down_controls_height"
+        android:layout_alignBottom="@+id/controller"
+        android:layout_centerHorizontal="true" />
+  </RelativeLayout>
+
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/window_magnifier_view.xml b/packages/SystemUI/res/layout/window_magnifier_view.xml
new file mode 100644
index 0000000..f818612
--- /dev/null
+++ b/packages/SystemUI/res/layout/window_magnifier_view.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+
+    <SurfaceView
+        android:layout_marginStart="@dimen/magnification_border_size"
+        android:layout_marginTop="@dimen/magnification_border_size"
+        android:id="@+id/surface_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+
+        <View
+            android:id="@+id/left_handle"
+            android:layout_width="@dimen/magnification_border_size"
+            android:layout_height="match_parent"
+            android:layout_above="@+id/drag_handle"
+            android:background="@color/magnification_border_color" />
+
+        <View
+            android:id="@+id/top_handle"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/magnification_border_size"
+            android:background="@color/magnification_border_color" />
+
+        <View
+            android:id="@+id/right_handle"
+            android:layout_width="@dimen/magnification_border_size"
+            android:layout_height="match_parent"
+            android:layout_above="@+id/drag_handle"
+            android:layout_alignParentEnd="true"
+            android:background="@color/magnification_border_color" />
+
+        <View
+            android:id="@+id/bottom_handle"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/magnification_border_size"
+            android:layout_above="@+id/drag_handle"
+            android:background="@color/magnification_border_color" />
+
+        <View
+            android:id="@+id/drag_handle"
+            android:layout_width="@dimen/magnification_drag_view_width"
+            android:layout_height="@dimen/magnification_drag_view_height"
+            android:layout_alignParentBottom="true"
+            android:layout_centerHorizontal="true"
+            android:background="@color/magnification_border_color" />
+
+    </RelativeLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 92c7477..c142465 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -211,4 +211,5 @@
     <color name="GM2_green_500">#FF34A853</color>
     <color name="GM2_blue_500">#FF4285F4</color>
 
+    <color name="magnification_border_color">#FF9900</color>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index e896c16..640f31b 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -295,6 +295,7 @@
         <item>com.android.systemui.SizeCompatModeActivityController</item>
         <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
         <item>com.android.systemui.theme.ThemeOverlayController</item>
+        <item>com.android.systemui.accessibility.WindowMagnification</item>
     </string-array>
 
     <!-- SystemUI vender service, used in config_systemUIServiceComponents. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c948116..da0323a 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1139,4 +1139,16 @@
     <dimen name="qs_media_width">350dp</dimen>
     <dimen name="qs_media_padding">8dp</dimen>
     <dimen name="qs_media_corner_radius">10dp</dimen>
+
+    <dimen name="magnification_border_size">5dp</dimen>
+    <dimen name="magnification_frame_move_short">5dp</dimen>
+    <dimen name="magnification_frame_move_long">25dp</dimen>
+    <dimen name="magnification_drag_view_width">100dp</dimen>
+    <dimen name="magnification_drag_view_height">35dp</dimen>
+    <dimen name="magnification_controls_size">90dp</dimen>
+    <dimen name="magnifier_left_right_controls_width">35dp</dimen>
+    <dimen name="magnifier_left_right_controls_height">45dp</dimen>
+    <dimen name="magnifier_up_down_controls_width">45dp</dimen>
+    <dimen name="magnifier_up_down_controls_height">40dp</dimen>
+
 </resources>
diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml
index deae7e2..c1cf7b4 100644
--- a/packages/SystemUI/res/values/integers.xml
+++ b/packages/SystemUI/res/values/integers.xml
@@ -32,4 +32,6 @@
     <!-- Ratio of "right" end of status bar that will swipe to QS. -->
     <integer name="qs_split_fraction">2</integer>
 
+    <integer name="magnification_default_scale">2</integer>
+
 </resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 1053750..bc808b3 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2492,4 +2492,12 @@
 
     <!-- Title of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=25] -->
     <string name="inattentive_sleep_warning_title">Standby</string>
+
+    <!-- Window Magnification strings -->
+    <!-- Title for Magnification Overlay Window [CHAR LIMIT=NONE] -->
+    <string name="magnification_overlay_title">Magnification Overlay Window</string>
+    <!-- Title for Magnification Window [CHAR LIMIT=NONE] -->
+    <string name="magnification_window_title">Magnification Window</string>
+    <!-- Title for Magnification Controls Window [CHAR LIMIT=NONE] -->
+    <string name="magnification_controls_title">Magnification Window Controls</string>
 </resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
index 22d1675c..9f13718 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
@@ -27,6 +27,7 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.util.Log;
+import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 
@@ -215,4 +216,23 @@
     public void removePinnedStackListener(PinnedStackListener listener) {
         mPinnedStackListenerForwarder.removeListener(listener);
     }
+
+    /**
+     * Mirrors a specified display. The SurfaceControl returned is the root of the mirrored
+     * hierarchy.
+     *
+     * @param displayId The id of the display to mirror
+     * @return The SurfaceControl for the root of the mirrored hierarchy.
+     */
+    public SurfaceControl mirrorDisplay(final int displayId) {
+        try {
+            SurfaceControl outSurfaceControl = new SurfaceControl();
+            WindowManagerGlobal.getWindowManagerService().mirrorDisplay(displayId,
+                    outSurfaceControl);
+            return outSurfaceControl;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to reach window manager", e);
+        }
+        return null;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
new file mode 100644
index 0000000..6178ff2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.provider.Settings;
+
+import com.android.systemui.SystemUI;
+import com.android.systemui.dagger.qualifiers.MainHandler;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Class to handle changes to setting window_magnification value.
+ */
+@Singleton
+public class WindowMagnification extends SystemUI {
+    private WindowMagnificationController mWindowMagnificationController;
+    private final Handler mHandler;
+
+    @Inject
+    public WindowMagnification(Context context, @MainHandler Handler mainHandler) {
+        super(context);
+        mHandler = mainHandler;
+    }
+
+    @Override
+    public void start() {
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.WINDOW_MAGNIFICATION),
+                true, new ContentObserver(mHandler) {
+                    @Override
+                    public void onChange(boolean selfChange) {
+                        updateWindowMagnification();
+                    }
+                });
+    }
+
+    private void updateWindowMagnification() {
+        try {
+            boolean enable = Settings.Secure.getInt(mContext.getContentResolver(),
+                    Settings.Secure.WINDOW_MAGNIFICATION) != 0;
+            if (enable) {
+                enableMagnification();
+            } else {
+                disableMagnification();
+            }
+        } catch (Settings.SettingNotFoundException e) {
+            disableMagnification();
+        }
+    }
+
+    private void enableMagnification() {
+        if (mWindowMagnificationController == null) {
+            mWindowMagnificationController = new WindowMagnificationController(mContext, mHandler);
+        }
+        mWindowMagnificationController.createWindowMagnification();
+    }
+
+    private void disableMagnification() {
+        if (mWindowMagnificationController != null) {
+            mWindowMagnificationController.deleteWindowMagnification();
+        }
+        mWindowMagnificationController = null;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
new file mode 100644
index 0000000..e3694ac
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.os.Handler;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+import com.android.systemui.shared.system.WindowManagerWrapper;
+
+/**
+ * Class to handle adding and removing a window magnification.
+ */
+public class WindowMagnificationController implements View.OnClickListener,
+        View.OnLongClickListener, View.OnTouchListener, SurfaceHolder.Callback {
+    private final int mBorderSize;
+    private final int mMoveFrameAmountShort;
+    private final int mMoveFrameAmountLong;
+
+    private final Context mContext;
+    private final Point mDisplaySize = new Point();
+    private final int mDisplayId;
+    private final Handler mHandler;
+    private final Rect mMagnificationFrame = new Rect();
+    private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+
+    private final WindowManager mWm;
+
+    private float mScale;
+
+    private final Rect mTmpRect = new Rect();
+
+    // The root of the mirrored content
+    private SurfaceControl mMirrorSurface;
+
+    private boolean mIsPressedDown;
+
+    private View mLeftControl;
+    private View mUpControl;
+    private View mRightControl;
+    private View mBottomControl;
+
+    private View mDragView;
+    private View mLeftDrag;
+    private View mTopDrag;
+    private View mRightDrag;
+    private View mBottomDrag;
+
+    private final PointF mLastDrag = new PointF();
+    private final Point mMoveWindowOffset = new Point();
+
+    private View mMirrorView;
+    private SurfaceView mMirrorSurfaceView;
+    private View mControlsView;
+    private View mOverlayView;
+
+    private MoveMirrorRunnable mMoveMirrorRunnable = new MoveMirrorRunnable();
+
+    WindowMagnificationController(Context context, Handler handler) {
+        mContext = context;
+        mHandler = handler;
+        Display display = mContext.getDisplay();
+        display.getSize(mDisplaySize);
+        mDisplayId = mContext.getDisplayId();
+
+        mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+
+        Resources r = context.getResources();
+        mBorderSize = (int) r.getDimension(R.dimen.magnification_border_size);
+        mMoveFrameAmountShort = (int) r.getDimension(R.dimen.magnification_frame_move_short);
+        mMoveFrameAmountLong = (int) r.getDimension(R.dimen.magnification_frame_move_long);
+
+        mScale = r.getInteger(R.integer.magnification_default_scale);
+    }
+
+    /**
+     * Creates a magnification window if it doesn't already exist.
+     */
+    void createWindowMagnification() {
+        if (mMirrorView != null) {
+            return;
+        }
+        createOverlayWindow();
+    }
+
+    private void createOverlayWindow() {
+        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+                WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT,
+                WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY,
+                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+                PixelFormat.TRANSPARENT);
+        params.gravity = Gravity.TOP | Gravity.LEFT;
+        params.token = new Binder();
+        params.setTitle(mContext.getString(R.string.magnification_overlay_title));
+
+        mOverlayView = new View(mContext);
+        mOverlayView.getViewTreeObserver().addOnWindowAttachListener(
+                new ViewTreeObserver.OnWindowAttachListener() {
+                    @Override
+                    public void onWindowAttached() {
+                        mOverlayView.getViewTreeObserver().removeOnWindowAttachListener(this);
+                        createMirrorWindow();
+                        createControls();
+                    }
+
+                    @Override
+                    public void onWindowDetached() {
+
+                    }
+                });
+
+        mOverlayView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                | View.SYSTEM_UI_FLAG_FULLSCREEN
+                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
+
+        mWm.addView(mOverlayView, params);
+    }
+
+    /**
+     * Deletes the magnification window.
+     */
+    void deleteWindowMagnification() {
+        if (mMirrorSurface != null) {
+            mTransaction.remove(mMirrorSurface).apply();
+            mMirrorSurface = null;
+        }
+
+        if (mOverlayView != null) {
+            mWm.removeView(mOverlayView);
+            mOverlayView = null;
+        }
+
+        if (mMirrorView != null) {
+            mWm.removeView(mMirrorView);
+            mMirrorView = null;
+        }
+
+        if (mControlsView != null) {
+            mWm.removeView(mControlsView);
+            mControlsView = null;
+        }
+    }
+
+    private void createMirrorWindow() {
+        setInitialStartBounds();
+
+        // The window should be the size the mirrored surface will be but also add room for the
+        // border and the drag handle.
+        int dragViewHeight = (int) mContext.getResources().getDimension(
+                R.dimen.magnification_drag_view_height);
+        int windowWidth = mMagnificationFrame.width() + 2 * mBorderSize;
+        int windowHeight = mMagnificationFrame.height() + dragViewHeight + 2 * mBorderSize;
+
+        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+                windowWidth, windowHeight,
+                WindowManager.LayoutParams.TYPE_APPLICATION_PANEL,
+                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+                PixelFormat.TRANSPARENT);
+        params.gravity = Gravity.TOP | Gravity.LEFT;
+        params.token = mOverlayView.getWindowToken();
+        params.x = mMagnificationFrame.left;
+        params.y = mMagnificationFrame.top;
+        params.setTitle(mContext.getString(R.string.magnification_window_title));
+
+        mMirrorView = LayoutInflater.from(mContext).inflate(R.layout.window_magnifier_view, null);
+        mMirrorSurfaceView = mMirrorView.findViewById(R.id.surface_view);
+        // This places the SurfaceView's SurfaceControl above the ViewRootImpl's SurfaceControl to
+        // ensure the mirrored area can get touch instead of going to the window
+        mMirrorSurfaceView.setZOrderOnTop(true);
+
+        mMirrorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                | View.SYSTEM_UI_FLAG_FULLSCREEN
+                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
+        mWm.addView(mMirrorView, params);
+
+        SurfaceHolder holder = mMirrorSurfaceView.getHolder();
+        holder.addCallback(this);
+        holder.setFormat(PixelFormat.RGBA_8888);
+
+        addDragTouchListeners();
+    }
+
+    private void createControls() {
+        int controlsSize = (int) mContext.getResources().getDimension(
+                R.dimen.magnification_controls_size);
+
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(controlsSize, controlsSize,
+                WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL,
+                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+                PixelFormat.RGBA_8888);
+        lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
+        lp.token = mOverlayView.getWindowToken();
+        lp.setTitle(mContext.getString(R.string.magnification_controls_title));
+
+        mControlsView = LayoutInflater.from(mContext).inflate(R.layout.magnifier_controllers, null);
+        mWm.addView(mControlsView, lp);
+
+        mLeftControl = mControlsView.findViewById(R.id.left_control);
+        mUpControl = mControlsView.findViewById(R.id.up_control);
+        mRightControl = mControlsView.findViewById(R.id.right_control);
+        mBottomControl = mControlsView.findViewById(R.id.down_control);
+
+        mLeftControl.setOnClickListener(this);
+        mUpControl.setOnClickListener(this);
+        mRightControl.setOnClickListener(this);
+        mBottomControl.setOnClickListener(this);
+
+        mLeftControl.setOnLongClickListener(this);
+        mUpControl.setOnLongClickListener(this);
+        mRightControl.setOnLongClickListener(this);
+        mBottomControl.setOnLongClickListener(this);
+
+        mLeftControl.setOnTouchListener(this);
+        mUpControl.setOnTouchListener(this);
+        mRightControl.setOnTouchListener(this);
+        mBottomControl.setOnTouchListener(this);
+    }
+
+    private void setInitialStartBounds() {
+        // Sets the initial frame area for the mirror and places it in the center of the display.
+        int initSize = Math.min(mDisplaySize.x, mDisplaySize.y) / 2;
+        int initX = mDisplaySize.x / 2 - initSize / 2;
+        int initY = mDisplaySize.y / 2 - initSize / 2;
+        mMagnificationFrame.set(initX, initY, initX + initSize, initY + initSize);
+    }
+
+    /**
+     * This is called once the surfaceView is created so the mirrored content can be placed as a
+     * child of the surfaceView.
+     */
+    private void createMirror() {
+        mMirrorSurface = WindowManagerWrapper.getInstance().mirrorDisplay(mDisplayId);
+        if (!mMirrorSurface.isValid()) {
+            return;
+        }
+        mTransaction.show(mMirrorSurface)
+                .reparent(mMirrorSurface, mMirrorSurfaceView.getSurfaceControl());
+
+        modifyWindowMagnification(mTransaction);
+        mTransaction.apply();
+    }
+
+    private void addDragTouchListeners() {
+        mDragView = mMirrorView.findViewById(R.id.drag_handle);
+        mLeftDrag = mMirrorView.findViewById(R.id.left_handle);
+        mTopDrag = mMirrorView.findViewById(R.id.top_handle);
+        mRightDrag = mMirrorView.findViewById(R.id.right_handle);
+        mBottomDrag = mMirrorView.findViewById(R.id.bottom_handle);
+
+        mDragView.setOnTouchListener(this);
+        mLeftDrag.setOnTouchListener(this);
+        mTopDrag.setOnTouchListener(this);
+        mRightDrag.setOnTouchListener(this);
+        mBottomDrag.setOnTouchListener(this);
+    }
+
+    /**
+     * Modifies the placement of the mirrored content.
+     */
+    private void modifyWindowMagnification(SurfaceControl.Transaction t) {
+        Rect sourceBounds = getSourceBounds(mMagnificationFrame, mScale);
+        // The final destination for the magnification surface should be at 0,0 since the
+        // ViewRootImpl's position will change
+        mTmpRect.set(0, 0, mMagnificationFrame.width(), mMagnificationFrame.height());
+
+        WindowManager.LayoutParams params =
+                (WindowManager.LayoutParams) mMirrorView.getLayoutParams();
+        params.x = mMagnificationFrame.left;
+        params.y = mMagnificationFrame.top;
+        mWm.updateViewLayout(mMirrorView, params);
+
+        t.setGeometry(mMirrorSurface, sourceBounds, mTmpRect, Surface.ROTATION_0);
+    }
+
+    @Override
+    public void onClick(View v) {
+        setMoveOffset(v, mMoveFrameAmountShort);
+        moveMirrorFromControls();
+    }
+
+    @Override
+    public boolean onLongClick(View v) {
+        mIsPressedDown = true;
+        setMoveOffset(v, mMoveFrameAmountLong);
+        mHandler.post(mMoveMirrorRunnable);
+        return true;
+    }
+
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+        if (v == mLeftControl || v == mUpControl || v == mRightControl || v == mBottomControl) {
+            return handleControlTouchEvent(event);
+        } else if (v == mDragView || v == mLeftDrag || v == mTopDrag || v == mRightDrag
+                || v == mBottomDrag) {
+            return handleDragTouchEvent(event);
+        }
+        return false;
+    }
+
+    private boolean handleControlTouchEvent(MotionEvent event) {
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                mIsPressedDown = false;
+                break;
+        }
+        return false;
+    }
+
+    private boolean handleDragTouchEvent(MotionEvent event) {
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                mLastDrag.set(event.getRawX(), event.getRawY());
+                return true;
+            case MotionEvent.ACTION_MOVE:
+                int xDiff = (int) (event.getRawX() - mLastDrag.x);
+                int yDiff = (int) (event.getRawY() - mLastDrag.y);
+                mMagnificationFrame.offset(xDiff, yDiff);
+                mLastDrag.set(event.getRawX(), event.getRawY());
+                modifyWindowMagnification(mTransaction);
+                mTransaction.apply();
+                return true;
+        }
+        return false;
+    }
+
+    private void setMoveOffset(View v, int moveFrameAmount) {
+        mMoveWindowOffset.set(0, 0);
+
+        if (v == mLeftControl) {
+            mMoveWindowOffset.x = -moveFrameAmount;
+        } else if (v == mUpControl) {
+            mMoveWindowOffset.y = -moveFrameAmount;
+        } else if (v == mRightControl) {
+            mMoveWindowOffset.x = moveFrameAmount;
+        } else if (v == mBottomControl) {
+            mMoveWindowOffset.y = moveFrameAmount;
+        }
+    }
+
+    private void moveMirrorFromControls() {
+        mMagnificationFrame.offset(mMoveWindowOffset.x, mMoveWindowOffset.y);
+
+        modifyWindowMagnification(mTransaction);
+        mTransaction.apply();
+    }
+
+    /**
+     * Calculates the desired source bounds. This will be the area under from the center of  the
+     * displayFrame, factoring in scale.
+     */
+    private Rect getSourceBounds(Rect displayFrame, float scale) {
+        int halfWidth = displayFrame.width() / 2;
+        int halfHeight = displayFrame.height() / 2;
+        int left = displayFrame.left + (halfWidth - (int) (halfWidth / scale));
+        int right = displayFrame.right - (halfWidth - (int) (halfWidth / scale));
+        int top = displayFrame.top + (halfHeight - (int) (halfHeight / scale));
+        int bottom = displayFrame.bottom - (halfHeight - (int) (halfHeight / scale));
+        return new Rect(left, top, right, bottom);
+    }
+
+    @Override
+    public void surfaceCreated(SurfaceHolder holder) {
+        createMirror();
+    }
+
+    @Override
+    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+    }
+
+    @Override
+    public void surfaceDestroyed(SurfaceHolder holder) {
+    }
+
+    class MoveMirrorRunnable implements Runnable {
+        @Override
+        public void run() {
+            if (mIsPressedDown) {
+                moveMirrorFromControls();
+                mHandler.postDelayed(mMoveMirrorRunnable, 100);
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/OWNERS b/packages/SystemUI/src/com/android/systemui/biometrics/OWNERS
new file mode 100644
index 0000000..8765c9a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/OWNERS
@@ -0,0 +1,7 @@
+set noparent
+
+kchyn@google.com
+jaggies@google.com
+curtislb@google.com
+ilyamaty@google.com
+joshmccloskey@google.com
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index 3cf14d6..99dd5e2 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -21,6 +21,7 @@
 import com.android.systemui.SizeCompatModeActivityController;
 import com.android.systemui.SliceBroadcastRelayHandler;
 import com.android.systemui.SystemUI;
+import com.android.systemui.accessibility.WindowMagnification;
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.globalactions.GlobalActionsComponent;
 import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -156,4 +157,10 @@
     @IntoMap
     @ClassKey(VolumeUI.class)
     public abstract SystemUI bindVolumeUI(VolumeUI sysui);
+
+    /** Inject into WindowMagnification. */
+    @Binds
+    @IntoMap
+    @ClassKey(WindowMagnification.class)
+    public abstract SystemUI bindWindowMagnification(WindowMagnification sysui);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java
index 9ae3882..ec1efa5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java
@@ -24,6 +24,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Represents a set of grouped notifications. The final notification list is usually a mix of
@@ -57,15 +58,22 @@
 
     @VisibleForTesting
     public void setSummary(@Nullable NotificationEntry summary) {
-        mSummary = summary;
+        if (!Objects.equals(mSummary, summary)) {
+            mSummary = summary;
+            onGroupingUpdated();
+        }
     }
 
     void clearChildren() {
-        mChildren.clear();
+        if (mChildren.size() != 0) {
+            mChildren.clear();
+            onGroupingUpdated();
+        }
     }
 
     void addChild(NotificationEntry child) {
         mChildren.add(child);
+        onGroupingUpdated();
     }
 
     void sortChildren(Comparator<? super NotificationEntry> c) {
@@ -77,4 +85,5 @@
     }
 
     public static final GroupEntry ROOT_ENTRY = new GroupEntry("<root>");
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
index 6ce7fd9..052473a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
@@ -19,6 +19,14 @@
 import android.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dependency;
+import com.android.systemui.statusbar.notification.collection.provider.DerivedMember;
+import com.android.systemui.statusbar.notification.collection.provider.IsHighPriorityProvider;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
 
 /**
  * Abstract superclass for top-level entries, i.e. things that can appear in the final notification
@@ -26,14 +34,23 @@
  */
 public abstract class ListEntry {
     private final String mKey;
+    private final IsHighPriorityProvider mIsHighPriorityProvider = new IsHighPriorityProvider();
+    private final List<DerivedMember> mDerivedMemberList = Arrays.asList(mIsHighPriorityProvider);
 
     @Nullable private GroupEntry mParent;
     @Nullable private GroupEntry mPreviousParent;
     private int mSection;
     int mFirstAddedIteration = -1;
 
+    // TODO: (b/145659174) remove groupManager when moving to NewNotifPipeline. Logic
+    //  replaced in GroupEntry and NotifListBuilderImpl
+    private final NotificationGroupManager mGroupManager;
+
     ListEntry(String key) {
         mKey = key;
+
+        // TODO: (b/145659174) remove
+        mGroupManager = Dependency.get(NotificationGroupManager.class);
     }
 
     public String getKey() {
@@ -53,7 +70,11 @@
 
     @VisibleForTesting
     public void setParent(@Nullable GroupEntry parent) {
-        mParent = parent;
+        if (!Objects.equals(mParent, parent)) {
+            invalidateParent();
+            mParent = parent;
+            onGroupingUpdated();
+        }
     }
 
     @Nullable public GroupEntry getPreviousParent() {
@@ -72,4 +93,58 @@
     void setSection(int section) {
         mSection = section;
     }
+
+    /**
+     * Resets the cached values of DerivedMembers.
+     */
+    void invalidateDerivedMembers() {
+        for (int i = 0; i < mDerivedMemberList.size(); i++) {
+            mDerivedMemberList.get(i).invalidate();
+        }
+    }
+
+    /**
+     * Whether this notification is shown to the user as a high priority notification: visible on
+     * the lock screen/status bar and in the top section in the shade.
+     */
+    public boolean isHighPriority() {
+        return mIsHighPriorityProvider.get(this);
+    }
+
+    private void invalidateParent() {
+        // invalidate our parent (GroupEntry) since DerivedMembers may be dependent on children
+        if (getParent() != null) {
+            getParent().invalidateDerivedMembers();
+        }
+
+        // TODO: (b/145659174) remove
+        final NotificationEntry notifEntry = getRepresentativeEntry();
+        if (notifEntry != null && mGroupManager.isGroupChild(notifEntry.getSbn())) {
+            NotificationEntry summary = mGroupManager.getLogicalGroupSummary(notifEntry.getSbn());
+            if (summary != null) {
+                summary.invalidateDerivedMembers();
+            }
+        }
+    }
+
+    void onGroupingUpdated() {
+        for (int i = 0; i < mDerivedMemberList.size(); i++) {
+            mDerivedMemberList.get(i).onGroupingUpdated();
+        }
+        invalidateParent();
+    }
+
+    void onSbnUpdated() {
+        for (int i = 0; i < mDerivedMemberList.size(); i++) {
+            mDerivedMemberList.get(i).onSbnUpdated();
+        }
+        invalidateParent();
+    }
+
+    void onRankingUpdated() {
+        for (int i = 0; i < mDerivedMemberList.size(); i++) {
+            mDerivedMemberList.get(i).onRankingUpdated();
+        }
+        invalidateParent();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 232fb6d..de16ef5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -21,7 +21,6 @@
 import static android.app.Notification.CATEGORY_EVENT;
 import static android.app.Notification.CATEGORY_MESSAGE;
 import static android.app.Notification.CATEGORY_REMINDER;
-import static android.app.Notification.EXTRA_MESSAGES;
 import static android.app.Notification.FLAG_BUBBLE;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
@@ -42,7 +41,6 @@
 import android.content.Context;
 import android.graphics.drawable.Icon;
 import android.os.Bundle;
-import android.os.Parcelable;
 import android.os.SystemClock;
 import android.service.notification.NotificationListenerService.Ranking;
 import android.service.notification.SnoozeCriterion;
@@ -92,7 +90,6 @@
     private StatusBarNotification mSbn;
     private Ranking mRanking;
 
-
     /*
      * Bookkeeping members
      */
@@ -120,7 +117,6 @@
     public int targetSdk;
     private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
     public CharSequence remoteInputText;
-    private final List<Person> mAssociatedPeople = new ArrayList<>();
     private Notification.BubbleMetadata mBubbleMetadata;
 
     /**
@@ -157,12 +153,6 @@
      */
     private boolean hasSentReply;
 
-    /**
-     * Whether this notification is shown to the user as a high priority notification: visible on
-     * the lock screen/status bar and in the top section in the shade.
-     */
-    private boolean mHighPriority;
-
     private boolean mSensitive = true;
     private Runnable mOnSensitiveChangedListener;
     private boolean mAutoHeadsUp;
@@ -212,9 +202,11 @@
                     + " doesn't match existing key " + mKey);
         }
 
-        mSbn = sbn;
-        mBubbleMetadata = mSbn.getNotification().getBubbleMetadata();
-        updatePeopleList();
+        if (!Objects.equals(mSbn, sbn)) {
+            mSbn = sbn;
+            mBubbleMetadata = mSbn.getNotification().getBubbleMetadata();
+            onSbnUpdated();
+        }
     }
 
     /**
@@ -239,10 +231,12 @@
                     + " doesn't match existing key " + mKey);
         }
 
-        mRanking = ranking;
+        if (!Objects.equals(mRanking, ranking)) {
+            mRanking = ranking;
+            onRankingUpdated();
+        }
     }
 
-
     /*
      * Convenience getters for SBN and Ranking members
      */
@@ -304,49 +298,10 @@
         return interruption;
     }
 
-    public boolean isHighPriority() {
-        return mHighPriority;
-    }
-
-    public void setIsHighPriority(boolean highPriority) {
-        this.mHighPriority = highPriority;
-    }
-
     public boolean isBubble() {
         return (mSbn.getNotification().flags & FLAG_BUBBLE) != 0;
     }
 
-    private void updatePeopleList() {
-        mAssociatedPeople.clear();
-
-        Bundle extras = mSbn.getNotification().extras;
-        if (extras == null) {
-            return;
-        }
-
-        List<Person> p = extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST);
-
-        if (p != null) {
-            mAssociatedPeople.addAll(p);
-        }
-
-        if (Notification.MessagingStyle.class.equals(
-                mSbn.getNotification().getNotificationStyle())) {
-            final Parcelable[] messages = extras.getParcelableArray(EXTRA_MESSAGES);
-            if (!ArrayUtils.isEmpty(messages)) {
-                for (Notification.MessagingStyle.Message message :
-                        Notification.MessagingStyle.Message
-                                .getMessagesFromBundleArray(messages)) {
-                    mAssociatedPeople.add(message.getSenderPerson());
-                }
-            }
-        }
-    }
-
-    boolean hasAssociatedPeople() {
-        return mAssociatedPeople.size() > 0;
-    }
-
     /**
      * Returns the data needed for a bubble for this notification, if it exists.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
index 48a4882..7010943 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
@@ -16,14 +16,11 @@
 
 package com.android.systemui.statusbar.notification.collection
 
-import android.app.NotificationManager.IMPORTANCE_DEFAULT
 import android.app.NotificationManager.IMPORTANCE_HIGH
-import android.app.NotificationManager.IMPORTANCE_LOW
 import android.app.NotificationManager.IMPORTANCE_MIN
 import android.service.notification.NotificationListenerService.Ranking
 import android.service.notification.NotificationListenerService.RankingMap
 import android.service.notification.StatusBarNotification
-import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.statusbar.NotificationMediaManager
 import com.android.systemui.statusbar.notification.NotificationFilter
 import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
@@ -105,44 +102,6 @@
         return entry.key == mediaManager.mediaNotificationKey && importance > IMPORTANCE_MIN
     }
 
-    @VisibleForTesting
-    protected fun isHighPriority(entry: NotificationEntry): Boolean {
-        if (entry.importance >= IMPORTANCE_DEFAULT ||
-                hasHighPriorityCharacteristics(entry)) {
-            return true
-        }
-
-        if (groupManager.isSummaryOfGroup(entry.sbn)) {
-            val logicalChildren = groupManager.getLogicalChildren(entry.sbn)
-            for (child in logicalChildren) {
-                if (isHighPriority(child)) {
-                    return true
-                }
-            }
-        }
-
-        return false
-    }
-
-    private fun hasHighPriorityCharacteristics(entry: NotificationEntry): Boolean {
-        val c = entry.channel
-        val n = entry.sbn.notification
-
-        if ((n.isForegroundService && entry.ranking.importance >= IMPORTANCE_LOW) ||
-                n.hasMediaSession() ||
-                entry.isPeopleNotification()) {
-            // Users who have long pressed and demoted to silent should not see the notification
-            // in the top section
-            if (c != null && c.hasUserSetImportance()) {
-                return false
-            }
-
-            return true
-        }
-
-        return false
-    }
-
     fun updateRanking(
         newRankingMap: RankingMap?,
         entries: Collection<NotificationEntry>,
@@ -219,7 +178,10 @@
                         // TODO: notify group manager here?
                         groupManager.onEntryUpdated(entry, oldSbn)
                     }
-                    entry.setIsHighPriority(isHighPriority(entry))
+
+                    // TODO: (b/145659174) remove after moving to new NotifPipeline
+                    // (should be able to remove all groupManager code post-migration)
+                    entry.invalidateDerivedMembers()
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index 4413dc4..232246e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -37,6 +37,8 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.collection.GroupEntry;
+import com.android.systemui.statusbar.notification.collection.ListEntry;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
@@ -133,8 +135,8 @@
                 // to be shown on the lockscreen
                 // TODO: grouping hasn't happened yet (b/145134683)
                 if (entry.getParent() != null) {
-                    final NotificationEntry summary = entry.getParent().getRepresentativeEntry();
-                    if (priorityExceedsLockscreenShowingThreshold(summary)) {
+                    final GroupEntry parent = entry.getParent();
+                    if (priorityExceedsLockscreenShowingThreshold(parent)) {
                         return false;
                     }
                 }
@@ -144,7 +146,7 @@
         }
     };
 
-    private boolean priorityExceedsLockscreenShowingThreshold(NotificationEntry entry) {
+    private boolean priorityExceedsLockscreenShowingThreshold(ListEntry entry) {
         if (entry == null) {
             return false;
         }
@@ -154,7 +156,7 @@
             //  correctly updated before reaching this point (b/145134683)
             return entry.isHighPriority();
         } else {
-            return !entry.getRanking().isAmbient();
+            return !entry.getRepresentativeEntry().getRanking().isAmbient();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/DerivedMember.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/DerivedMember.java
new file mode 100644
index 0000000..815e6f7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/DerivedMember.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.provider;
+/**
+ * Caches a computed value until invalidate() is called
+ * @param <Parent> Object used to computeValue
+ * @param <Value> type of value to cache until invalidate is called
+ */
+public abstract class DerivedMember<Parent, Value> {
+    private Value mValue;
+    protected abstract Value computeValue(Parent parent);
+
+    /**
+     * Gets the last cached value, else recomputes the value.
+     */
+    public Value get(Parent parent) {
+        if (mValue == null) {
+            mValue = computeValue(parent);
+        }
+        return mValue;
+    }
+
+    /**
+     * Resets the cached value.
+     * Next time "get" is called, the value is recomputed.
+     */
+    public void invalidate() {
+        mValue = null;
+    }
+
+    /**
+     * Called when a NotificationEntry's status bar notification has updated.
+     * Derived members can invalidate here.
+     */
+    public void onSbnUpdated() {}
+
+    /**
+     * Called when a NotificationEntry's Ranking has updated.
+     * Derived members can invalidate here.
+     */
+    public void onRankingUpdated() {}
+
+    /**
+     * Called when a ListEntry's grouping information (parent or children) has changed.
+     * Derived members can invalidate here.
+     */
+    public void onGroupingUpdated() {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/IsHighPriorityProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/IsHighPriorityProvider.java
new file mode 100644
index 0000000..76e256b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/IsHighPriorityProvider.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.provider;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.Person;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.statusbar.notification.collection.GroupEntry;
+import com.android.systemui.statusbar.notification.collection.ListEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Whether the ListEntry is shown to the user as a high priority notification: visible on
+ * the lock screen/status bar and in the top section in the shade.
+ *
+ * A NotificationEntry is considered high priority if it:
+ *  - has importance greater than or equal to IMPORTANCE_DEFAULT
+ *  OR
+ *  - their importance has NOT been set to a low priority option by the user AND the notification
+ *  fulfills one of the following:
+ *      - has a person associated with it
+ *      - has a media session associated with it
+ *      - has messaging style
+ *
+ * A GroupEntry is considered high priority if its representativeEntry (summary) or children are
+ * high priority
+ */
+public class IsHighPriorityProvider extends DerivedMember<ListEntry, Boolean> {
+    // TODO: (b/145659174) remove groupManager when moving to NewNotifPipeline. Logic
+    //  replaced in GroupEntry and NotifListBuilderImpl
+    private final NotificationGroupManager mGroupManager;
+
+
+    public IsHighPriorityProvider() {
+        // TODO: (b/145659174) remove
+        mGroupManager = Dependency.get(NotificationGroupManager.class);
+    }
+
+    @Override
+    protected Boolean computeValue(ListEntry entry) {
+        if (entry == null) {
+            return false;
+        }
+
+        return isHighPriority(entry);
+    }
+
+    private boolean isHighPriority(ListEntry listEntry) {
+        // requires groups have been set (AFTER PipelineState.STATE_TRANSFORMING)
+        final NotificationEntry notifEntry = listEntry.getRepresentativeEntry();
+        return notifEntry.getRanking().getImportance() >= NotificationManager.IMPORTANCE_DEFAULT
+                || hasHighPriorityCharacteristics(notifEntry)
+                || hasHighPriorityChild(listEntry);
+
+    }
+
+    private boolean hasHighPriorityChild(ListEntry entry) {
+        // TODO: (b/145659174) remove
+        if (entry instanceof NotificationEntry) {
+            NotificationEntry notifEntry = (NotificationEntry) entry;
+            if (mGroupManager.isSummaryOfGroup(notifEntry.getSbn())) {
+                List<NotificationEntry> logicalChildren =
+                        mGroupManager.getLogicalChildren(notifEntry.getSbn());
+                for (NotificationEntry child : logicalChildren) {
+                    if (child.isHighPriority()) {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        if (entry instanceof GroupEntry) {
+            for (NotificationEntry child : ((GroupEntry) entry).getChildren()) {
+                if (child.isHighPriority()) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private boolean hasHighPriorityCharacteristics(NotificationEntry entry) {
+        return !hasUserSetImportance(entry)
+                && (isImportantOngoing(entry)
+                || entry.getSbn().getNotification().hasMediaSession()
+                || hasPerson(entry)
+                || isMessagingStyle(entry));
+    }
+
+    private boolean isImportantOngoing(NotificationEntry entry) {
+        return entry.getSbn().getNotification().isForegroundService()
+                && entry.getRanking().getImportance() >= NotificationManager.IMPORTANCE_LOW;
+    }
+
+    private boolean isMessagingStyle(NotificationEntry entry) {
+        return Notification.MessagingStyle.class.equals(
+                entry.getSbn().getNotification().getNotificationStyle());
+    }
+
+    private boolean hasPerson(NotificationEntry entry) {
+        // TODO: cache favorite and recent contacts to check contact affinity
+        Notification notification = entry.getSbn().getNotification();
+        ArrayList<Person> people = notification.extras != null
+                ? notification.extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST)
+                : new ArrayList<>();
+        return people != null && !people.isEmpty();
+    }
+
+    private boolean hasUserSetImportance(NotificationEntry entry) {
+        return entry.getRanking().getChannel() != null
+                && entry.getRanking().getChannel().hasUserSetImportance();
+    }
+
+    @Override
+    public void onSbnUpdated() {
+        invalidate();
+    }
+
+    @Override
+    public void onRankingUpdated() {
+        invalidate();
+    }
+
+    @Override
+    public void onGroupingUpdated() {
+        invalidate();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index ba7b2e2..cef210c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -26,12 +26,14 @@
 import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
 import android.app.KeyguardManager;
+import android.app.Notification;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -198,11 +200,13 @@
         Settings.Secure.putInt(mContext.getContentResolver(),
                 Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 0);
 
+        final Notification notification = mock(Notification.class);
+        when(notification.isForegroundService()).thenReturn(true);
         NotificationEntry entry = new NotificationEntryBuilder()
                 .setImportance(IMPORTANCE_LOW)
+                .setNotification(notification)
                 .build();
         entry.setBucket(BUCKET_SILENT);
-        entry.setIsHighPriority(true);
         assertFalse(mLockscreenUserManager.shouldShowOnKeyguard(entry));
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java
index d003b99..5310dd8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java
@@ -76,6 +76,7 @@
         mSmartActions = copyList(ranking.getSmartActions());
         mSmartReplies = copyList(ranking.getSmartReplies());
         mCanBubble = ranking.canBubble();
+        mIsVisuallyInterruptive = ranking.visuallyInterruptive();
     }
 
     public Ranking build() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryTest.java
new file mode 100644
index 0000000..721bbdc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection;
+
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_MIN;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationEntryBuilder;
+import com.android.systemui.statusbar.RankingBuilder;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class GroupEntryTest extends SysuiTestCase {
+    @Test
+    public void testIsHighPriority_addChild() {
+        // GIVEN a GroupEntry with a lowPrioritySummary and no children
+        final GroupEntry parentEntry = new GroupEntry("test_group_key");
+        final NotificationEntry lowPrioritySummary = createNotifEntry(false);
+        setSummary(parentEntry, lowPrioritySummary);
+        assertFalse(parentEntry.isHighPriority());
+
+        // WHEN we add a high priority child and invalidate derived members
+        addChild(parentEntry, createNotifEntry(true));
+        parentEntry.invalidateDerivedMembers();
+
+        // THEN the GroupEntry's priority is updated to high even though the summary is still low
+        // priority
+        assertTrue(parentEntry.isHighPriority());
+        assertFalse(lowPrioritySummary.isHighPriority());
+    }
+
+    @Test
+    public void testIsHighPriority_clearChildren() {
+        // GIVEN a GroupEntry with a lowPrioritySummary and high priority children
+        final GroupEntry parentEntry = new GroupEntry("test_group_key");
+        setSummary(parentEntry, createNotifEntry(false));
+        addChild(parentEntry, createNotifEntry(true));
+        addChild(parentEntry, createNotifEntry(true));
+        addChild(parentEntry, createNotifEntry(true));
+        assertTrue(parentEntry.isHighPriority());
+
+        // WHEN we clear the children and invalidate derived members
+        parentEntry.clearChildren();
+        parentEntry.invalidateDerivedMembers();
+
+        // THEN the parentEntry isn't high priority anymore
+        assertFalse(parentEntry.isHighPriority());
+    }
+
+    @Test
+    public void testIsHighPriority_summaryUpdated() {
+        // GIVEN a GroupEntry with a lowPrioritySummary and no children
+        final GroupEntry parentEntry = new GroupEntry("test_group_key");
+        final NotificationEntry lowPrioritySummary = createNotifEntry(false);
+        setSummary(parentEntry, lowPrioritySummary);
+        assertFalse(parentEntry.isHighPriority());
+
+        // WHEN the summary changes to high priority and invalidates its derived members
+        lowPrioritySummary.setRanking(
+                new RankingBuilder()
+                        .setKey(lowPrioritySummary.getKey())
+                        .setImportance(IMPORTANCE_HIGH)
+                        .build());
+        lowPrioritySummary.invalidateDerivedMembers();
+        assertTrue(lowPrioritySummary.isHighPriority());
+
+        // THEN the GroupEntry's priority is updated to high
+        assertTrue(parentEntry.isHighPriority());
+    }
+
+    @Test
+    public void testIsHighPriority_checkChildrenToCalculatePriority() {
+        // GIVEN:
+        // GroupEntry = parentEntry, summary = lowPrioritySummary
+        //      NotificationEntry = lowPriorityChild
+        //      NotificationEntry = highPriorityChild
+        final GroupEntry parentEntry = new GroupEntry("test_group_key");
+        setSummary(parentEntry, createNotifEntry(false));
+        addChild(parentEntry, createNotifEntry(false));
+        addChild(parentEntry, createNotifEntry(true));
+
+        // THEN the GroupEntry parentEntry is high priority since it has a high priority child
+        assertTrue(parentEntry.isHighPriority());
+    }
+
+    @Test
+    public void testIsHighPriority_childEntryRankingUpdated() {
+        // GIVEN:
+        // GroupEntry = parentEntry, summary = lowPrioritySummary
+        //      NotificationEntry = lowPriorityChild
+        final GroupEntry parentEntry = new GroupEntry("test_group_key");
+        final NotificationEntry lowPriorityChild = createNotifEntry(false);
+        setSummary(parentEntry, createNotifEntry(false));
+        addChild(parentEntry, lowPriorityChild);
+
+        // WHEN the child entry ranking changes to high priority and invalidates its derived members
+        lowPriorityChild.setRanking(
+                new RankingBuilder()
+                        .setKey(lowPriorityChild.getKey())
+                        .setImportance(IMPORTANCE_HIGH)
+                        .build());
+        lowPriorityChild.invalidateDerivedMembers();
+
+        // THEN the parent entry's high priority value is updated - but not the parent's summary
+        assertTrue(parentEntry.isHighPriority());
+        assertFalse(parentEntry.getSummary().isHighPriority());
+    }
+
+    private NotificationEntry createNotifEntry(boolean highPriority) {
+        return new NotificationEntryBuilder()
+                .setImportance(highPriority ? IMPORTANCE_HIGH : IMPORTANCE_MIN)
+                .build();
+    }
+
+    private void setSummary(GroupEntry parent, NotificationEntry summary) {
+        parent.setSummary(summary);
+        summary.setParent(parent);
+    }
+
+    private void addChild(GroupEntry parent, NotificationEntry child) {
+        parent.addChild(child);
+        child.setParent(parent);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
index 536aeb4..17d556d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
@@ -21,6 +21,8 @@
 import static android.app.Notification.CATEGORY_EVENT;
 import static android.app.Notification.CATEGORY_MESSAGE;
 import static android.app.Notification.CATEGORY_REMINDER;
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_MIN;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
 
 import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
@@ -91,6 +93,44 @@
     }
 
     @Test
+    public void testIsHighPriority_notificationUpdates() {
+        // GIVEN a notification with high importance
+        final NotificationEntry entryHigh = new NotificationEntryBuilder()
+                .setImportance(IMPORTANCE_HIGH)
+                .build();
+
+        // WHEN we get the value for the high priority entry, we're caching the high priority value
+        assertTrue(entryHigh.isHighPriority());
+
+        // WHEN we change the ranking and derived members (high priority) are invalidated
+        entryHigh.setRanking(
+                new RankingBuilder()
+                        .setKey(entryHigh.getKey())
+                        .setImportance(IMPORTANCE_MIN)
+                        .build());
+        entryHigh.invalidateDerivedMembers();
+
+        // THEN the priority is recalculated and is now low
+        assertFalse(entryHigh.isHighPriority());
+
+        // WHEN the sbn is updated to have messaging style (high priority characteristic)
+        //  AND the entry invalidates its derived members
+        final Notification notification =
+                new Notification.Builder(mContext, "test")
+                        .setStyle(new Notification.MessagingStyle(""))
+                        .build();
+        final StatusBarNotification sbn = entryHigh.getSbn();
+        entryHigh.setSbn(new StatusBarNotification(
+                sbn.getPackageName(), sbn.getPackageName(),
+                sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
+                notification, sbn.getUser(), sbn.getOverrideGroupKey(), 0));
+        entryHigh.invalidateDerivedMembers();
+
+        // THEN the priority is recalculated and is now high
+        assertTrue(entryHigh.isHighPriority());
+    }
+
+    @Test
     public void testIsExemptFromDndVisualSuppression_foreground() {
         mEntry.getSbn().getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
index cda1538e..1764bef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
@@ -17,17 +17,12 @@
 package com.android.systemui.statusbar.notification.collection
 
 import android.app.Notification
-import android.app.NotificationChannel
 import android.app.NotificationManager.IMPORTANCE_DEFAULT
+import android.app.NotificationManager.IMPORTANCE_HIGH
 import android.app.NotificationManager.IMPORTANCE_LOW
 import android.service.notification.NotificationListenerService.RankingMap
-import android.service.notification.StatusBarNotification
 import android.testing.AndroidTestingRunner
-
-import org.junit.runner.RunWith
-
 import androidx.test.filters.SmallTest
-
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.NotificationEntryBuilder
 import com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking
@@ -42,12 +37,9 @@
 import com.android.systemui.statusbar.policy.HeadsUpManager
 import dagger.Lazy
 import junit.framework.Assert.assertEquals
-import junit.framework.Assert.assertFalse
-import junit.framework.Assert.assertTrue
-
 import org.junit.Before
 import org.junit.Test
-import org.mockito.Mockito.`when`
+import org.junit.runner.RunWith
 import org.mockito.Mockito.mock
 
 @SmallTest
@@ -76,106 +68,34 @@
     }
 
     @Test
-    fun testPeopleNotification_isHighPriority() {
-        val notification = Notification.Builder(mContext, "test")
-                .build()
-
-        val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
-                notification, mContext.user, "", 0)
-
-        `when`(personNotificationIdentifier.isPeopleNotification(sbn)).thenReturn(true)
-
-        val e = NotificationEntryBuilder()
-                .setNotification(notification)
-                .setSbn(sbn)
-                .build()
-
-        assertTrue(rankingManager.isHighPriority2(e))
-    }
-
-    @Test
-    fun lowForegroundHighPriority() {
-        val notification = mock(Notification::class.java)
-        `when`(notification.isForegroundService).thenReturn(true)
-
-        val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
-                notification, mContext.user, "", 0)
-
-        val e = NotificationEntryBuilder()
-                .setNotification(notification)
-                .setSbn(sbn)
-                .build()
-
-        modifyRanking(e)
-                .setImportance(IMPORTANCE_LOW)
-                .build()
-
-        assertTrue(rankingManager.isHighPriority2(e))
-    }
-
-    @Test
-    fun userChangeTrumpsHighPriorityCharacteristics() {
-        val notification = Notification.Builder(mContext, "test")
-                .setStyle(Notification.MessagingStyle(""))
-                .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
-                .build()
-
-        val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
-                notification, mContext.user, "", 0)
-
-        `when`(personNotificationIdentifier.isPeopleNotification(sbn)).thenReturn(true)
-
-        val channel = NotificationChannel("a", "a", IMPORTANCE_LOW)
-        channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE)
-
-        val e = NotificationEntryBuilder()
-                .setSbn(sbn)
-                .setChannel(channel)
-                .build()
-
-        assertFalse(rankingManager.isHighPriority2(e))
-    }
-
-    @Test
     fun testSort_highPriorityTrumpsNMSRank() {
         // NMS rank says A and then B. But A is not high priority and B is, so B should sort in
         // front
-        val aN = Notification.Builder(mContext, "test")
-                .setStyle(Notification.MessagingStyle(""))
-                .build()
         val a = NotificationEntryBuilder()
+                .setImportance(IMPORTANCE_LOW) // low priority
+                .setRank(1) // NMS says rank first
                 .setPkg("pkg")
                 .setOpPkg("pkg")
                 .setTag("tag")
-                .setNotification(aN)
+                .setNotification(
+                        Notification.Builder(mContext, "test")
+                                .build())
                 .setUser(mContext.getUser())
                 .setOverrideGroupKey("")
                 .build()
 
-        a.setIsHighPriority(false)
-
-        modifyRanking(a)
-                .setImportance(IMPORTANCE_LOW)
-                .setRank(1)
-                .build()
-
-        val bN = Notification.Builder(mContext, "test")
-                .setStyle(Notification.MessagingStyle(""))
-                .build()
         val b = NotificationEntryBuilder()
+                .setImportance(IMPORTANCE_HIGH) // high priority
+                .setRank(2) // NMS says rank second
                 .setPkg("pkg2")
                 .setOpPkg("pkg2")
                 .setTag("tag")
-                .setNotification(bN)
+                .setNotification(
+                        Notification.Builder(mContext, "test")
+                                .build())
                 .setUser(mContext.getUser())
                 .setOverrideGroupKey("")
                 .build()
-        b.setIsHighPriority(true)
-
-        modifyRanking(b)
-                .setImportance(IMPORTANCE_LOW)
-                .setRank(2)
-                .build()
 
         assertEquals(
                 listOf(b, a),
@@ -189,6 +109,8 @@
                 .setStyle(Notification.MessagingStyle(""))
                 .build()
         val a = NotificationEntryBuilder()
+                .setRank(1)
+                .setImportance(IMPORTANCE_HIGH)
                 .setPkg("pkg")
                 .setOpPkg("pkg")
                 .setTag("tag")
@@ -196,17 +118,13 @@
                 .setUser(mContext.getUser())
                 .setOverrideGroupKey("")
                 .build()
-        a.setIsHighPriority(false)
-
-        modifyRanking(a)
-                .setImportance(IMPORTANCE_LOW)
-                .setRank(1)
-                .build()
 
         val bN = Notification.Builder(mContext, "test")
                 .setStyle(Notification.MessagingStyle(""))
                 .build()
         val b = NotificationEntryBuilder()
+                .setRank(2)
+                .setImportance(IMPORTANCE_HIGH)
                 .setPkg("pkg2")
                 .setOpPkg("pkg2")
                 .setTag("tag")
@@ -214,12 +132,6 @@
                 .setUser(mContext.getUser())
                 .setOverrideGroupKey("")
                 .build()
-        b.setIsHighPriority(false)
-
-        modifyRanking(b)
-                .setImportance(IMPORTANCE_LOW)
-                .setRank(2)
-                .build()
 
         assertEquals(
                 listOf(a, b),
@@ -239,7 +151,7 @@
                 .setOverrideGroupKey("")
                 .build()
 
-        modifyRanking(e).setImportance(IMPORTANCE_DEFAULT) .build()
+        modifyRanking(e).setImportance(IMPORTANCE_DEFAULT).build()
 
         rankingManager.updateRanking(RankingMap(arrayOf(e.ranking)), listOf(e), "test")
         assertEquals(e.bucket, BUCKET_ALERTING)
@@ -281,11 +193,6 @@
         sectionsFeatureManager,
         peopleNotificationIdentifier
     ) {
-
-        fun isHighPriority2(e: NotificationEntry): Boolean {
-            return isHighPriority(e)
-        }
-
         fun applyTestRankingMap(r: RankingMap) {
             rankingMap = r
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/IsHighPriorityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/IsHighPriorityProviderTest.java
new file mode 100644
index 0000000..11488a0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/IsHighPriorityProviderTest.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.provider;
+
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.NotificationManager.IMPORTANCE_MIN;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.Person;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class IsHighPriorityProviderTest extends SysuiTestCase {
+    private IsHighPriorityProvider mIsHighPriorityProvider;
+
+    @Before
+    public void setup() {
+        mIsHighPriorityProvider = new IsHighPriorityProvider();
+    }
+
+    @Test
+    public void testCache() {
+        // GIVEN a notification with high importance
+        final NotificationEntry entryHigh = new NotificationEntryBuilder()
+                .setImportance(IMPORTANCE_HIGH)
+                .build();
+
+        // GIVEN notification with min importance
+        final NotificationEntry entryMin = new NotificationEntryBuilder()
+                .setImportance(IMPORTANCE_MIN)
+                .build();
+
+        // WHEN we get the value for the high priority entry
+        assertTrue(mIsHighPriorityProvider.get(entryHigh));
+
+        // THEN the value is cached, so even when passed an entryMin, we still get high priority
+        assertTrue(mIsHighPriorityProvider.get(entryMin));
+
+        // UNTIL the provider is invalidated
+        mIsHighPriorityProvider.invalidate();
+
+        // THEN the priority is recalculated
+        assertFalse(mIsHighPriorityProvider.get(entryMin));
+    }
+
+    @Test
+    public void highImportance() {
+        // GIVEN notification has high importance
+        final NotificationEntry entry = new NotificationEntryBuilder()
+                .setImportance(IMPORTANCE_HIGH)
+                .build();
+
+        // THEN it has high priority
+        assertTrue(mIsHighPriorityProvider.get(entry));
+    }
+
+    @Test
+    public void peopleNotification() {
+        // GIVEN notification is low importance but has a person associated with it
+        final Notification notification = new Notification.Builder(mContext, "test")
+                .addPerson(
+                        new Person.Builder()
+                                .setName("name")
+                                .setKey("abc")
+                                .setUri("uri")
+                                .setBot(true)
+                                .build())
+                .build();
+
+        final NotificationEntry entry = new NotificationEntryBuilder()
+                .setNotification(notification)
+                .setImportance(IMPORTANCE_LOW)
+                .build();
+
+        // THEN it has high priority
+        assertTrue(mIsHighPriorityProvider.get(entry));
+    }
+
+    @Test
+    public void messagingStyle() {
+        // GIVEN notification is low importance but has messaging style
+        final Notification notification = new Notification.Builder(mContext, "test")
+                .setStyle(new Notification.MessagingStyle(""))
+                .build();
+
+        final NotificationEntry entry = new NotificationEntryBuilder()
+                .setNotification(notification)
+                .build();
+
+        // THEN it has high priority
+        assertTrue(mIsHighPriorityProvider.get(entry));
+    }
+
+    @Test
+    public void lowImportanceForeground() {
+        // GIVEN notification is low importance and is associated with a foreground service
+        final Notification notification = mock(Notification.class);
+        when(notification.isForegroundService()).thenReturn(true);
+
+        final NotificationEntry entry = new NotificationEntryBuilder()
+                .setNotification(notification)
+                .setImportance(IMPORTANCE_LOW)
+                .build();
+
+        // THEN it has high priority
+        assertTrue(mIsHighPriorityProvider.get(entry));
+    }
+
+    @Test
+    public void minImportanceForeground() {
+        // GIVEN notification is low importance and is associated with a foreground service
+        final Notification notification = mock(Notification.class);
+        when(notification.isForegroundService()).thenReturn(true);
+
+        final NotificationEntry entry = new NotificationEntryBuilder()
+                .setNotification(notification)
+                .setImportance(IMPORTANCE_MIN)
+                .build();
+
+        // THEN it does NOT have high priority
+        assertFalse(mIsHighPriorityProvider.get(entry));
+    }
+
+    @Test
+    public void userChangeTrumpsHighPriorityCharacteristics() {
+        // GIVEN notification has high priority characteristics but the user changed the importance
+        // to less than IMPORTANCE_DEFAULT (ie: IMPORTANCE_LOW or IMPORTANCE_MIN)
+        final Notification notification = new Notification.Builder(mContext, "test")
+                .addPerson(
+                        new Person.Builder()
+                                .setName("name")
+                                .setKey("abc")
+                                .setUri("uri")
+                                .setBot(true)
+                                .build())
+                .setStyle(new Notification.MessagingStyle(""))
+                .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+                .build();
+
+        final NotificationChannel channel = new NotificationChannel("a", "a",
+                IMPORTANCE_LOW);
+        channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
+
+        final NotificationEntry entry = new NotificationEntryBuilder()
+                .setNotification(notification)
+                .setChannel(channel)
+                .build();
+
+        // THEN it does NOT have high priority
+        assertFalse(mIsHighPriorityProvider.get(entry));
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index 43d39a2..ccc9496 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -20,6 +20,7 @@
 import static android.app.AppOpsManager.OP_RECORD_AUDIO;
 import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
 import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
 
 import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
@@ -383,15 +384,14 @@
         NotificationInfo notificationInfoView = mock(NotificationInfo.class);
         ExpandableNotificationRow row = spy(mHelper.createRow());
         row.setBlockingHelperShowing(true);
-        modifyRanking(row.getEntry())
+        final NotificationEntry entry = row.getEntry();
+        modifyRanking(entry)
                 .setUserSentiment(USER_SENTIMENT_NEGATIVE)
-                .setImportance(IMPORTANCE_DEFAULT)
+                .setImportance(IMPORTANCE_HIGH)
                 .build();
-        row.getEntry().setIsHighPriority(true);
-        when(row.getIsNonblockable()).thenReturn(false);
-        StatusBarNotification statusBarNotification = row.getEntry().getSbn();
-        NotificationEntry entry = row.getEntry();
 
+        when(row.getIsNonblockable()).thenReturn(false);
+        StatusBarNotification statusBarNotification = entry.getSbn();
         mGutsManager.initializeNotificationInfo(row, notificationInfoView);
 
         verify(notificationInfoView).bindNotification(
@@ -408,7 +408,7 @@
                 eq(false),
                 eq(false),
                 eq(true) /* isForBlockingHelper */,
-                eq(IMPORTANCE_DEFAULT),
+                eq(IMPORTANCE_HIGH),
                 eq(true) /* wasShownHighPriority */);
     }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/AccessibilityGestureDetector.java b/services/accessibility/java/com/android/server/accessibility/gestures/AccessibilityGestureDetector.java
deleted file mode 100644
index 3dfe59e..0000000
--- a/services/accessibility/java/com/android/server/accessibility/gestures/AccessibilityGestureDetector.java
+++ /dev/null
@@ -1,640 +0,0 @@
-/*
- ** Copyright 2015, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- **     http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-package com.android.server.accessibility.gestures;
-
-import android.accessibilityservice.AccessibilityGestureEvent;
-import android.accessibilityservice.AccessibilityService;
-import android.content.Context;
-import android.gesture.GesturePoint;
-import android.graphics.PointF;
-import android.util.Slog;
-import android.util.TypedValue;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-
-import java.util.ArrayList;
-
-/**
- * This class handles gesture detection for the Touch Explorer.  It collects
- * touch events and determines when they match a gesture, as well as when they
- * won't match a gesture.  These state changes are then surfaced to mListener.
- */
-class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListener {
-
-    private static final boolean DEBUG = false;
-
-    // Tag for logging received events.
-    private static final String LOG_TAG = "AccessibilityGestureDetector";
-
-    // Constants for sampling motion event points.
-    // We sample based on a minimum distance between points, primarily to improve accuracy by
-    // reducing noisy minor changes in direction.
-    private static final float MIN_INCHES_BETWEEN_SAMPLES = 0.1f;
-    private final float mMinPixelsBetweenSamplesX;
-    private final float mMinPixelsBetweenSamplesY;
-
-    // Constants for separating gesture segments
-    private static final float ANGLE_THRESHOLD = 0.0f;
-
-    // Constants for line segment directions
-    private static final int LEFT = 0;
-    private static final int RIGHT = 1;
-    private static final int UP = 2;
-    private static final int DOWN = 3;
-    private static final int[][] DIRECTIONS_TO_GESTURE_ID = {
-        {
-            AccessibilityService.GESTURE_SWIPE_LEFT,
-            AccessibilityService.GESTURE_SWIPE_LEFT_AND_RIGHT,
-            AccessibilityService.GESTURE_SWIPE_LEFT_AND_UP,
-            AccessibilityService.GESTURE_SWIPE_LEFT_AND_DOWN
-        },
-        {
-            AccessibilityService.GESTURE_SWIPE_RIGHT_AND_LEFT,
-            AccessibilityService.GESTURE_SWIPE_RIGHT,
-            AccessibilityService.GESTURE_SWIPE_RIGHT_AND_UP,
-            AccessibilityService.GESTURE_SWIPE_RIGHT_AND_DOWN
-        },
-        {
-            AccessibilityService.GESTURE_SWIPE_UP_AND_LEFT,
-            AccessibilityService.GESTURE_SWIPE_UP_AND_RIGHT,
-            AccessibilityService.GESTURE_SWIPE_UP,
-            AccessibilityService.GESTURE_SWIPE_UP_AND_DOWN
-        },
-        {
-            AccessibilityService.GESTURE_SWIPE_DOWN_AND_LEFT,
-            AccessibilityService.GESTURE_SWIPE_DOWN_AND_RIGHT,
-            AccessibilityService.GESTURE_SWIPE_DOWN_AND_UP,
-            AccessibilityService.GESTURE_SWIPE_DOWN
-        }
-    };
-
-
-    /**
-     * Listener functions are called as a result of onMoveEvent().  The current
-     * MotionEvent in the context of these functions is the event passed into
-     * onMotionEvent.
-     */
-    public interface Listener {
-        /**
-         * Called when the user has performed a double tap and then held down
-         * the second tap.
-         *
-         * @param event The most recent MotionEvent received.
-         * @param policyFlags The policy flags of the most recent event.
-         */
-        void onDoubleTapAndHold(MotionEvent event, int policyFlags);
-
-        /**
-         * Called when the user lifts their finger on the second tap of a double
-         * tap.
-         *
-         * @param event The most recent MotionEvent received.
-         * @param policyFlags The policy flags of the most recent event.
-         *
-         * @return true if the event is consumed, else false
-         */
-        boolean onDoubleTap(MotionEvent event, int policyFlags);
-
-        /**
-         * Called when the system has decided the event stream is a gesture.
-         *
-         * @return true if the event is consumed, else false
-         */
-        boolean onGestureStarted();
-
-        /**
-         * Called when an event stream is recognized as a gesture.
-         *
-         * @param gestureEvent Information about the gesture.
-         *
-         * @return true if the event is consumed, else false
-         */
-        boolean onGestureCompleted(AccessibilityGestureEvent gestureEvent);
-
-        /**
-         * Called when the system has decided an event stream doesn't match any
-         * known gesture.
-         *
-         * @param event The most recent MotionEvent received.
-         * @param policyFlags The policy flags of the most recent event.
-         *
-         * @return true if the event is consumed, else false
-         */
-        public boolean onGestureCancelled(MotionEvent event, int policyFlags);
-    }
-
-    private final Listener mListener;
-    private final Context mContext;  // Retained for on-demand construction of GestureDetector.
-    private final GestureDetector mGestureDetector;  // Double-tap detector.
-
-    // Indicates that a single tap has occurred.
-    private boolean mFirstTapDetected;
-
-    // Indicates that the down event of a double tap has occured.
-    private boolean mDoubleTapDetected;
-
-    // Indicates that motion events are being collected to match a gesture.
-    private boolean mRecognizingGesture;
-
-    // Indicates that we've collected enough data to be sure it could be a
-    // gesture.
-    private boolean mGestureStarted;
-
-    // Indicates that motion events from the second pointer are being checked
-    // for a double tap.
-    private boolean mSecondFingerDoubleTap;
-
-    // Tracks the most recent time where ACTION_POINTER_DOWN was sent for the
-    // second pointer.
-    private long mSecondPointerDownTime;
-
-    // Policy flags of the previous event.
-    private int mPolicyFlags;
-
-    // These values track the previous point that was saved to use for gesture
-    // detection.  They are only updated when the user moves more than the
-    // recognition threshold.
-    private float mPreviousGestureX;
-    private float mPreviousGestureY;
-
-    // These values track the previous point that was used to determine if there
-    // was a transition into or out of gesture detection.  They are updated when
-    // the user moves more than the detection threshold.
-    private float mBaseX;
-    private float mBaseY;
-    private long mBaseTime;
-
-    // This is the calculated movement threshold used track if the user is still
-    // moving their finger.
-    private final float mGestureDetectionThreshold;
-
-    // Buffer for storing points for gesture detection.
-    private final ArrayList<GesturePoint> mStrokeBuffer = new ArrayList<GesturePoint>(100);
-
-    // The minimal delta between moves to add a gesture point.
-    private static final int TOUCH_TOLERANCE = 3;
-
-    // The minimal score for accepting a predicted gesture.
-    private static final float MIN_PREDICTION_SCORE = 2.0f;
-
-    // Distance a finger must travel before we decide if it is a gesture or not.
-    private static final int GESTURE_CONFIRM_MM = 10;
-
-    // Time threshold used to determine if an interaction is a gesture or not.
-    // If the first movement of 1cm takes longer than this value, we assume it's
-    // a slow movement, and therefore not a gesture.
-    //
-    // This value was determined by measuring the time for the first 1cm
-    // movement when gesturing, and touch exploring.  Based on user testing,
-    // all gestures started with the initial movement taking less than 100ms.
-    // When touch exploring, the first movement almost always takes longer than
-    // 200ms.
-    private static final long CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS = 150;
-
-    // Time threshold used to determine if a gesture should be cancelled.  If
-    // the finger takes more than this time to move 1cm, the ongoing gesture is
-    // cancelled.
-    private static final long CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS = 300;
-
-    /**
-     * Construct the gesture detector for {@link TouchExplorer}.
-     *
-     * @see #AccessibilityGestureDetector(Context, Listener, GestureDetector)
-     */
-    AccessibilityGestureDetector(Context context, Listener listener) {
-        this(context, listener, null);
-    }
-
-    /**
-     * Construct the gesture detector for {@link TouchExplorer}.
-     *
-     * @param context A context handle for accessing resources.
-     * @param listener A listener to callback with gesture state or information.
-     * @param detector The gesture detector to handle touch event. If null the default one created
-     *                 in place, or for testing purpose.
-     */
-    AccessibilityGestureDetector(Context context, Listener listener, GestureDetector detector) {
-        mListener = listener;
-        mContext = context;
-
-        // Break the circular dependency between constructors and let the class to be testable
-        if (detector == null) {
-            mGestureDetector = new GestureDetector(context, this);
-        } else {
-            mGestureDetector = detector;
-        }
-        mGestureDetector.setOnDoubleTapListener(this);
-        mGestureDetectionThreshold = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1,
-                context.getResources().getDisplayMetrics()) * GESTURE_CONFIRM_MM;
-
-        // Calculate minimum gesture velocity
-        final float pixelsPerInchX = context.getResources().getDisplayMetrics().xdpi;
-        final float pixelsPerInchY = context.getResources().getDisplayMetrics().ydpi;
-        mMinPixelsBetweenSamplesX = MIN_INCHES_BETWEEN_SAMPLES * pixelsPerInchX;
-        mMinPixelsBetweenSamplesY = MIN_INCHES_BETWEEN_SAMPLES * pixelsPerInchY;
-    }
-
-    /**
-     * Handle a motion event.  If an action is completed, the appropriate
-     * callback on mListener is called, and the return value of the callback is
-     * passed to the caller.
-     *
-     * @param event The transformed motion event to be handled.
-     * @param rawEvent The raw motion event.  It's important that this be the raw
-     * event, before any transformations have been applied, so that measurements
-     * can be made in physical units.
-     * @param policyFlags Policy flags for the event.
-     *
-     * @return true if the event is consumed, else false
-     */
-    public boolean onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
-        // The accessibility gesture detector is interested in the movements in physical space,
-        // so it uses the rawEvent to ignore magnification and other transformations.
-        final float x = rawEvent.getX();
-        final float y = rawEvent.getY();
-        final long time = rawEvent.getEventTime();
-
-        mPolicyFlags = policyFlags;
-        switch (rawEvent.getActionMasked()) {
-            case MotionEvent.ACTION_DOWN:
-                mDoubleTapDetected = false;
-                mSecondFingerDoubleTap = false;
-                mRecognizingGesture = true;
-                mGestureStarted = false;
-                mPreviousGestureX = x;
-                mPreviousGestureY = y;
-                mStrokeBuffer.clear();
-                mStrokeBuffer.add(new GesturePoint(x, y, time));
-
-                mBaseX = x;
-                mBaseY = y;
-                mBaseTime = time;
-                break;
-
-            case MotionEvent.ACTION_MOVE:
-                if (mRecognizingGesture) {
-                    final float deltaX = mBaseX - x;
-                    final float deltaY = mBaseY - y;
-                    final double moveDelta = Math.hypot(deltaX, deltaY);
-                    if (moveDelta > mGestureDetectionThreshold) {
-                        // If the pointer has moved more than the threshold,
-                        // update the stored values.
-                        mBaseX = x;
-                        mBaseY = y;
-                        mBaseTime = time;
-
-                        // Since the pointer has moved, this is not a double
-                        // tap.
-                        mFirstTapDetected = false;
-                        mDoubleTapDetected = false;
-
-                        // If this hasn't been confirmed as a gesture yet, send
-                        // the event.
-                        if (!mGestureStarted) {
-                            mGestureStarted = true;
-                            return mListener.onGestureStarted();
-                        }
-                    } else if (!mFirstTapDetected) {
-                        // The finger may not move if they are double tapping.
-                        // In that case, we shouldn't cancel the gesture.
-                        final long timeDelta = time - mBaseTime;
-                        final long threshold = mGestureStarted ?
-                            CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS :
-                            CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS;
-
-                        // If the pointer hasn't moved for longer than the
-                        // timeout, cancel gesture detection.
-                        if (timeDelta > threshold) {
-                            cancelGesture();
-                            return mListener.onGestureCancelled(rawEvent, policyFlags);
-                        }
-                    }
-
-                    final float dX = Math.abs(x - mPreviousGestureX);
-                    final float dY = Math.abs(y - mPreviousGestureY);
-                    if (dX >= mMinPixelsBetweenSamplesX || dY >= mMinPixelsBetweenSamplesY) {
-                        mPreviousGestureX = x;
-                        mPreviousGestureY = y;
-                        mStrokeBuffer.add(new GesturePoint(x, y, time));
-                    }
-                }
-                break;
-
-            case MotionEvent.ACTION_UP:
-                if (mDoubleTapDetected) {
-                    return finishDoubleTap(rawEvent, policyFlags);
-                }
-                if (mGestureStarted) {
-                    final float dX = Math.abs(x - mPreviousGestureX);
-                    final float dY = Math.abs(y - mPreviousGestureY);
-                    if (dX >= mMinPixelsBetweenSamplesX || dY >= mMinPixelsBetweenSamplesY) {
-                        mStrokeBuffer.add(new GesturePoint(x, y, time));
-                    }
-                    return recognizeGesture(rawEvent, policyFlags);
-                }
-                break;
-
-            case MotionEvent.ACTION_POINTER_DOWN:
-                // Once a second finger is used, we're definitely not
-                // recognizing a gesture.
-                cancelGesture();
-
-                if (rawEvent.getPointerCount() == 2) {
-                    // If this was the second finger, attempt to recognize double
-                    // taps on it.
-                    mSecondFingerDoubleTap = true;
-                    mSecondPointerDownTime = time;
-                } else {
-                    // If there are more than two fingers down, stop watching
-                    // for a double tap.
-                    mSecondFingerDoubleTap = false;
-                }
-                break;
-
-            case MotionEvent.ACTION_POINTER_UP:
-                // If we're detecting taps on the second finger, see if we
-                // should finish the double tap.
-                if (mSecondFingerDoubleTap && mDoubleTapDetected) {
-                    return finishDoubleTap(rawEvent, policyFlags);
-                }
-                break;
-
-            case MotionEvent.ACTION_CANCEL:
-                clear();
-                break;
-        }
-
-        // If we're detecting taps on the second finger, map events from the
-        // finger to the first finger.
-        if (mSecondFingerDoubleTap) {
-            MotionEvent newEvent = mapSecondPointerToFirstPointer(rawEvent);
-            if (newEvent == null) {
-                return false;
-            }
-            boolean handled = mGestureDetector.onTouchEvent(newEvent);
-            newEvent.recycle();
-            return handled;
-        }
-
-        if (!mRecognizingGesture) {
-            return false;
-        }
-
-        // Pass the transformed event on to the standard gesture detector.
-        return mGestureDetector.onTouchEvent(event);
-    }
-
-    public void clear() {
-        mFirstTapDetected = false;
-        mDoubleTapDetected = false;
-        mSecondFingerDoubleTap = false;
-        mGestureStarted = false;
-        mGestureDetector.onTouchEvent(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_CANCEL,
-                0.0f, 0.0f, 0));
-        cancelGesture();
-    }
-
-
-    @Override
-    public void onLongPress(MotionEvent e) {
-        maybeSendLongPress(e, mPolicyFlags);
-    }
-
-    @Override
-    public boolean onSingleTapUp(MotionEvent event) {
-        mFirstTapDetected = true;
-        return false;
-    }
-
-    @Override
-    public boolean onSingleTapConfirmed(MotionEvent event) {
-        clear();
-        return false;
-    }
-
-    @Override
-    public boolean onDoubleTap(MotionEvent event) {
-        // The processing of the double tap is deferred until the finger is
-        // lifted, so that we can detect a long press on the second tap.
-        mDoubleTapDetected = true;
-        return false;
-    }
-
-    private void maybeSendLongPress(MotionEvent event, int policyFlags) {
-        if (!mDoubleTapDetected) {
-            return;
-        }
-
-        clear();
-
-        mListener.onDoubleTapAndHold(event, policyFlags);
-    }
-
-    private boolean finishDoubleTap(MotionEvent event, int policyFlags) {
-        clear();
-
-        return mListener.onDoubleTap(event, policyFlags);
-    }
-
-    private void cancelGesture() {
-        mRecognizingGesture = false;
-        mGestureStarted = false;
-        mStrokeBuffer.clear();
-    }
-
-    /**
-     * Looks at the sequence of motions in mStrokeBuffer, classifies the gesture, then calls
-     * Listener callbacks for success or failure.
-     *
-     * @param event The raw motion event to pass to the listener callbacks.
-     * @param policyFlags Policy flags for the event.
-     *
-     * @return true if the event is consumed, else false
-     */
-    private boolean recognizeGesture(MotionEvent event, int policyFlags) {
-        if (mStrokeBuffer.size() < 2) {
-            return mListener.onGestureCancelled(event, policyFlags);
-        }
-
-        // Look at mStrokeBuffer and extract 2 line segments, delimited by near-perpendicular
-        // direction change.
-        // Method: for each sampled motion event, check the angle of the most recent motion vector
-        // versus the preceding motion vector, and segment the line if the angle is about
-        // 90 degrees.
-
-        ArrayList<PointF> path = new ArrayList<>();
-        PointF lastDelimiter = new PointF(mStrokeBuffer.get(0).x, mStrokeBuffer.get(0).y);
-        path.add(lastDelimiter);
-
-        float dX = 0;  // Sum of unit vectors from last delimiter to each following point
-        float dY = 0;
-        int count = 0;  // Number of points since last delimiter
-        float length = 0;  // Vector length from delimiter to most recent point
-
-        PointF next = new PointF();
-        for (int i = 1; i < mStrokeBuffer.size(); ++i) {
-            next = new PointF(mStrokeBuffer.get(i).x, mStrokeBuffer.get(i).y);
-            if (count > 0) {
-                // Average of unit vectors from delimiter to following points
-                float currentDX = dX / count;
-                float currentDY = dY / count;
-
-                // newDelimiter is a possible new delimiter, based on a vector with length from
-                // the last delimiter to the previous point, but in the direction of the average
-                // unit vector from delimiter to previous points.
-                // Using the averaged vector has the effect of "squaring off the curve",
-                // creating a sharper angle between the last motion and the preceding motion from
-                // the delimiter. In turn, this sharper angle achieves the splitting threshold
-                // even in a gentle curve.
-                PointF newDelimiter = new PointF(length * currentDX + lastDelimiter.x,
-                    length * currentDY + lastDelimiter.y);
-
-                // Unit vector from newDelimiter to the most recent point
-                float nextDX = next.x - newDelimiter.x;
-                float nextDY = next.y - newDelimiter.y;
-                float nextLength = (float) Math.sqrt(nextDX * nextDX + nextDY * nextDY);
-                nextDX = nextDX / nextLength;
-                nextDY = nextDY / nextLength;
-
-                // Compare the initial motion direction to the most recent motion direction,
-                // and segment the line if direction has changed by about 90 degrees.
-                float dot = currentDX * nextDX + currentDY * nextDY;
-                if (dot < ANGLE_THRESHOLD) {
-                    path.add(newDelimiter);
-                    lastDelimiter = newDelimiter;
-                    dX = 0;
-                    dY = 0;
-                    count = 0;
-                }
-            }
-
-            // Vector from last delimiter to most recent point
-            float currentDX = next.x - lastDelimiter.x;
-            float currentDY = next.y - lastDelimiter.y;
-            length = (float) Math.sqrt(currentDX * currentDX + currentDY * currentDY);
-
-            // Increment sum of unit vectors from delimiter to each following point
-            count = count + 1;
-            dX = dX + currentDX / length;
-            dY = dY + currentDY / length;
-        }
-
-        path.add(next);
-        Slog.i(LOG_TAG, "path=" + path.toString());
-
-        // Classify line segments, and call Listener callbacks.
-        return recognizeGesturePath(event, policyFlags, path);
-    }
-
-    /**
-     * Classifies a pair of line segments, by direction.
-     * Calls Listener callbacks for success or failure.
-     *
-     * @param event The raw motion event to pass to the listener's onGestureCanceled method.
-     * @param policyFlags Policy flags for the event.
-     * @param path A sequence of motion line segments derived from motion points in mStrokeBuffer.
-     *
-     * @return true if the event is consumed, else false
-     */
-    private boolean recognizeGesturePath(MotionEvent event, int policyFlags,
-            ArrayList<PointF> path) {
-
-        final int displayId = event.getDisplayId();
-        if (path.size() == 2) {
-            PointF start = path.get(0);
-            PointF end = path.get(1);
-
-            float dX = end.x - start.x;
-            float dY = end.y - start.y;
-            int direction = toDirection(dX, dY);
-            switch (direction) {
-                case LEFT:
-                    return mListener.onGestureCompleted(
-                            new AccessibilityGestureEvent(AccessibilityService.GESTURE_SWIPE_LEFT,
-                                    displayId));
-                case RIGHT:
-                    return mListener.onGestureCompleted(
-                            new AccessibilityGestureEvent(AccessibilityService.GESTURE_SWIPE_RIGHT,
-                                    displayId));
-                case UP:
-                    return mListener.onGestureCompleted(
-                            new AccessibilityGestureEvent(AccessibilityService.GESTURE_SWIPE_UP,
-                                    displayId));
-                case DOWN:
-                    return mListener.onGestureCompleted(
-                            new AccessibilityGestureEvent(AccessibilityService.GESTURE_SWIPE_DOWN,
-                                    displayId));
-                default:
-                    // Do nothing.
-            }
-
-        } else if (path.size() == 3) {
-            PointF start = path.get(0);
-            PointF mid = path.get(1);
-            PointF end = path.get(2);
-
-            float dX0 = mid.x - start.x;
-            float dY0 = mid.y - start.y;
-
-            float dX1 = end.x - mid.x;
-            float dY1 = end.y - mid.y;
-
-            int segmentDirection0 = toDirection(dX0, dY0);
-            int segmentDirection1 = toDirection(dX1, dY1);
-            int gestureId = DIRECTIONS_TO_GESTURE_ID[segmentDirection0][segmentDirection1];
-            return mListener.onGestureCompleted(
-                    new AccessibilityGestureEvent(gestureId, displayId));
-        }
-        // else if (path.size() < 2 || 3 < path.size()) then no gesture recognized.
-        return mListener.onGestureCancelled(event, policyFlags);
-    }
-
-    /** Maps a vector to a dominant direction in set {LEFT, RIGHT, UP, DOWN}. */
-    private static int toDirection(float dX, float dY) {
-        if (Math.abs(dX) > Math.abs(dY)) {
-            // Horizontal
-            return (dX < 0) ? LEFT : RIGHT;
-        } else {
-            // Vertical
-            return (dY < 0) ? UP : DOWN;
-        }
-    }
-
-    private MotionEvent mapSecondPointerToFirstPointer(MotionEvent event) {
-        // Only map basic events when two fingers are down.
-        if (event.getPointerCount() != 2 ||
-                (event.getActionMasked() != MotionEvent.ACTION_POINTER_DOWN &&
-                 event.getActionMasked() != MotionEvent.ACTION_POINTER_UP &&
-                 event.getActionMasked() != MotionEvent.ACTION_MOVE)) {
-            return null;
-        }
-
-        int action = event.getActionMasked();
-
-        if (action == MotionEvent.ACTION_POINTER_DOWN) {
-            action = MotionEvent.ACTION_DOWN;
-        } else if (action == MotionEvent.ACTION_POINTER_UP) {
-            action = MotionEvent.ACTION_UP;
-        }
-
-        // Map the information from the second pointer to the first.
-        return MotionEvent.obtain(mSecondPointerDownTime, event.getEventTime(), action,
-                event.getX(1), event.getY(1), event.getPressure(1), event.getSize(1),
-                event.getMetaState(), event.getXPrecision(), event.getYPrecision(),
-                event.getDeviceId(), event.getEdgeFlags());
-    }
-}
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
new file mode 100644
index 0000000..9b7adc8
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2019 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.accessibility.gestures;
+
+import static android.accessibilityservice.AccessibilityService.GESTURE_DOUBLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_DOUBLE_TAP_AND_HOLD;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN_AND_LEFT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN_AND_RIGHT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN_AND_UP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_LEFT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_LEFT_AND_DOWN;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_LEFT_AND_RIGHT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_LEFT_AND_UP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_RIGHT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_RIGHT_AND_DOWN;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_RIGHT_AND_LEFT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_RIGHT_AND_UP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_UP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_UP_AND_DOWN;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_UP_AND_LEFT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_UP_AND_RIGHT;
+
+import static com.android.server.accessibility.gestures.Swipe.DOWN;
+import static com.android.server.accessibility.gestures.Swipe.LEFT;
+import static com.android.server.accessibility.gestures.Swipe.RIGHT;
+import static com.android.server.accessibility.gestures.Swipe.UP;
+import static com.android.server.accessibility.gestures.TouchExplorer.DEBUG;
+
+import android.accessibilityservice.AccessibilityGestureEvent;
+import android.content.Context;
+import android.os.Handler;
+import android.util.Slog;
+import android.view.MotionEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class coordinates a series of individual gesture matchers to serve as a unified gesture
+ * detector. Gesture matchers are tied to a single gesture. It calls listener callback functions
+ * when a gesture starts or completes.
+ */
+class GestureManifold implements GestureMatcher.StateChangeListener {
+
+    private static final String LOG_TAG = "GestureManifold";
+
+    private final List<GestureMatcher> mGestures = new ArrayList<>();
+    private final Context mContext;
+    // Handler for performing asynchronous operations.
+    private final Handler mHandler;
+    // Listener to be notified of gesture start and end.
+    private Listener mListener;
+    // Shared state information.
+    private TouchState mState;
+
+    GestureManifold(Context context, Listener listener, TouchState state) {
+        mContext = context;
+        mHandler = new Handler(context.getMainLooper());
+        mListener = listener;
+        mState = state;
+        // Set up gestures.
+        // Start with double tap.
+        mGestures.add(new MultiTap(context, 2, GESTURE_DOUBLE_TAP, this));
+        mGestures.add(new MultiTapAndHold(context, 2, GESTURE_DOUBLE_TAP_AND_HOLD, this));
+        // One-direction swipes.
+        mGestures.add(new Swipe(context, RIGHT, GESTURE_SWIPE_RIGHT, this));
+        mGestures.add(new Swipe(context, LEFT, GESTURE_SWIPE_LEFT, this));
+        mGestures.add(new Swipe(context, UP, GESTURE_SWIPE_UP, this));
+        mGestures.add(new Swipe(context, DOWN, GESTURE_SWIPE_DOWN, this));
+        // Two-direction swipes.
+        mGestures.add(new Swipe(context, LEFT, RIGHT, GESTURE_SWIPE_LEFT_AND_RIGHT, this));
+        mGestures.add(new Swipe(context, LEFT, UP, GESTURE_SWIPE_LEFT_AND_UP, this));
+        mGestures.add(new Swipe(context, LEFT, DOWN, GESTURE_SWIPE_LEFT_AND_DOWN, this));
+        mGestures.add(new Swipe(context, RIGHT, UP, GESTURE_SWIPE_RIGHT_AND_UP, this));
+        mGestures.add(new Swipe(context, RIGHT, DOWN, GESTURE_SWIPE_RIGHT_AND_DOWN, this));
+        mGestures.add(new Swipe(context, RIGHT, LEFT, GESTURE_SWIPE_RIGHT_AND_LEFT, this));
+        mGestures.add(new Swipe(context, DOWN, UP, GESTURE_SWIPE_DOWN_AND_UP, this));
+        mGestures.add(new Swipe(context, DOWN, LEFT, GESTURE_SWIPE_DOWN_AND_LEFT, this));
+        mGestures.add(new Swipe(context, DOWN, RIGHT, GESTURE_SWIPE_DOWN_AND_RIGHT, this));
+        mGestures.add(new Swipe(context, UP, DOWN, GESTURE_SWIPE_UP_AND_DOWN, this));
+        mGestures.add(new Swipe(context, UP, LEFT, GESTURE_SWIPE_UP_AND_LEFT, this));
+        mGestures.add(new Swipe(context, UP, RIGHT, GESTURE_SWIPE_UP_AND_RIGHT, this));
+    }
+
+    /**
+     * Processes a motion event.
+     *
+     * @param event The event as received from the previous entry in the event stream.
+     * @param rawEvent The event without any transformations e.g. magnification.
+     * @param policyFlags
+     * @return True if the event has been appropriately handled by the gesture manifold and related
+     *     callback functions, false if it should be handled further by the calling function.
+     */
+    boolean onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (mState.isClear()) {
+            if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+                // Sanity safeguard: if touch state is clear, then matchers should always be clear
+                // before processing the next down event.
+                clear();
+            } else {
+                // If for some reason other events come through while in the clear state they could
+                // compromise the state of particular matchers, so we just ignore them.
+                return false;
+            }
+        }
+        for (GestureMatcher matcher : mGestures) {
+            if (matcher.getState() != GestureMatcher.STATE_GESTURE_CANCELED) {
+                if (DEBUG) {
+                    Slog.d(LOG_TAG, matcher.toString());
+                }
+                matcher.onMotionEvent(event, rawEvent, policyFlags);
+                if (DEBUG) {
+                    Slog.d(LOG_TAG, matcher.toString());
+                }
+                if (matcher.getState() == GestureMatcher.STATE_GESTURE_COMPLETED) {
+                    // Here we just clear and return. The actual gesture dispatch is done in
+                    // onStateChanged().
+                    clear();
+                    // No need to process this event any further.
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public void clear() {
+        for (GestureMatcher matcher : mGestures) {
+            matcher.clear();
+        }
+    }
+
+    /**
+     * Listener that receives notifications of the state of the gesture detector. Listener functions
+     * are called as a result of onMotionEvent(). The current MotionEvent in the context of these
+     * functions is the event passed into onMotionEvent.
+     */
+    public interface Listener {
+        /**
+         * Called when the user has performed a double tap and then held down the second tap.
+         */
+        void onDoubleTapAndHold();
+
+        /**
+         * Called when the user lifts their finger on the second tap of a double tap.
+         * @return true if the event is consumed, else false
+         */
+        boolean onDoubleTap();
+
+        /**
+         * Called when the system has decided the event stream is a gesture.
+         *
+         * @return true if the event is consumed, else false
+         */
+        boolean onGestureStarted();
+
+        /**
+         * Called when an event stream is recognized as a gesture.
+         *
+         * @param gestureEvent Information about the gesture.
+         * @return true if the event is consumed, else false
+         */
+        boolean onGestureCompleted(AccessibilityGestureEvent gestureEvent);
+
+        /**
+         * Called when the system has decided an event stream doesn't match any known gesture.
+         *
+         * @param event The most recent MotionEvent received.
+         * @param policyFlags The policy flags of the most recent event.
+         * @return true if the event is consumed, else false
+         */
+        boolean onGestureCancelled(MotionEvent event, MotionEvent rawEvent, int policyFlags);
+    }
+
+    @Override
+    public void onStateChanged(
+            int gestureId, int state, MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (state == GestureMatcher.STATE_GESTURE_STARTED && !mState.isGestureDetecting()) {
+            mListener.onGestureStarted();
+        } else if (state == GestureMatcher.STATE_GESTURE_COMPLETED) {
+            onGestureCompleted(gestureId);
+        } else if (state == GestureMatcher.STATE_GESTURE_CANCELED && mState.isGestureDetecting()) {
+            // We only want to call the cancelation callback if there are no other pending
+            // detectors.
+            for (GestureMatcher matcher : mGestures) {
+                if (matcher.getState() == GestureMatcher.STATE_GESTURE_STARTED) {
+                    return;
+                }
+            }
+            if (DEBUG) {
+                Slog.d(LOG_TAG, "Cancelling.");
+            }
+            mListener.onGestureCancelled(event, rawEvent, policyFlags);
+        }
+    }
+
+    private void onGestureCompleted(int gestureId) {
+        MotionEvent event = mState.getLastReceivedEvent();
+        // Note that gestures that complete immediately call clear() from onMotionEvent.
+        // Gestures that complete on a delay call clear() here.
+        switch (gestureId) {
+            case GESTURE_DOUBLE_TAP:
+                mListener.onDoubleTap();
+                clear();
+                break;
+            case GESTURE_DOUBLE_TAP_AND_HOLD:
+                mListener.onDoubleTapAndHold();
+                clear();
+                break;
+            default:
+                AccessibilityGestureEvent gestureEvent =
+                        new AccessibilityGestureEvent(gestureId, event.getDisplayId());
+                mListener.onGestureCompleted(gestureEvent);
+                break;
+        }
+    }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/GestureMatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/GestureMatcher.java
new file mode 100644
index 0000000..0b30ff57
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureMatcher.java
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2019 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.accessibility.gestures;
+
+import static com.android.server.accessibility.gestures.TouchExplorer.DEBUG;
+
+import android.annotation.IntDef;
+import android.os.Handler;
+import android.util.Slog;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+/**
+ * This class describes a common base for gesture matchers. A gesture matcher checks a series of
+ * motion events against a single gesture. Coordinating the individual gesture matchers is done by
+ * the GestureManifold. To create a new Gesture, extend this class and override the onDown, onMove,
+ * onUp, etc methods as necessary. If you don't override a method your matcher will do nothing in
+ * response to that type of event. Finally, be sure to give your gesture a name by overriding
+ * getGestureName().
+ */
+abstract class GestureMatcher {
+    // Potential states for this individual gesture matcher.
+    // In STATE_CLEAR, this matcher is accepting new motion events but has not formally signaled
+    // that there is enough data to judge that a gesture has started.
+    static final int STATE_CLEAR = 0;
+    // In STATE_GESTURE_STARTED, this matcher continues to accept motion events and it has signaled
+    // to the gesture manifold that what looks like the specified gesture has started.
+    static final int STATE_GESTURE_STARTED = 1;
+    // In STATE_GESTURE_COMPLETED, this matcher has successfully matched the specified gesture. and
+    // will not accept motion events until it is cleared.
+    static final int STATE_GESTURE_COMPLETED = 2;
+    // In STATE_GESTURE_CANCELED, this matcher will not accept new motion events because it is
+    // impossible that this set of motion events will match the specified gesture.
+    static final int STATE_GESTURE_CANCELED = 3;
+
+    @IntDef({STATE_CLEAR, STATE_GESTURE_STARTED, STATE_GESTURE_COMPLETED, STATE_GESTURE_CANCELED})
+    public @interface State {}
+
+    @State private int mState = STATE_CLEAR;
+    // The id number of the gesture that gets passed to accessibility services.
+    private final int mGestureId;
+    // handler for asynchronous operations like timeouts
+    private final Handler mHandler;
+
+    private final StateChangeListener mListener;
+
+    // Use this to transition to new states after a delay.
+    // e.g. cancel or complete after some timeout.
+    // Convenience functions for tapTimeout and doubleTapTimeout are already defined here.
+    protected final DelayedTransition mDelayedTransition;
+
+    GestureMatcher(int gestureId, Handler handler, StateChangeListener listener) {
+        mGestureId = gestureId;
+        mHandler = handler;
+        mDelayedTransition = new DelayedTransition();
+        mListener = listener;
+    }
+
+    /**
+     * Resets all state information for this matcher. Subclasses that include their own state
+     * information should override this method to reset their own state information and call
+     * super.clear().
+     */
+    protected void clear() {
+        mState = STATE_CLEAR;
+        cancelPendingTransitions();
+    }
+
+    public int getState() {
+        return mState;
+    }
+
+    /**
+     * Transitions to a new state and notifies any listeners. Note that any pending transitions are
+     * canceled.
+     */
+    private void setState(
+            @State int state, MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        mState = state;
+        cancelPendingTransitions();
+        mListener.onStateChanged(mGestureId, mState, event, rawEvent, policyFlags);
+    }
+
+    /** Indicates that there is evidence to suggest that this gesture has started. */
+    protected final void startGesture(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        setState(STATE_GESTURE_STARTED, event, rawEvent, policyFlags);
+    }
+
+    /** Indicates this stream of motion events can no longer match this gesture. */
+    protected final void cancelGesture(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        setState(STATE_GESTURE_CANCELED, event, rawEvent, policyFlags);
+    }
+
+    /** Indicates this gesture is completed. */
+    protected final void completeGesture(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        setState(STATE_GESTURE_COMPLETED, event, rawEvent, policyFlags);
+    }
+
+    public int getGestureId() {
+        return mGestureId;
+    }
+
+    /**
+     * Process a motion event and attempt to match it to this gesture.
+     *
+     * @param event the event as passed in from the event stream.
+     * @param rawEvent the original un-modified event. Useful for calculating movements in physical
+     *     space.
+     * @param policyFlags the policy flags as passed in from the event stream.
+     * @return the state of this matcher.
+     */
+    public final int onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (mState == STATE_GESTURE_CANCELED || mState == STATE_GESTURE_COMPLETED) {
+            return mState;
+        }
+        switch (event.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN:
+                onDown(event, rawEvent, policyFlags);
+                break;
+            case MotionEvent.ACTION_POINTER_DOWN:
+                onPointerDown(event, rawEvent, policyFlags);
+                break;
+            case MotionEvent.ACTION_MOVE:
+                onMove(event, rawEvent, policyFlags);
+                break;
+            case MotionEvent.ACTION_POINTER_UP:
+                onPointerUp(event, rawEvent, policyFlags);
+                break;
+            case MotionEvent.ACTION_UP:
+                onUp(event, rawEvent, policyFlags);
+                break;
+            default:
+                // Cancel because of invalid event.
+                setState(STATE_GESTURE_CANCELED, event, rawEvent, policyFlags);
+                break;
+        }
+        return mState;
+    }
+
+    /**
+     * Matchers override this method to respond to ACTION_DOWN events. ACTION_DOWN events indicate
+     * the first finger has touched the screen. If not overridden the default response is to do
+     * nothing.
+     */
+    protected void onDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {}
+
+    /**
+     * Matchers override this method to respond to ACTION_POINTER_DOWN events. ACTION_POINTER_DOWN
+     * indicates that more than one finger has touched the screen. If not overridden the default
+     * response is to do nothing.
+     *
+     * @param event the event as passed in from the event stream.
+     * @param rawEvent the original un-modified event. Useful for calculating movements in physical
+     *     space.
+     * @param policyFlags the policy flags as passed in from the event stream.
+     */
+    protected void onPointerDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {}
+
+    /**
+     * Matchers override this method to respond to ACTION_MOVE events. ACTION_MOVE indicates that
+     * one or fingers has moved. If not overridden the default response is to do nothing.
+     *
+     * @param event the event as passed in from the event stream.
+     * @param rawEvent the original un-modified event. Useful for calculating movements in physical
+     *     space.
+     * @param policyFlags the policy flags as passed in from the event stream.
+     */
+    protected void onMove(MotionEvent event, MotionEvent rawEvent, int policyFlags) {}
+
+    /**
+     * Matchers override this method to respond to ACTION_POINTER_UP events. ACTION_POINTER_UP
+     * indicates that a finger has lifted from the screen but at least one finger continues to touch
+     * the screen. If not overridden the default response is to do nothing.
+     *
+     * @param event the event as passed in from the event stream.
+     * @param rawEvent the original un-modified event. Useful for calculating movements in physical
+     *     space.
+     * @param policyFlags the policy flags as passed in from the event stream.
+     */
+    protected void onPointerUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {}
+
+    /**
+     * Matchers override this method to respond to ACTION_UP events. ACTION_UP indicates that there
+     * are no more fingers touching the screen. If not overridden the default response is to do
+     * nothing.
+     *
+     * @param event the event as passed in from the event stream.
+     * @param rawEvent the original un-modified event. Useful for calculating movements in physical
+     *     space.
+     * @param policyFlags the policy flags as passed in from the event stream.
+     */
+    protected void onUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {}
+
+    /** Cancels this matcher after the tap timeout. Any pending state transitions are removed. */
+    protected void cancelAfterTapTimeout(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        cancelAfter(ViewConfiguration.getTapTimeout(), event, rawEvent, policyFlags);
+    }
+
+    /** Cancels this matcher after the double tap timeout. Any pending cancelations are removed. */
+    protected final void cancelAfterDoubleTapTimeout(
+            MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        cancelAfter(ViewConfiguration.getDoubleTapTimeout(), event, rawEvent, policyFlags);
+    }
+
+    /**
+     * Cancels this matcher after the specified timeout. Any pending cancelations are removed. Used
+     * to prevent this matcher from accepting motion events until it is cleared.
+     */
+    protected final void cancelAfter(
+            long timeout, MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        mDelayedTransition.cancel();
+        mDelayedTransition.post(STATE_GESTURE_CANCELED, timeout, event, rawEvent, policyFlags);
+    }
+
+    /** Cancels any delayed transitions between states scheduled for this matcher. */
+    protected final void cancelPendingTransitions() {
+        mDelayedTransition.cancel();
+    }
+
+    /**
+     * Signals that this gesture has been completed after the tap timeout has expired. Used to
+     * ensure that there is no conflict with another gesture or for gestures that explicitly require
+     * a hold.
+     */
+    protected final void completeAfterLongPressTimeout(
+            MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        completeAfter(ViewConfiguration.getLongPressTimeout(), event, rawEvent, policyFlags);
+    }
+
+    /**
+     * Signals that this gesture has been completed after the tap timeout has expired. Used to
+     * ensure that there is no conflict with another gesture or for gestures that explicitly require
+     * a hold.
+     */
+    protected final void completeAfterTapTimeout(
+            MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        completeAfter(ViewConfiguration.getTapTimeout(), event, rawEvent, policyFlags);
+    }
+
+    /**
+     * Signals that this gesture has been completed after the specified timeout has expired. Used to
+     * ensure that there is no conflict with another gesture or for gestures that explicitly require
+     * a hold.
+     */
+    protected final void completeAfter(
+            long timeout, MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        mDelayedTransition.cancel();
+        mDelayedTransition.post(STATE_GESTURE_COMPLETED, timeout, event, rawEvent, policyFlags);
+    }
+
+    /**
+     * Signals that this gesture has been completed after the double-tap timeout has expired. Used
+     * to ensure that there is no conflict with another gesture or for gestures that explicitly
+     * require a hold.
+     */
+    protected final void completeAfterDoubleTapTimeout(
+            MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        completeAfter(ViewConfiguration.getDoubleTapTimeout(), event, rawEvent, policyFlags);
+    }
+
+    public static String getStateSymbolicName(@State int state) {
+        switch (state) {
+            case STATE_CLEAR:
+                return "STATE_CLEAR";
+            case STATE_GESTURE_STARTED:
+                return "STATE_GESTURE_STARTED";
+            case STATE_GESTURE_COMPLETED:
+                return "STATE_GESTURE_COMPLETED";
+            case STATE_GESTURE_CANCELED:
+                return "STATE_GESTURE_CANCELED";
+            default:
+                return "Unknown state: " + state;
+        }
+    }
+
+    /**
+     * Returns a readable name for this matcher that can be displayed to the user and in system
+     * logs.
+     */
+    abstract String getGestureName();
+
+    /**
+     * Returns a String representation of this matcher. Each matcher can override this method to add
+     * extra state information to the string representation.
+     */
+    public String toString() {
+        return getGestureName() + ":" + getStateSymbolicName(mState);
+    }
+
+    /** This class allows matchers to transition between states on a delay. */
+    protected final class DelayedTransition implements Runnable {
+
+        private static final String LOG_TAG = "GestureMatcher.DelayedTransition";
+        int mTargetState;
+        MotionEvent mEvent;
+        MotionEvent mRawEvent;
+        int mPolicyFlags;
+
+        public void cancel() {
+            // Avoid meaningless debug messages.
+            if (DEBUG && isPending()) {
+                Slog.d(
+                        LOG_TAG,
+                        getGestureName()
+                                + ": canceling delayed transition to "
+                                + getStateSymbolicName(mTargetState));
+            }
+            mHandler.removeCallbacks(this);
+        }
+
+        public void post(
+                int state, long delay, MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+            mTargetState = state;
+            mEvent = event;
+            mRawEvent = rawEvent;
+            mPolicyFlags = policyFlags;
+            mHandler.postDelayed(this, delay);
+            if (DEBUG) {
+                Slog.d(
+                        LOG_TAG,
+                        getGestureName()
+                                + ": posting delayed transition to "
+                                + getStateSymbolicName(mTargetState));
+            }
+        }
+
+        public boolean isPending() {
+            return mHandler.hasCallbacks(this);
+        }
+
+        public void forceSendAndRemove() {
+            if (isPending()) {
+                run();
+                cancel();
+            }
+        }
+
+        @Override
+        public void run() {
+            if (DEBUG) {
+                Slog.d(
+                        LOG_TAG,
+                        getGestureName()
+                                + ": executing delayed transition to "
+                                + getStateSymbolicName(mTargetState));
+            }
+            setState(mTargetState, mEvent, mRawEvent, mPolicyFlags);
+        }
+    }
+
+    /** Interface to allow a class to listen for state changes in a specific gesture matcher */
+    interface StateChangeListener {
+
+        void onStateChanged(
+                int gestureId, int state, MotionEvent event, MotionEvent rawEvent, int policyFlags);
+    }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiTap.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiTap.java
new file mode 100644
index 0000000..2891c6c
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiTap.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2019 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.accessibility.gestures;
+
+import android.content.Context;
+import android.os.Handler;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+/**
+ * This class matches multi-tap gestures. The number of taps for each instance is specified in the
+ * constructor.
+ */
+class MultiTap extends GestureMatcher {
+
+    // Maximum reasonable number of taps.
+    public static final int MAX_TAPS = 10;
+    final int mTargetTaps;
+    // The acceptable distance between two taps
+    int mDoubleTapSlop;
+    // The acceptable distance the pointer can move and still count as a tap.
+    int mTouchSlop;
+    int mTapTimeout;
+    int mDoubleTapTimeout;
+    int mCurrentTaps;
+    float mBaseX;
+    float mBaseY;
+
+    MultiTap(Context context, int taps, int gesture, GestureMatcher.StateChangeListener listener) {
+        super(gesture, new Handler(context.getMainLooper()), listener);
+        mTargetTaps = taps;
+        mDoubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop();
+        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+        mTapTimeout = ViewConfiguration.getTapTimeout();
+        mDoubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
+        clear();
+    }
+
+    @Override
+    protected void clear() {
+        mCurrentTaps = 0;
+        mBaseX = Float.NaN;
+        mBaseY = Float.NaN;
+        super.clear();
+    }
+
+    @Override
+    protected void onDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        cancelAfterTapTimeout(event, rawEvent, policyFlags);
+        if (Float.isNaN(mBaseX) && Float.isNaN(mBaseY)) {
+            mBaseX = event.getX();
+            mBaseY = event.getY();
+        }
+        if (!isInsideSlop(rawEvent, mDoubleTapSlop)) {
+            cancelGesture(event, rawEvent, policyFlags);
+        }
+        mBaseX = event.getX();
+        mBaseY = event.getY();
+    }
+
+    @Override
+    protected void onUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        cancelAfterDoubleTapTimeout(event, rawEvent, policyFlags);
+        if (!isInsideSlop(rawEvent, mTouchSlop)) {
+            cancelGesture(event, rawEvent, policyFlags);
+        }
+        if (getState() == STATE_GESTURE_STARTED || getState() == STATE_CLEAR) {
+            mCurrentTaps++;
+            if (mCurrentTaps == mTargetTaps) {
+                // Done.
+                completeAfterTapTimeout(event, rawEvent, policyFlags);
+                return;
+            }
+            // Needs more taps.
+            cancelAfterDoubleTapTimeout(event, rawEvent, policyFlags);
+        } else {
+            // Either too many taps or nonsensical event stream.
+            cancelGesture(event, rawEvent, policyFlags);
+        }
+    }
+
+    @Override
+    protected void onMove(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (!isInsideSlop(rawEvent, mTouchSlop)) {
+            cancelGesture(event, rawEvent, policyFlags);
+        }
+    }
+
+    @Override
+    protected void onPointerDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        cancelGesture(event, rawEvent, policyFlags);
+    }
+
+    @Override
+    protected void onPointerUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        cancelGesture(event, rawEvent, policyFlags);
+    }
+
+    @Override
+    public String getGestureName() {
+        switch (mTargetTaps) {
+            case 2:
+                return "Double Tap";
+            case 3:
+                return "Triple Tap";
+            default:
+                return Integer.toString(mTargetTaps) + " Taps";
+        }
+    }
+
+    private boolean isInsideSlop(MotionEvent rawEvent, int slop) {
+        final float deltaX = mBaseX - rawEvent.getX();
+        final float deltaY = mBaseY - rawEvent.getY();
+        if (deltaX == 0 && deltaY == 0) {
+            return true;
+        }
+        final double moveDelta = Math.hypot(deltaX, deltaY);
+        return moveDelta <= slop;
+    }
+
+    @Override
+    public String toString() {
+        return super.toString()
+                + ", Taps:"
+                + mCurrentTaps
+                + ", mBaseX: "
+                + Float.toString(mBaseX)
+                + ", mBaseY: "
+                + Float.toString(mBaseY);
+    }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiTapAndHold.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiTapAndHold.java
new file mode 100644
index 0000000..6a1f1a5
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiTapAndHold.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2019 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.accessibility.gestures;
+
+import android.content.Context;
+import android.view.MotionEvent;
+
+/**
+ * This class matches gestures of the form multi-tap and hold. The number of taps for each instance
+ * is specified in the constructor.
+ */
+class MultiTapAndHold extends MultiTap {
+    MultiTapAndHold(
+            Context context, int taps, int gesture, GestureMatcher.StateChangeListener listener) {
+        super(context, taps, gesture, listener);
+    }
+
+    @Override
+    protected void onDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        super.onDown(event, rawEvent, policyFlags);
+        if (mCurrentTaps + 1 == mTargetTaps) {
+            completeAfterLongPressTimeout(event, rawEvent, policyFlags);
+        }
+    }
+
+    @Override
+    public String getGestureName() {
+        switch (mTargetTaps) {
+            case 2:
+                return "Double Tap and Hold";
+            case 3:
+                return "Triple Tap and Hold";
+            default:
+                return Integer.toString(mTargetTaps) + " Taps and Hold";
+        }
+    }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/Swipe.java b/services/accessibility/java/com/android/server/accessibility/gestures/Swipe.java
new file mode 100644
index 0000000..b246c67
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/Swipe.java
@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2019 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.accessibility.gestures;
+
+import static com.android.server.accessibility.gestures.TouchExplorer.DEBUG;
+
+import android.content.Context;
+import android.gesture.GesturePoint;
+import android.graphics.PointF;
+import android.os.Handler;
+import android.util.DisplayMetrics;
+import android.util.Slog;
+import android.util.TypedValue;
+import android.view.MotionEvent;
+
+import java.util.ArrayList;
+
+/**
+ * This class is responsible for matching one-finger swipe gestures. Each instance matches one swipe
+ * gesture. A swipe is specified as a series of one or more directions e.g. left, left and up, etc.
+ * At this time swipes with more than two directions are not supported.
+ */
+class Swipe extends GestureMatcher {
+
+    // Direction constants.
+    public static final int LEFT = 0;
+    public static final int RIGHT = 1;
+    public static final int UP = 2;
+    public static final int DOWN = 3;
+    // This is the calculated movement threshold used track if the user is still
+    // moving their finger.
+    private final float mGestureDetectionThreshold;
+
+    // Buffer for storing points for gesture detection.
+    private final ArrayList<GesturePoint> mStrokeBuffer = new ArrayList<GesturePoint>(100);
+
+    // The minimal delta between moves to add a gesture point.
+    private static final int TOUCH_TOLERANCE_PIX = 3;
+
+    // The minimal score for accepting a predicted gesture.
+    private static final float MIN_PREDICTION_SCORE = 2.0f;
+
+    // Distance a finger must travel before we decide if it is a gesture or not.
+    private static final int GESTURE_CONFIRM_CM = 1;
+
+    // Time threshold used to determine if an interaction is a gesture or not.
+    // If the first movement of 1cm takes longer than this value, we assume it's
+    // a slow movement, and therefore not a gesture.
+    //
+    // This value was determined by measuring the time for the first 1cm
+    // movement when gesturing, and touch exploring.  Based on user testing,
+    // all gestures started with the initial movement taking less than 100ms.
+    // When touch exploring, the first movement almost always takes longer than
+    // 200ms.
+    private static final long CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS = 150;
+
+    // Time threshold used to determine if a gesture should be cancelled.  If
+    // the finger takes more than this time to move 1cm, the ongoing gesture is
+    // cancelled.
+    private static final long CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS = 300;
+
+    private int[] mDirections;
+    private float mBaseX;
+    private float mBaseY;
+    private long mBaseTime;
+    private float mPreviousGestureX;
+    private float mPreviousGestureY;
+    // Constants for sampling motion event points.
+    // We sample based on a minimum distance between points, primarily to improve accuracy by
+    // reducing noisy minor changes in direction.
+    private static final float MIN_CM_BETWEEN_SAMPLES = 0.25f;
+    private final float mMinPixelsBetweenSamplesX;
+    private final float mMinPixelsBetweenSamplesY;
+
+    // Constants for separating gesture segments
+    private static final float ANGLE_THRESHOLD = 0.0f;
+
+    Swipe(
+            Context context,
+            int direction,
+            int gesture,
+            GestureMatcher.StateChangeListener listener) {
+        this(context, new int[] {direction}, gesture, listener);
+    }
+
+    Swipe(
+            Context context,
+            int direction1,
+            int direction2,
+            int gesture,
+            GestureMatcher.StateChangeListener listener) {
+        this(context, new int[] {direction1, direction2}, gesture, listener);
+    }
+
+    private Swipe(
+            Context context,
+            int[] directions,
+            int gesture,
+            GestureMatcher.StateChangeListener listener) {
+        super(gesture, new Handler(context.getMainLooper()), listener);
+        mDirections = directions;
+        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+        mGestureDetectionThreshold =
+                TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 10, displayMetrics)
+                        * GESTURE_CONFIRM_CM;
+        // Calculate minimum gesture velocity
+        final float pixelsPerCmX = displayMetrics.xdpi / 2.54f;
+        final float pixelsPerCmY = displayMetrics.ydpi / 2.54f;
+        mMinPixelsBetweenSamplesX = MIN_CM_BETWEEN_SAMPLES * pixelsPerCmX;
+        mMinPixelsBetweenSamplesY = MIN_CM_BETWEEN_SAMPLES * pixelsPerCmY;
+        clear();
+    }
+
+    @Override
+    protected void clear() {
+        mBaseX = Float.NaN;
+        mBaseY = Float.NaN;
+        mBaseTime = 0;
+        mStrokeBuffer.clear();
+        super.clear();
+    }
+
+    @Override
+    protected void onDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        cancelAfterDelay(event, rawEvent, policyFlags);
+        if (Float.isNaN(mBaseX) && Float.isNaN(mBaseY)) {
+            mBaseX = rawEvent.getX();
+            mBaseY = rawEvent.getY();
+            mBaseTime = event.getEventTime();
+            mPreviousGestureX = mBaseX;
+            mPreviousGestureY = mBaseY;
+        }
+        // Otherwise do nothing because this event doesn't make sense in the middle of a gesture.
+    }
+
+    @Override
+    protected void onMove(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        final float x = rawEvent.getX();
+        final float y = rawEvent.getY();
+        final long time = event.getEventTime();
+        final float dX = Math.abs(x - mPreviousGestureX);
+        final float dY = Math.abs(y - mPreviousGestureY);
+        final long timeDelta = time - mBaseTime;
+        final double moveDelta = Math.hypot(Math.abs(x - mBaseX), Math.abs(y - mBaseY));
+        if (DEBUG) {
+            Slog.d(
+                    getGestureName(),
+                    "moveDelta:"
+                            + Double.toString(moveDelta)
+                            + " mGestureDetectionThreshold: "
+                            + Float.toString(mGestureDetectionThreshold));
+        }
+        if (getState() == STATE_CLEAR) {
+            if (mStrokeBuffer.size() == 0) {
+                // First, make sure the pointer is going in the right direction.
+                cancelAfterDelay(event, rawEvent, policyFlags);
+                int direction = toDirection(x - mBaseX, y - mBaseY);
+                if (direction != mDirections[0]) {
+                    cancelGesture(event, rawEvent, policyFlags);
+                    return;
+                } else {
+                    // This is confirmed to be some kind of swipe so start tracking points.
+                    mStrokeBuffer.add(new GesturePoint(mBaseX, mBaseY, mBaseTime));
+                }
+            }
+            if (moveDelta > mGestureDetectionThreshold) {
+                // If the pointer has moved more than the threshold,
+                // update the stored values.
+                mBaseX = x;
+                mBaseY = y;
+                mBaseTime = time;
+                if (getState() == STATE_CLEAR) {
+                    startGesture(event, rawEvent, policyFlags);
+                    cancelAfterDelay(event, rawEvent, policyFlags);
+                }
+            }
+        }
+        if (getState() == STATE_GESTURE_STARTED) {
+            if (dX >= mMinPixelsBetweenSamplesX || dY >= mMinPixelsBetweenSamplesY) {
+                mPreviousGestureX = x;
+                mPreviousGestureY = y;
+                mStrokeBuffer.add(new GesturePoint(x, y, time));
+                cancelAfterDelay(event, rawEvent, policyFlags);
+            }
+        }
+    }
+
+    @Override
+    protected void onUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (getState() != STATE_GESTURE_STARTED) {
+            cancelGesture(event, rawEvent, policyFlags);
+            return;
+        }
+
+        final float x = rawEvent.getX();
+        final float y = rawEvent.getY();
+        final long time = event.getEventTime();
+        final float dX = Math.abs(x - mPreviousGestureX);
+        final float dY = Math.abs(y - mPreviousGestureY);
+        if (dX >= mMinPixelsBetweenSamplesX || dY >= mMinPixelsBetweenSamplesY) {
+            mStrokeBuffer.add(new GesturePoint(x, y, time));
+        }
+        recognizeGesture(event, rawEvent, policyFlags);
+    }
+
+    @Override
+    protected void onPointerDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        cancelGesture(event, rawEvent, policyFlags);
+    }
+
+    @Override
+    protected void onPointerUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        cancelGesture(event, rawEvent, policyFlags);
+    }
+
+    /**
+     * queues a transition to STATE_GESTURE_CANCEL based on the current state. If we have
+     * transitioned to STATE_GESTURE_STARTED the delay is longer.
+     */
+    private void cancelAfterDelay(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        cancelPendingTransitions();
+        switch (getState()) {
+            case STATE_CLEAR:
+                cancelAfter(CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS, event, rawEvent, policyFlags);
+                break;
+            case STATE_GESTURE_STARTED:
+                cancelAfter(CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS, event, rawEvent, policyFlags);
+                break;
+            default:
+                break;
+        }
+    }
+
+    /**
+     * Looks at the sequence of motions in mStrokeBuffer, classifies the gesture, then calls
+     * Listener callbacks for success or failure.
+     *
+     * @param event The raw motion event to pass to the listener callbacks.
+     * @param policyFlags Policy flags for the event.
+     * @return true if the event is consumed, else false
+     */
+    private void recognizeGesture(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (mStrokeBuffer.size() < 2) {
+            cancelGesture(event, rawEvent, policyFlags);
+            return;
+        }
+
+        // Look at mStrokeBuffer and extract 2 line segments, delimited by near-perpendicular
+        // direction change.
+        // Method: for each sampled motion event, check the angle of the most recent motion vector
+        // versus the preceding motion vector, and segment the line if the angle is about
+        // 90 degrees.
+
+        ArrayList<PointF> path = new ArrayList<>();
+        PointF lastDelimiter = new PointF(mStrokeBuffer.get(0).x, mStrokeBuffer.get(0).y);
+        path.add(lastDelimiter);
+
+        float dX = 0; // Sum of unit vectors from last delimiter to each following point
+        float dY = 0;
+        int count = 0; // Number of points since last delimiter
+        float length = 0; // Vector length from delimiter to most recent point
+
+        PointF next = new PointF();
+        for (int i = 1; i < mStrokeBuffer.size(); ++i) {
+            next = new PointF(mStrokeBuffer.get(i).x, mStrokeBuffer.get(i).y);
+            if (count > 0) {
+                // Average of unit vectors from delimiter to following points
+                float currentDX = dX / count;
+                float currentDY = dY / count;
+
+                // newDelimiter is a possible new delimiter, based on a vector with length from
+                // the last delimiter to the previous point, but in the direction of the average
+                // unit vector from delimiter to previous points.
+                // Using the averaged vector has the effect of "squaring off the curve",
+                // creating a sharper angle between the last motion and the preceding motion from
+                // the delimiter. In turn, this sharper angle achieves the splitting threshold
+                // even in a gentle curve.
+                PointF newDelimiter =
+                        new PointF(
+                                length * currentDX + lastDelimiter.x,
+                                length * currentDY + lastDelimiter.y);
+
+                // Unit vector from newDelimiter to the most recent point
+                float nextDX = next.x - newDelimiter.x;
+                float nextDY = next.y - newDelimiter.y;
+                float nextLength = (float) Math.sqrt(nextDX * nextDX + nextDY * nextDY);
+                nextDX = nextDX / nextLength;
+                nextDY = nextDY / nextLength;
+
+                // Compare the initial motion direction to the most recent motion direction,
+                // and segment the line if direction has changed by about 90 degrees.
+                float dot = currentDX * nextDX + currentDY * nextDY;
+                if (dot < ANGLE_THRESHOLD) {
+                    path.add(newDelimiter);
+                    lastDelimiter = newDelimiter;
+                    dX = 0;
+                    dY = 0;
+                    count = 0;
+                }
+            }
+
+            // Vector from last delimiter to most recent point
+            float currentDX = next.x - lastDelimiter.x;
+            float currentDY = next.y - lastDelimiter.y;
+            length = (float) Math.sqrt(currentDX * currentDX + currentDY * currentDY);
+
+            // Increment sum of unit vectors from delimiter to each following point
+            count = count + 1;
+            dX = dX + currentDX / length;
+            dY = dY + currentDY / length;
+        }
+
+        path.add(next);
+        if (DEBUG) {
+            Slog.d(getGestureName(), "path=" + path.toString());
+        }
+        // Classify line segments, and call Listener callbacks.
+        recognizeGesturePath(event, rawEvent, policyFlags, path);
+    }
+
+    /**
+     * Classifies a pair of line segments, by direction. Calls Listener callbacks for success or
+     * failure.
+     *
+     * @param event The raw motion event to pass to the listener's onGestureCanceled method.
+     * @param policyFlags Policy flags for the event.
+     * @param path A sequence of motion line segments derived from motion points in mStrokeBuffer.
+     * @return true if the event is consumed, else false
+     */
+    private void recognizeGesturePath(
+            MotionEvent event, MotionEvent rawEvent, int policyFlags, ArrayList<PointF> path) {
+
+        final int displayId = event.getDisplayId();
+        if (path.size() != mDirections.length + 1) {
+            cancelGesture(event, rawEvent, policyFlags);
+            return;
+        }
+        for (int i = 0; i < path.size() - 1; ++i) {
+            PointF start = path.get(i);
+            PointF end = path.get(i + 1);
+
+            float dX = end.x - start.x;
+            float dY = end.y - start.y;
+            int direction = toDirection(dX, dY);
+            if (direction != mDirections[i]) {
+                if (DEBUG) {
+                    Slog.d(
+                            getGestureName(),
+                            "Found direction "
+                                    + directionToString(direction)
+                                    + " when expecting "
+                                    + directionToString(mDirections[i]));
+                }
+                cancelGesture(event, rawEvent, policyFlags);
+                return;
+            }
+        }
+        if (DEBUG) {
+            Slog.d(getGestureName(), "Completed.");
+        }
+        completeGesture(event, rawEvent, policyFlags);
+    }
+
+    private static int toDirection(float dX, float dY) {
+        if (Math.abs(dX) > Math.abs(dY)) {
+            // Horizontal
+            return (dX < 0) ? LEFT : RIGHT;
+        } else {
+            // Vertical
+            return (dY < 0) ? UP : DOWN;
+        }
+    }
+
+    public static String directionToString(int direction) {
+        switch (direction) {
+            case LEFT:
+                return "left";
+            case RIGHT:
+                return "right";
+            case UP:
+                return "up";
+            case DOWN:
+                return "down";
+            default:
+                return "Unknown Direction";
+        }
+    }
+
+    @Override
+    String getGestureName() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("Swipe ").append(directionToString(mDirections[0]));
+        for (int i = 1; i < mDirections.length; ++i) {
+            builder.append(" and ").append(directionToString(mDirections[i]));
+        }
+        return builder.toString();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder(super.toString());
+        if (getState() != STATE_GESTURE_CANCELED) {
+            builder.append(", mBaseX: ")
+                    .append(mBaseX)
+                    .append(", mBaseY: ")
+                    .append(mBaseY)
+                    .append(", mGestureDetectionThreshold:")
+                    .append(mGestureDetectionThreshold)
+                    .append(", mMinPixelsBetweenSamplesX:")
+                    .append(mMinPixelsBetweenSamplesX)
+                    .append(", mMinPixelsBetweenSamplesY:")
+                    .append(mMinPixelsBetweenSamplesY);
+        }
+        return builder.toString();
+    }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index b62e260..5f41638 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -59,7 +59,7 @@
  * @hide
  */
 public class TouchExplorer extends BaseEventStreamTransformation
-        implements AccessibilityGestureDetector.Listener {
+        implements GestureManifold.Listener {
 
     static final boolean DEBUG = false;
 
@@ -104,7 +104,7 @@
     private final ExitGestureDetectionModeDelayed mExitGestureDetectionModeDelayed;
 
     // Helper to detect gestures.
-    private final AccessibilityGestureDetector mGestureDetector;
+    private final GestureManifold  mGestureDetector;
 
     // Helper class to track received pointers.
     private final TouchState.ReceivedPointerTracker mReceivedPointerTracker;
@@ -142,7 +142,7 @@
      *                one created in place, or for testing purpose.
      */
     public TouchExplorer(Context context, AccessibilityManagerService service,
-            AccessibilityGestureDetector detector) {
+            GestureManifold detector) {
         mContext = context;
         mAms = service;
         mState = new TouchState();
@@ -161,7 +161,7 @@
                 AccessibilityEvent.TYPE_TOUCH_INTERACTION_END,
                 mDetermineUserIntentTimeout);
         if (detector == null) {
-            mGestureDetector = new AccessibilityGestureDetector(context, this);
+            mGestureDetector = new GestureManifold(context, this, mState);
         } else {
             mGestureDetector = detector;
         }
@@ -285,7 +285,7 @@
     }
 
     @Override
-    public void onDoubleTapAndHold(MotionEvent event, int policyFlags) {
+    public void onDoubleTapAndHold() {
         // Ignore the event if we aren't touch interacting.
         if (!mState.isTouchInteracting()) {
             return;
@@ -303,7 +303,7 @@
     }
 
     @Override
-    public boolean onDoubleTap(MotionEvent event, int policyFlags) {
+    public boolean onDoubleTap() {
         if (!mState.isTouchInteracting()) {
             return false;
         }
@@ -319,7 +319,7 @@
 
         // Announce the end of a new touch interaction.
         mDispatcher.sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
-
+        mSendTouchInteractionEndDelayed.cancel();
         // Try to use the standard accessibility API to click
         if (!mAms.performActionOnAccessibilityFocusedItem(
                 AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK)) {
@@ -356,7 +356,7 @@
     }
 
     @Override
-    public boolean onGestureCancelled(MotionEvent event, int policyFlags) {
+    public boolean onGestureCancelled(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
         if (mState.isGestureDetecting()) {
             endGestureDetection(event.getActionMasked() == MotionEvent.ACTION_UP);
             return true;
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
index f463260..d23dbbe 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
@@ -71,7 +71,10 @@
     // Helper class to track received pointers.
     // Todo: collapse or hide this class so multiple classes don't modify it.
     private final ReceivedPointerTracker mReceivedPointerTracker;
+    // The most recently received motion event.
     private MotionEvent mLastReceivedEvent;
+    // The accompanying raw event without any transformations.
+    private MotionEvent mLastReceivedRawEvent;
 
     public TouchState() {
         mReceivedPointerTracker = new ReceivedPointerTracker();
@@ -97,6 +100,9 @@
         if (mLastReceivedEvent != null) {
             mLastReceivedEvent.recycle();
         }
+        if (mLastReceivedRawEvent != null) {
+            mLastReceivedRawEvent.recycle();
+        }
         mLastReceivedEvent = MotionEvent.obtain(rawEvent);
         mReceivedPointerTracker.onMotionEvent(rawEvent);
     }
@@ -246,7 +252,6 @@
         // or if it goes up the next one that most recently went down.
         private int mPrimaryPointerId;
 
-
         ReceivedPointerTracker() {
             clear();
         }
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index f79b876..49046b2 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -341,14 +341,16 @@
      * @param responseObj The response of the first phase of ephemeral resolution
      * @param origIntent The original intent that triggered ephemeral resolution
      * @param resolvedType The resolved type of the intent
-     * @param callingPackage The name of the package requesting the ephemeral application
+     * @param callingPkg The app requesting the ephemeral application
+     * @param isRequesterInstantApp Whether or not the app requesting the ephemeral application
+     *                              is an instant app
      * @param verificationBundle Optional bundle to pass to the installer for additional
      * verification
      * @param userId The ID of the user that triggered ephemeral resolution
      */
     public abstract void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
-            Intent origIntent, String resolvedType, String callingPackage,
-            Bundle verificationBundle, int userId);
+            Intent origIntent, String resolvedType, String callingPkg,
+            boolean isRequesterInstantApp, Bundle verificationBundle, int userId);
 
     /**
      * Grants implicit access based on an interaction between two apps. This grants the target app
diff --git a/services/core/java/android/os/UserManagerInternal.java b/services/core/java/android/os/UserManagerInternal.java
index a2e9341..d84197c 100644
--- a/services/core/java/android/os/UserManagerInternal.java
+++ b/services/core/java/android/os/UserManagerInternal.java
@@ -57,7 +57,7 @@
      * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to set
      * restrictions enforced by the user.
      *
-     * @param userId target user id for the local restrictions.
+     * @param originatingUserId user id of the user where the restriction originated.
      * @param restrictions a bundle of user restrictions.
      * @param restrictionOwnerType determines which admin {@code userId} corresponds to.
      *             The admin can be either
@@ -70,8 +70,8 @@
      *             otherwise it will be applied just on the current user.
      * @see OwnerType
      */
-    public abstract void setDevicePolicyUserRestrictions(int userId, @Nullable Bundle restrictions,
-            @OwnerType int restrictionOwnerType);
+    public abstract void setDevicePolicyUserRestrictions(int originatingUserId,
+            @Nullable Bundle restrictions, @OwnerType int restrictionOwnerType);
 
     /**
      * Returns the "base" user restrictions.
diff --git a/services/core/java/com/android/server/biometrics/OWNERS b/services/core/java/com/android/server/biometrics/OWNERS
new file mode 100644
index 0000000..8765c9a
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/OWNERS
@@ -0,0 +1,7 @@
+set noparent
+
+kchyn@google.com
+jaggies@google.com
+curtislb@google.com
+ilyamaty@google.com
+joshmccloskey@google.com
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 9bae902..af8a366 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -39,11 +39,11 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.net.ISocketKeepaliveCallback;
+import android.net.InvalidPacketException;
 import android.net.KeepalivePacketData;
 import android.net.NattKeepalivePacketData;
 import android.net.NetworkAgent;
 import android.net.NetworkUtils;
-import android.net.SocketKeepalive.InvalidPacketException;
 import android.net.SocketKeepalive.InvalidSocketException;
 import android.net.TcpKeepalivePacketData;
 import android.net.util.IpUtils;
@@ -657,7 +657,10 @@
         final TcpKeepalivePacketData packet;
         try {
             packet = TcpKeepaliveController.getTcpKeepalivePacket(fd);
-        } catch (InvalidPacketException | InvalidSocketException e) {
+        } catch (InvalidSocketException e) {
+            notifyErrorCallback(cb, e.error);
+            return;
+        } catch (InvalidPacketException e) {
             notifyErrorCallback(cb, e.error);
             return;
         }
diff --git a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
index e570ef1e..1129899 100644
--- a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
+++ b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
@@ -30,8 +30,8 @@
 import static android.system.OsConstants.TIOCOUTQ;
 
 import android.annotation.NonNull;
+import android.net.InvalidPacketException;
 import android.net.NetworkUtils;
-import android.net.SocketKeepalive.InvalidPacketException;
 import android.net.SocketKeepalive.InvalidSocketException;
 import android.net.TcpKeepalivePacketData;
 import android.net.TcpKeepalivePacketDataParcelable;
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 2cb7e3b..069aeef 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -47,7 +47,8 @@
 import android.media.Session2CommandGroup;
 import android.media.Session2Token;
 import android.media.session.IActiveSessionsListener;
-import android.media.session.ICallback;
+import android.media.session.IOnMediaKeyEventDispatchedListener;
+import android.media.session.IOnMediaKeyEventSessionChangedListener;
 import android.media.session.IOnMediaKeyListener;
 import android.media.session.IOnVolumeKeyLongPressListener;
 import android.media.session.ISession;
@@ -750,7 +751,10 @@
 
         private final int mFullUserId;
         private final MediaSessionStack mPriorityStack;
-        private final HashMap<IBinder, CallbackRecord> mCallbacks = new HashMap<>();
+        private final HashMap<IBinder, OnMediaKeyEventDispatchedListenerRecord>
+                mOnMediaKeyEventDispatchedListeners = new HashMap<>();
+        private final HashMap<IBinder, OnMediaKeyEventSessionChangedListenerRecord>
+                mOnMediaKeyEventSessionChangedListeners = new HashMap<>();
 
         private PendingIntent mLastMediaButtonReceiver;
         private ComponentName mRestoredMediaButtonReceiver;
@@ -796,21 +800,47 @@
             }
         }
 
-        public void registerCallbackLocked(ICallback callback, int uid) {
-            IBinder cbBinder = callback.asBinder();
-            CallbackRecord cr = new CallbackRecord(callback, uid);
-            mCallbacks.put(cbBinder, cr);
+        public void addOnMediaKeyEventDispatchedListenerLocked(
+                IOnMediaKeyEventDispatchedListener listener, int uid) {
+            IBinder cbBinder = listener.asBinder();
+            OnMediaKeyEventDispatchedListenerRecord cr =
+                    new OnMediaKeyEventDispatchedListenerRecord(listener, uid);
+            mOnMediaKeyEventDispatchedListeners.put(cbBinder, cr);
             try {
                 cbBinder.linkToDeath(cr, 0);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed to register callback", e);
-                mCallbacks.remove(cbBinder);
+                Log.w(TAG, "Failed to add listener", e);
+                mOnMediaKeyEventDispatchedListeners.remove(cbBinder);
             }
         }
 
-        public void unregisterCallbackLocked(ICallback callback) {
-            IBinder cbBinder = callback.asBinder();
-            CallbackRecord cr = mCallbacks.remove(cbBinder);
+        public void removeOnMediaKeyEventDispatchedListenerLocked(
+                IOnMediaKeyEventDispatchedListener listener) {
+            IBinder cbBinder = listener.asBinder();
+            OnMediaKeyEventDispatchedListenerRecord cr =
+                    mOnMediaKeyEventDispatchedListeners.remove(cbBinder);
+            cbBinder.unlinkToDeath(cr, 0);
+        }
+
+        public void addOnMediaKeyEventSessionChangedListenerLocked(
+                IOnMediaKeyEventSessionChangedListener listener, int uid) {
+            IBinder cbBinder = listener.asBinder();
+            OnMediaKeyEventSessionChangedListenerRecord cr =
+                    new OnMediaKeyEventSessionChangedListenerRecord(listener, uid);
+            mOnMediaKeyEventSessionChangedListeners.put(cbBinder, cr);
+            try {
+                cbBinder.linkToDeath(cr, 0);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to add listener", e);
+                mOnMediaKeyEventSessionChangedListeners.remove(cbBinder);
+            }
+        }
+
+        public void removeOnMediaKeyEventSessionChangedListener(
+                IOnMediaKeyEventSessionChangedListener listener) {
+            IBinder cbBinder = listener.asBinder();
+            OnMediaKeyEventSessionChangedListenerRecord cr =
+                    mOnMediaKeyEventSessionChangedListeners.remove(cbBinder);
             cbBinder.unlinkToDeath(cr, 0);
         }
 
@@ -832,8 +862,16 @@
             pw.println(indent + "Media key listener: " + mOnMediaKeyListener);
             pw.println(indent + "Media key listener package: "
                     + getCallingPackageName(mOnMediaKeyListenerUid));
-            pw.println(indent + "Callbacks: registered " + mCallbacks.size() + " callback(s)");
-            for (CallbackRecord cr : mCallbacks.values()) {
+            pw.println(indent + "OnMediaKeyEventDispatchedListener: added "
+                    + mOnMediaKeyEventDispatchedListeners.size() + " listener(s)");
+            for (OnMediaKeyEventDispatchedListenerRecord cr
+                    : mOnMediaKeyEventDispatchedListeners.values()) {
+                pw.println(indent + "  from " + getCallingPackageName(cr.uid));
+            }
+            pw.println(indent + "OnMediaKeyEventSessionChangedListener: added "
+                    + mOnMediaKeyEventSessionChangedListeners.size() + " listener(s)");
+            for (OnMediaKeyEventSessionChangedListenerRecord cr
+                    : mOnMediaKeyEventSessionChangedListeners.values()) {
                 pw.println(indent + "  from " + getCallingPackageName(cr.uid));
             }
             pw.println(indent + "Last MediaButtonReceiver: " + mLastMediaButtonReceiver);
@@ -895,19 +933,22 @@
                     mFullUserId);
         }
 
-        private void pushAddressedPlayerChangedLocked(ICallback callback) {
+        private void pushAddressedPlayerChangedLocked(
+                IOnMediaKeyEventSessionChangedListener callback) {
             try {
                 MediaSessionRecord mediaButtonSession = getMediaButtonSessionLocked();
                 if (mediaButtonSession != null) {
-                    callback.onAddressedPlayerChangedToMediaSession(
+                    callback.onMediaKeyEventSessionChanged(mediaButtonSession.getPackageName(),
                             mediaButtonSession.getSessionToken());
                 } else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) {
-                    callback.onAddressedPlayerChangedToMediaButtonReceiver(
+                    callback.onMediaKeyEventSessionChanged(
                             mCurrentFullUserRecord.mLastMediaButtonReceiver
-                                    .getIntent().getComponent());
+                                    .getIntent().getComponent().getPackageName(),
+                            null);
                 } else if (mCurrentFullUserRecord.mRestoredMediaButtonReceiver != null) {
-                    callback.onAddressedPlayerChangedToMediaButtonReceiver(
-                            mCurrentFullUserRecord.mRestoredMediaButtonReceiver);
+                    callback.onMediaKeyEventSessionChanged(
+                            mCurrentFullUserRecord.mRestoredMediaButtonReceiver.getPackageName(),
+                            null);
                 }
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed to pushAddressedPlayerChangedLocked", e);
@@ -915,7 +956,8 @@
         }
 
         private void pushAddressedPlayerChangedLocked() {
-            for (CallbackRecord cr : mCallbacks.values()) {
+            for (OnMediaKeyEventSessionChangedListenerRecord cr
+                    : mOnMediaKeyEventSessionChangedListeners.values()) {
                 pushAddressedPlayerChangedLocked(cr.callback);
             }
         }
@@ -954,11 +996,12 @@
             return COMPONENT_TYPE_BROADCAST;
         }
 
-        final class CallbackRecord implements IBinder.DeathRecipient {
-            public final ICallback callback;
+        final class OnMediaKeyEventDispatchedListenerRecord implements IBinder.DeathRecipient {
+            public final IOnMediaKeyEventDispatchedListener callback;
             public final int uid;
 
-            CallbackRecord(ICallback callback, int uid) {
+            OnMediaKeyEventDispatchedListenerRecord(IOnMediaKeyEventDispatchedListener callback,
+                    int uid) {
                 this.callback = callback;
                 this.uid = uid;
             }
@@ -966,7 +1009,25 @@
             @Override
             public void binderDied() {
                 synchronized (mLock) {
-                    mCallbacks.remove(callback.asBinder());
+                    mOnMediaKeyEventDispatchedListeners.remove(callback.asBinder());
+                }
+            }
+        }
+
+        final class OnMediaKeyEventSessionChangedListenerRecord implements IBinder.DeathRecipient {
+            public final IOnMediaKeyEventSessionChangedListener callback;
+            public final int uid;
+
+            OnMediaKeyEventSessionChangedListenerRecord(
+                    IOnMediaKeyEventSessionChangedListener callback, int uid) {
+                this.callback = callback;
+                this.uid = uid;
+            }
+
+            @Override
+            public void binderDied() {
+                synchronized (mLock) {
+                    mOnMediaKeyEventSessionChangedListeners.remove(callback.asBinder());
                 }
             }
         }
@@ -1355,7 +1416,8 @@
         }
 
         @Override
-        public void registerCallback(final ICallback callback) {
+        public void addOnMediaKeyEventDispatchedListener(
+                final IOnMediaKeyEventDispatchedListener listener) {
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
             final int userId = UserHandle.getUserId(uid);
@@ -1363,18 +1425,18 @@
             try {
                 if (!hasMediaControlPermission(pid, uid)) {
                     throw new SecurityException("MEDIA_CONTENT_CONTROL permission is required to"
-                            + "  register Callback");
+                            + "  add MediaKeyEventDispatchedListener");
                 }
                 synchronized (mLock) {
                     FullUserRecord user = getFullUserRecordLocked(userId);
                     if (user == null || user.mFullUserId != userId) {
-                        Log.w(TAG, "Only the full user can register the callback"
+                        Log.w(TAG, "Only the full user can add the listener"
                                 + ", userId=" + userId);
                         return;
                     }
-                    user.registerCallbackLocked(callback, uid);
-                    Log.d(TAG, "The callback (" + callback.asBinder()
-                            + ") is registered by " + getCallingPackageName(uid));
+                    user.addOnMediaKeyEventDispatchedListenerLocked(listener, uid);
+                    Log.d(TAG, "The MediaKeyEventDispatchedListener (" + listener.asBinder()
+                            + ") is added by " + getCallingPackageName(uid));
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -1382,7 +1444,8 @@
         }
 
         @Override
-        public void unregisterCallback(final ICallback callback) {
+        public void removeOnMediaKeyEventDispatchedListener(
+                final IOnMediaKeyEventDispatchedListener listener) {
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
             final int userId = UserHandle.getUserId(uid);
@@ -1390,18 +1453,74 @@
             try {
                 if (!hasMediaControlPermission(pid, uid)) {
                     throw new SecurityException("MEDIA_CONTENT_CONTROL permission is required to"
-                            + "  unregister Callback");
+                            + "  remove MediaKeyEventDispatchedListener");
                 }
                 synchronized (mLock) {
                     FullUserRecord user = getFullUserRecordLocked(userId);
                     if (user == null || user.mFullUserId != userId) {
-                        Log.w(TAG, "Only the full user can unregister the callback"
+                        Log.w(TAG, "Only the full user can remove the listener"
                                 + ", userId=" + userId);
                         return;
                     }
-                    user.unregisterCallbackLocked(callback);
-                    Log.d(TAG, "The callback (" + callback.asBinder()
-                            + ") is unregistered by " + getCallingPackageName(uid));
+                    user.removeOnMediaKeyEventDispatchedListenerLocked(listener);
+                    Log.d(TAG, "The MediaKeyEventDispatchedListener (" + listener.asBinder()
+                            + ") is removed by " + getCallingPackageName(uid));
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void addOnMediaKeyEventSessionChangedListener(
+                final IOnMediaKeyEventSessionChangedListener listener) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final int userId = UserHandle.getUserId(uid);
+            final long token = Binder.clearCallingIdentity();
+            try {
+                if (!hasMediaControlPermission(pid, uid)) {
+                    throw new SecurityException("MEDIA_CONTENT_CONTROL permission is required to"
+                            + "  add MediaKeyEventSessionChangedListener");
+                }
+                synchronized (mLock) {
+                    FullUserRecord user = getFullUserRecordLocked(userId);
+                    if (user == null || user.mFullUserId != userId) {
+                        Log.w(TAG, "Only the full user can add the listener"
+                                + ", userId=" + userId);
+                        return;
+                    }
+                    user.addOnMediaKeyEventSessionChangedListenerLocked(listener, uid);
+                    Log.d(TAG, "The MediaKeyEventSessionChangedListener (" + listener.asBinder()
+                            + ") is added by " + getCallingPackageName(uid));
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void removeOnMediaKeyEventSessionChangedListener(
+                final IOnMediaKeyEventSessionChangedListener listener) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final int userId = UserHandle.getUserId(uid);
+            final long token = Binder.clearCallingIdentity();
+            try {
+                if (!hasMediaControlPermission(pid, uid)) {
+                    throw new SecurityException("MEDIA_CONTENT_CONTROL permission is required to"
+                            + "  remove MediaKeyEventSessionChangedListener");
+                }
+                synchronized (mLock) {
+                    FullUserRecord user = getFullUserRecordLocked(userId);
+                    if (user == null || user.mFullUserId != userId) {
+                        Log.w(TAG, "Only the full user can remove the listener"
+                                + ", userId=" + userId);
+                        return;
+                    }
+                    user.removeOnMediaKeyEventSessionChangedListener(listener);
+                    Log.d(TAG, "The MediaKeyEventSessionChangedListener (" + listener.asBinder()
+                            + ") is removed by " + getCallingPackageName(uid));
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -2015,10 +2134,10 @@
                         needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
                         mKeyEventReceiver);
                 try {
-                    for (FullUserRecord.CallbackRecord cr
-                            : mCurrentFullUserRecord.mCallbacks.values()) {
-                        cr.callback.onMediaKeyEventDispatchedToMediaSession(
-                                keyEvent, session.getSessionToken());
+                    for (FullUserRecord.OnMediaKeyEventDispatchedListenerRecord cr
+                            : mCurrentFullUserRecord.mOnMediaKeyEventDispatchedListeners.values()) {
+                        cr.callback.onMediaKeyEventDispatched(
+                                keyEvent, session.getPackageName(), session.getSessionToken());
                     }
                 } catch (RemoteException e) {
                     Log.w(TAG, "Failed to send callback", e);
@@ -2048,10 +2167,11 @@
                         ComponentName componentName = mCurrentFullUserRecord
                                 .mLastMediaButtonReceiver.getIntent().getComponent();
                         if (componentName != null) {
-                            for (FullUserRecord.CallbackRecord cr
-                                    : mCurrentFullUserRecord.mCallbacks.values()) {
-                                cr.callback.onMediaKeyEventDispatchedToMediaButtonReceiver(
-                                                keyEvent, componentName);
+                            for (FullUserRecord.OnMediaKeyEventDispatchedListenerRecord cr
+                                    : mCurrentFullUserRecord
+                                    .mOnMediaKeyEventDispatchedListeners.values()) {
+                                cr.callback.onMediaKeyEventDispatched(keyEvent,
+                                        componentName.getPackageName(), null);
                             }
                         }
                     } else {
@@ -2083,10 +2203,11 @@
                             Log.w(TAG, "Error sending media button to the restored intent "
                                     + receiver + ", type=" + componentType, e);
                         }
-                        for (FullUserRecord.CallbackRecord cr
-                                : mCurrentFullUserRecord.mCallbacks.values()) {
-                            cr.callback.onMediaKeyEventDispatchedToMediaButtonReceiver(
-                                            keyEvent, receiver);
+                        for (FullUserRecord.OnMediaKeyEventDispatchedListenerRecord cr
+                                : mCurrentFullUserRecord
+                                .mOnMediaKeyEventDispatchedListeners.values()) {
+                            cr.callback.onMediaKeyEventDispatched(keyEvent,
+                                    receiver.getPackageName(), null);
                         }
                     }
                 } catch (CanceledException e) {
diff --git a/services/core/java/com/android/server/om/OverlayActorEnforcer.java b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
index e055116..ac3bf9a 100644
--- a/services/core/java/com/android/server/om/OverlayActorEnforcer.java
+++ b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
@@ -26,6 +26,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.text.TextUtils;
+import android.util.Pair;
 
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.CollectionUtils;
@@ -44,6 +45,38 @@
 
     private final VerifyCallback mVerifyCallback;
 
+    /**
+     * @return nullable actor result with {@link ActorState} failure status
+     */
+    static Pair<String, ActorState> getPackageNameForActor(String actorUriString,
+            Map<String, Map<String, String>> namedActors) {
+        if (namedActors.isEmpty()) {
+            return Pair.create(null, ActorState.NO_NAMED_ACTORS);
+        }
+
+        Uri actorUri = Uri.parse(actorUriString);
+
+        String actorScheme = actorUri.getScheme();
+        List<String> actorPathSegments = actorUri.getPathSegments();
+        if (!"overlay".equals(actorScheme) || CollectionUtils.size(actorPathSegments) != 1) {
+            return Pair.create(null, ActorState.INVALID_OVERLAYABLE_ACTOR_NAME);
+        }
+
+        String actorNamespace = actorUri.getAuthority();
+        Map<String, String> namespace = namedActors.get(actorNamespace);
+        if (namespace == null) {
+            return Pair.create(null, ActorState.MISSING_NAMESPACE);
+        }
+
+        String actorName = actorPathSegments.get(0);
+        String packageName = namespace.get(actorName);
+        if (TextUtils.isEmpty(packageName)) {
+            return Pair.create(null, ActorState.MISSING_ACTOR_NAME);
+        }
+
+        return Pair.create(packageName, ActorState.ALLOWED);
+    }
+
     public OverlayActorEnforcer(@NonNull VerifyCallback verifyCallback) {
         mVerifyCallback = verifyCallback;
     }
@@ -141,31 +174,14 @@
             }
         }
 
-        Map<String, ? extends Map<String, String>> namedActors = mVerifyCallback.getNamedActors();
-        if (namedActors.isEmpty()) {
-            return ActorState.NO_NAMED_ACTORS;
+        Map<String, Map<String, String>> namedActors = mVerifyCallback.getNamedActors();
+        Pair<String, ActorState> actorUriPair = getPackageNameForActor(actor, namedActors);
+        ActorState actorUriState = actorUriPair.second;
+        if (actorUriState != ActorState.ALLOWED) {
+            return actorUriState;
         }
 
-        Uri actorUri = Uri.parse(actor);
-
-        String actorScheme = actorUri.getScheme();
-        List<String> actorPathSegments = actorUri.getPathSegments();
-        if (!"overlay".equals(actorScheme) || CollectionUtils.size(actorPathSegments) != 1) {
-            return ActorState.INVALID_OVERLAYABLE_ACTOR_NAME;
-        }
-
-        String actorNamespace = actorUri.getAuthority();
-        Map<String, String> namespace = namedActors.get(actorNamespace);
-        if (namespace == null) {
-            return ActorState.MISSING_NAMESPACE;
-        }
-
-        String actorName = actorPathSegments.get(0);
-        String packageName = namespace.get(actorName);
-        if (TextUtils.isEmpty(packageName)) {
-            return ActorState.MISSING_ACTOR_NAME;
-        }
-
+        String packageName = actorUriPair.first;
         PackageInfo packageInfo = mVerifyCallback.getPackageInfo(packageName, userId);
         if (packageInfo == null) {
             return ActorState.MISSING_APP_INFO;
@@ -192,7 +208,7 @@
      * For easier logging/debugging, a set of all possible failure/success states when running
      * enforcement.
      */
-    private enum ActorState {
+    enum ActorState {
         ALLOWED,
         INVALID_ACTOR,
         MISSING_NAMESPACE,
@@ -244,7 +260,7 @@
          * value maps actor name to package name
          */
         @NonNull
-        Map<String, ? extends Map<String, String>> getNamedActors();
+        Map<String, Map<String, String>> getNamedActors();
 
         /**
          * @return true if the target package has declared an overlayable
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 8b69946..f1947ac 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -1073,8 +1073,6 @@
             mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
         }
 
-        // TODO(b/143096091): Remove PackageInfo cache so that PackageManager is always queried
-        //  to enforce visibility/other permission checks
         public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId,
                 final boolean useCache) {
             if (useCache) {
@@ -1097,18 +1095,12 @@
 
         @Override
         public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId) {
-            // TODO(b/143096091): Remove clearing calling ID
-            long callingIdentity = Binder.clearCallingIdentity();
-            try {
-                return getPackageInfo(packageName, userId, true);
-            } finally {
-                Binder.restoreCallingIdentity(callingIdentity);
-            }
+            return getPackageInfo(packageName, userId, true);
         }
 
         @NonNull
         @Override
-        public Map<String, ? extends Map<String, String>> getNamedActors() {
+        public Map<String, Map<String, String>> getNamedActors() {
             return SystemConfig.getInstance().getNamedActors();
         }
 
@@ -1136,57 +1128,45 @@
         public OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
                 @Nullable String targetOverlayableName, int userId)
                 throws IOException {
-            // TODO(b/143096091): Remove clearing calling ID
-            long callingIdentity = Binder.clearCallingIdentity();
+            PackageInfo packageInfo = getPackageInfo(packageName, userId);
+            if (packageInfo == null) {
+                throw new IOException("Unable to get target package");
+            }
+
+            String baseCodePath = packageInfo.applicationInfo.getBaseCodePath();
+
+            ApkAssets apkAssets = null;
             try {
-                PackageInfo packageInfo = getPackageInfo(packageName, userId);
-                if (packageInfo == null) {
-                    throw new IOException("Unable to get target package");
-                }
-
-                String baseCodePath = packageInfo.applicationInfo.getBaseCodePath();
-
-                ApkAssets apkAssets = null;
-                try {
-                    apkAssets = ApkAssets.loadFromPath(baseCodePath);
-                    return apkAssets.getOverlayableInfo(targetOverlayableName);
-                } finally {
-                    if (apkAssets != null) {
-                        try {
-                            apkAssets.close();
-                        } catch (Throwable ignored) {
-                        }
+                apkAssets = ApkAssets.loadFromPath(baseCodePath);
+                return apkAssets.getOverlayableInfo(targetOverlayableName);
+            } finally {
+                if (apkAssets != null) {
+                    try {
+                        apkAssets.close();
+                    } catch (Throwable ignored) {
                     }
                 }
-            } finally {
-                Binder.restoreCallingIdentity(callingIdentity);
             }
         }
 
         @Override
         public boolean doesTargetDefineOverlayable(String targetPackageName, int userId)
                 throws RemoteException, IOException {
-            // TODO(b/143096091): Remove clearing calling ID
-            long callingIdentity = Binder.clearCallingIdentity();
-            try {
-                PackageInfo packageInfo = mPackageManager.getPackageInfo(targetPackageName, 0,
-                        userId);
-                String baseCodePath = packageInfo.applicationInfo.getBaseCodePath();
+            PackageInfo packageInfo = mPackageManager.getPackageInfo(targetPackageName, 0,
+                    userId);
+            String baseCodePath = packageInfo.applicationInfo.getBaseCodePath();
 
-                ApkAssets apkAssets = null;
-                try {
-                    apkAssets = ApkAssets.loadFromPath(baseCodePath);
-                    return apkAssets.definesOverlayable();
-                } finally {
-                    if (apkAssets != null) {
-                        try {
-                            apkAssets.close();
-                        } catch (Throwable ignored) {
-                        }
+            ApkAssets apkAssets = null;
+            try {
+                apkAssets = ApkAssets.loadFromPath(baseCodePath);
+                return apkAssets.definesOverlayable();
+            } finally {
+                if (apkAssets != null) {
+                    try {
+                        apkAssets.close();
+                    } catch (Throwable ignored) {
                     }
                 }
-            } finally {
-                Binder.restoreCallingIdentity(callingIdentity);
             }
         }
 
@@ -1229,16 +1209,10 @@
         @Nullable
         @Override
         public String[] getPackagesForUid(int uid) {
-            // TODO(b/143096091): Remove clearing calling ID
-            long callingIdentity = Binder.clearCallingIdentity();
             try {
-                try {
-                    return mPackageManager.getPackagesForUid(uid);
-                } catch (RemoteException ignored) {
-                    return null;
-                }
-            } finally {
-                Binder.restoreCallingIdentity(callingIdentity);
+                return mPackageManager.getPackagesForUid(uid);
+            } catch (RemoteException ignored) {
+                return null;
             }
         }
 
diff --git a/services/core/java/com/android/server/om/OverlayReferenceMapper.java b/services/core/java/com/android/server/om/OverlayReferenceMapper.java
new file mode 100644
index 0000000..8bea119
--- /dev/null
+++ b/services/core/java/com/android/server/om/OverlayReferenceMapper.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2019 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.om;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.parsing.AndroidPackage;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Pair;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.CollectionUtils;
+import com.android.server.SystemConfig;
+import com.android.server.pm.PackageSetting;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Track visibility of a targets and overlays to actors.
+ *
+ * 4 cases to handle:
+ * <ol>
+ *     <li>Target adds/changes an overlayable to add a reference to an actor
+ *         <ul>
+ *             <li>Must expose target to actor</li>
+ *             <li>Must expose any overlays that pointed to that overlayable name to the actor</li>
+ *         </ul>
+ *     </li>
+ *     <li>Target removes/changes an overlayable to remove a reference to an actor
+ *         <ul>
+ *             <li>If this target has no other overlayables referencing the actor, hide the
+ *             target</li>
+ *             <li>For all overlays targeting this overlayable, if the overlay is only visible to
+ *             the actor through this overlayable, hide the overlay</li>
+ *         </ul>
+ *     </li>
+ *     <li>Overlay adds/changes an overlay tag to add a reference to an overlayable name
+ *         <ul>
+ *             <li>Expose this overlay to the actor defined by the target overlayable</li>
+ *         </ul>
+ *     </li>
+ *     <li>Overlay removes/changes an overlay tag to remove a reference to an overlayable name
+ *         <ul>
+ *             <li>If this overlay is only visible to an actor through this overlayable name's
+ *             target's actor</li>
+ *         </ul>
+ *     </li>
+ * </ol>
+ *
+ * In this class, the names "actor", "target", and "overlay" all refer to the ID representations.
+ * All other use cases are named appropriate. "actor" is actor name, "target" is target package
+ * name, and "overlay" is overlay package name.
+ */
+public class OverlayReferenceMapper {
+
+    private final Object mLock = new Object();
+
+    /**
+     * Keys are actors, values are maps which map target to a set of overlays targeting it.
+     * The presence of a target in the value map means the actor and targets are connected, even
+     * if the corresponding target's set is empty.
+     * See class comment for specific types.
+     */
+    @GuardedBy("mLock")
+    private final Map<String, Map<String, Set<String>>> mActorToTargetToOverlays = new HashMap<>();
+
+    /**
+     * Keys are actor package names, values are generic package names the actor should be able
+     * to see.
+     */
+    @GuardedBy("mLock")
+    private final Map<String, Set<String>> mActorPkgToPkgs = new HashMap<>();
+
+    @GuardedBy("mLock")
+    private boolean mDeferRebuild;
+
+    @NonNull
+    private final Provider mProvider;
+
+    /**
+     * @param deferRebuild whether or not to defer rebuild calls on add/remove until first get call;
+     *                     useful during boot when multiple packages are added in rapid succession
+     *                     and queries in-between are not expected
+     */
+    public OverlayReferenceMapper(boolean deferRebuild, @Nullable Provider provider) {
+        this.mDeferRebuild = deferRebuild;
+        this.mProvider = provider != null ? provider : new Provider() {
+            @Nullable
+            @Override
+            public String getActorPkg(String actor) {
+                Map<String, Map<String, String>> namedActors = SystemConfig.getInstance()
+                        .getNamedActors();
+
+                Pair<String, OverlayActorEnforcer.ActorState> actorPair =
+                        OverlayActorEnforcer.getPackageNameForActor(actor, namedActors);
+                return actorPair.first;
+            }
+
+            @NonNull
+            @Override
+            public Map<String, Set<String>> getTargetToOverlayables(@NonNull AndroidPackage pkg) {
+                String target = pkg.getOverlayTarget();
+                if (TextUtils.isEmpty(target)) {
+                    return Collections.emptyMap();
+                }
+
+                String overlayable = pkg.getOverlayTargetName();
+                Map<String, Set<String>> targetToOverlayables = new HashMap<>();
+                Set<String> overlayables = new HashSet<>();
+                overlayables.add(overlayable);
+                targetToOverlayables.put(target, overlayables);
+                return targetToOverlayables;
+            }
+        };
+    }
+
+    /**
+     * @return mapping of actor package to a set of packages it can view
+     */
+    @NonNull
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    public Map<String, Set<String>> getActorPkgToPkgs() {
+        return mActorPkgToPkgs;
+    }
+
+    public boolean isValidActor(@NonNull String targetName, @NonNull String actorPackageName) {
+        synchronized (mLock) {
+            assertMapBuilt();
+            Set<String> validSet = mActorPkgToPkgs.get(actorPackageName);
+            return validSet != null && validSet.contains(targetName);
+        }
+    }
+
+    /**
+     * Add a package to be considered for visibility. Currently supports adding as a target and/or
+     * an overlay. Adding an actor is not supported. Those are configured as part of
+     * {@link SystemConfig#getNamedActors()}.
+     *
+     * @param pkg the package to add
+     * @param otherPkgs map of other packages to consider, excluding {@param pkg}
+     */
+    public void addPkg(AndroidPackage pkg, Map<String, AndroidPackage> otherPkgs) {
+        synchronized (mLock) {
+            if (!pkg.getOverlayables().isEmpty()) {
+                addTarget(pkg, otherPkgs);
+            }
+
+            // TODO(b/135203078): Replace with isOverlay boolean flag check; fix test mocks
+            if (!mProvider.getTargetToOverlayables(pkg).isEmpty()) {
+                addOverlay(pkg, otherPkgs);
+            }
+
+            if (!mDeferRebuild) {
+                rebuild();
+            }
+        }
+    }
+
+    /**
+     * Removes a package to be considered for visibility. Currently supports removing as a target
+     * and/or an overlay. Removing an actor is not supported. Those are staticly configured as part
+     * of {@link SystemConfig#getNamedActors()}.
+     *
+     * @param pkgName name to remove, as was added through {@link #addPkg(AndroidPackage, Map)}
+     */
+    public void removePkg(String pkgName) {
+        synchronized (mLock) {
+            removeTarget(pkgName);
+            removeOverlay(pkgName);
+
+            if (!mDeferRebuild) {
+                rebuild();
+            }
+        }
+    }
+
+    private void removeTarget(String target) {
+        synchronized (mLock) {
+            Iterator<Map<String, Set<String>>> iterator =
+                    mActorToTargetToOverlays.values().iterator();
+            while (iterator.hasNext()) {
+                Map<String, Set<String>> next = iterator.next();
+                next.remove(target);
+                if (next.isEmpty()) {
+                    iterator.remove();
+                }
+            }
+        }
+    }
+
+    /**
+     * Associate an actor with an association of a new target to overlays for that target.
+     *
+     * If a target overlays itself, it will not be associated with itself, as only one half of the
+     * relationship needs to exist for visibility purposes.
+     */
+    private void addTarget(AndroidPackage targetPkg, Map<String, AndroidPackage> otherPkgs) {
+        synchronized (mLock) {
+            String target = targetPkg.getPackageName();
+            removeTarget(target);
+
+            Map<String, String> overlayablesToActors = targetPkg.getOverlayables();
+            for (String overlayable : overlayablesToActors.keySet()) {
+                String actor = overlayablesToActors.get(overlayable);
+                addTargetToMap(actor, target);
+
+                for (AndroidPackage overlayPkg : otherPkgs.values()) {
+                    Map<String, Set<String>> targetToOverlayables =
+                            mProvider.getTargetToOverlayables(overlayPkg);
+                    Set<String> overlayables = targetToOverlayables.get(target);
+                    if (CollectionUtils.isEmpty(overlayables)) {
+                        continue;
+                    }
+
+                    if (overlayables.contains(overlayable)) {
+                        addOverlayToMap(actor, target, overlayPkg.getPackageName());
+                    }
+                }
+            }
+        }
+    }
+
+    private void removeOverlay(String overlay) {
+        synchronized (mLock) {
+            for (Map<String, Set<String>> targetToOverlays : mActorToTargetToOverlays.values()) {
+                for (Set<String> overlays : targetToOverlays.values()) {
+                    overlays.remove(overlay);
+                }
+            }
+        }
+    }
+
+    /**
+     * Associate an actor with an association of targets to overlays for a new overlay.
+     *
+     * If an overlay targets itself, it will not be associated with itself, as only one half of the
+     * relationship needs to exist for visibility purposes.
+     */
+    private void addOverlay(AndroidPackage overlayPkg, Map<String, AndroidPackage> otherPkgs) {
+        synchronized (mLock) {
+            String overlay = overlayPkg.getPackageName();
+            removeOverlay(overlay);
+
+            Map<String, Set<String>> targetToOverlayables =
+                    mProvider.getTargetToOverlayables(overlayPkg);
+            for (Map.Entry<String, Set<String>> entry : targetToOverlayables.entrySet()) {
+                String target = entry.getKey();
+                Set<String> overlayables = entry.getValue();
+                AndroidPackage targetPkg = otherPkgs.get(target);
+                if (targetPkg == null) {
+                    continue;
+                }
+
+                String targetPkgName = targetPkg.getPackageName();
+                Map<String, String> overlayableToActor = targetPkg.getOverlayables();
+                for (String overlayable : overlayables) {
+                    String actor = overlayableToActor.get(overlayable);
+                    if (TextUtils.isEmpty(actor)) {
+                        continue;
+                    }
+                    addOverlayToMap(actor, targetPkgName, overlay);
+                }
+            }
+        }
+    }
+
+    public void rebuildIfDeferred() {
+        synchronized (mLock) {
+            if (mDeferRebuild) {
+                rebuild();
+                mDeferRebuild = false;
+            }
+        }
+    }
+
+    private void assertMapBuilt() {
+        if (mDeferRebuild) {
+            throw new IllegalStateException("The actor map must be built by calling "
+                    + "rebuildIfDeferred before it is queried");
+        }
+    }
+
+    private void rebuild() {
+        synchronized (mLock) {
+            mActorPkgToPkgs.clear();
+            for (String actor : mActorToTargetToOverlays.keySet()) {
+                String actorPkg = mProvider.getActorPkg(actor);
+                if (TextUtils.isEmpty(actorPkg)) {
+                    continue;
+                }
+
+                Map<String, Set<String>> targetToOverlays = mActorToTargetToOverlays.get(actor);
+                Set<String> pkgs = new HashSet<>();
+
+                for (String target : targetToOverlays.keySet()) {
+                    Set<String> overlays = targetToOverlays.get(target);
+                    pkgs.add(target);
+                    pkgs.addAll(overlays);
+                }
+
+                mActorPkgToPkgs.put(actorPkg, pkgs);
+            }
+        }
+    }
+
+    private void addTargetToMap(String actor, String target) {
+        Map<String, Set<String>> targetToOverlays = mActorToTargetToOverlays.get(actor);
+        if (targetToOverlays == null) {
+            targetToOverlays = new HashMap<>();
+            mActorToTargetToOverlays.put(actor, targetToOverlays);
+        }
+
+        Set<String> overlays = targetToOverlays.get(target);
+        if (overlays == null) {
+            overlays = new HashSet<>();
+            targetToOverlays.put(target, overlays);
+        }
+    }
+
+    private void addOverlayToMap(String actor, String target, String overlay) {
+        synchronized (mLock) {
+            Map<String, Set<String>> targetToOverlays = mActorToTargetToOverlays.get(actor);
+            if (targetToOverlays == null) {
+                targetToOverlays = new HashMap<>();
+                mActorToTargetToOverlays.put(actor, targetToOverlays);
+            }
+
+            Set<String> overlays = targetToOverlays.get(target);
+            if (overlays == null) {
+                overlays = new HashSet<>();
+                targetToOverlays.put(target, overlays);
+            }
+
+            overlays.add(overlay);
+        }
+    }
+
+    public interface Provider {
+
+        /**
+         * Given the actor string from an overlayable definition, return the actor's package name.
+         */
+        @Nullable
+        String getActorPkg(String actor);
+
+        /**
+         * Mock response of multiple overlay tags.
+         *
+         * TODO(b/119899133): Replace with actual implementation; fix OverlayReferenceMapperTests
+         */
+        @NonNull
+        Map<String, Set<String>> getTargetToOverlayables(@NonNull AndroidPackage pkg);
+    }
+}
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 8374ee6..c4bcf80 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -16,8 +16,6 @@
 
 package com.android.server.pm;
 
-import static android.content.pm.PackageParser.Component;
-import static android.content.pm.PackageParser.IntentInfo;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE;
 
@@ -26,7 +24,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
 import android.content.pm.parsing.AndroidPackage;
 import android.content.pm.parsing.ComponentParseUtils;
 import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
@@ -50,9 +47,9 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.FgThread;
+import com.android.server.om.OverlayReferenceMapper;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
@@ -109,11 +106,16 @@
 
     private final FeatureConfig mFeatureConfig;
 
+    private final OverlayReferenceMapper mOverlayReferenceMapper;
+
     AppsFilter(FeatureConfig featureConfig, String[] forceQueryableWhitelist,
-            boolean systemAppsQueryable) {
+            boolean systemAppsQueryable,
+            @Nullable OverlayReferenceMapper.Provider overlayProvider) {
         mFeatureConfig = featureConfig;
         mForceQueryableByDevicePackageNames = forceQueryableWhitelist;
         mSystemAppsQueryable = systemAppsQueryable;
+        mOverlayReferenceMapper = new OverlayReferenceMapper(true /*deferRebuild*/,
+                overlayProvider);
     }
 
     public interface FeatureConfig {
@@ -193,7 +195,7 @@
             }
         }
         return new AppsFilter(featureConfig, forcedQueryablePackageNames,
-                forceSystemAppsQueryable);
+                forceSystemAppsQueryable, null);
     }
 
     /** Returns true if the querying package may query for the potential target package */
@@ -282,6 +284,7 @@
 
     public void onSystemReady() {
         mFeatureConfig.onSystemReady();
+        mOverlayReferenceMapper.rebuildIfDeferred();
     }
 
     /**
@@ -338,6 +341,16 @@
                     }
                 }
             }
+
+            int existingSize = existingSettings.size();
+            ArrayMap<String, AndroidPackage> existingPkgs = new ArrayMap<>(existingSize);
+            for (int index = 0; index < existingSize; index++) {
+                PackageSetting pkgSetting = existingSettings.valueAt(index);
+                if (pkgSetting.pkg != null) {
+                    existingPkgs.put(pkgSetting.name, pkgSetting.pkg);
+                }
+            }
+            mOverlayReferenceMapper.addPkg(newPkgSetting.pkg, existingPkgs);
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
@@ -381,6 +394,8 @@
                 addPackage(setting.sharedUser.packages.valueAt(i), existingSettings);
             }
         }
+
+        mOverlayReferenceMapper.removePkg(setting.name);
     }
 
     /**
@@ -397,8 +412,7 @@
             PackageSetting targetPkgSetting, int userId) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplication");
         try {
-            if (!shouldFilterApplicationInternal(callingUid, callingSetting,
-                    targetPkgSetting,
+            if (!shouldFilterApplicationInternal(callingUid, callingSetting, targetPkgSetting,
                     userId)) {
                 return false;
             }
@@ -412,8 +426,8 @@
         }
     }
 
-    private boolean shouldFilterApplicationInternal(int callingUid,
-            SettingBase callingSetting, PackageSetting targetPkgSetting, int userId) {
+    private boolean shouldFilterApplicationInternal(int callingUid, SettingBase callingSetting,
+            PackageSetting targetPkgSetting, int userId) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplicationInternal");
         try {
             final boolean featureEnabled = mFeatureConfig.isGloballyEnabled();
@@ -530,6 +544,29 @@
                     }
                 }
             }
+
+            if (callingSharedPkgSettings != null) {
+                int size = callingSharedPkgSettings.size();
+                for (int index = 0; index < size; index++) {
+                    PackageSetting pkgSetting = callingSharedPkgSettings.valueAt(index);
+                    if (mOverlayReferenceMapper.isValidActor(targetName, pkgSetting.name)) {
+                        if (DEBUG_LOGGING) {
+                            log(callingPkgSetting, targetPkgSetting,
+                                    "matches shared user of package that acts on target of "
+                                            + "overlay");
+                        }
+                        return false;
+                    }
+                }
+            } else {
+                if (mOverlayReferenceMapper.isValidActor(targetName, callingPkgSetting.name)) {
+                    if (DEBUG_LOGGING) {
+                        log(callingPkgSetting, targetPkgSetting, "acts on target of overlay");
+                    }
+                    return false;
+                }
+            }
+
             return true;
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
diff --git a/services/core/java/com/android/server/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java
index 30b2c9d..8333ae5 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolver.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolver.java
@@ -39,6 +39,7 @@
 import android.content.pm.AuxiliaryResolveInfo;
 import android.content.pm.InstantAppIntentFilter;
 import android.content.pm.InstantAppRequest;
+import android.content.pm.InstantAppRequestInfo;
 import android.content.pm.InstantAppResolveInfo;
 import android.content.pm.InstantAppResolveInfo.InstantAppDigest;
 import android.metrics.LogMaker;
@@ -47,6 +48,8 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.RemoteException;
+import android.os.UserHandle;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.Slog;
 
@@ -63,7 +66,6 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
-import java.util.UUID;
 
 /** @hide */
 public abstract class InstantAppResolver {
@@ -117,26 +119,40 @@
         return sanitizedIntent;
     }
 
+    /**
+     * Generate an {@link InstantAppDigest} from an {@link Intent} which contains hashes of the
+     * host. The object contains both secure and insecure hash array variants, and the secure
+     * version must be passed along to ensure the random data is consistent.
+     */
+    @NonNull
+    public static InstantAppDigest parseDigest(@NonNull Intent origIntent) {
+        if (origIntent.getData() != null && !TextUtils.isEmpty(origIntent.getData().getHost())) {
+            return new InstantAppResolveInfo.InstantAppDigest(origIntent.getData().getHost(),
+                    5 /*maxDigests*/);
+        } else {
+            return InstantAppResolveInfo.InstantAppDigest.UNDEFINED;
+        }
+    }
+
     public static AuxiliaryResolveInfo doInstantAppResolutionPhaseOne(
             InstantAppResolverConnection connection, InstantAppRequest requestObj) {
         final long startTime = System.currentTimeMillis();
-        final String token = UUID.randomUUID().toString();
+        final String token = requestObj.token;
         if (DEBUG_INSTANT) {
             Log.d(TAG, "[" + token + "] Phase1; resolving");
         }
-        final Intent origIntent = requestObj.origIntent;
-        final Intent sanitizedIntent = sanitizeIntent(origIntent);
 
         AuxiliaryResolveInfo resolveInfo = null;
         @ResolutionStatus int resolutionStatus = RESOLUTION_SUCCESS;
+        Intent origIntent = requestObj.origIntent;
         try {
             final List<InstantAppResolveInfo> instantAppResolveInfoList =
-                    connection.getInstantAppResolveInfoList(sanitizedIntent,
-                            requestObj.digest.getDigestPrefixSecure(), requestObj.userId, token);
+                    connection.getInstantAppResolveInfoList(buildRequestInfo(requestObj));
             if (instantAppResolveInfoList != null && instantAppResolveInfoList.size() > 0) {
                 resolveInfo = InstantAppResolver.filterInstantAppIntent(
                         instantAppResolveInfoList, origIntent, requestObj.resolvedType,
-                        requestObj.userId, origIntent.getPackage(), requestObj.digest, token);
+                        requestObj.userId, origIntent.getPackage(), token,
+                        requestObj.hostDigestPrefixSecure);
             }
         } catch (ConnectionException e) {
             if (e.failure == ConnectionException.FAILURE_BIND) {
@@ -166,7 +182,7 @@
         // if the match external flag is set, return an empty resolve info instead of a null result.
         if (resolveInfo == null && (origIntent.getFlags() & FLAG_ACTIVITY_MATCH_EXTERNAL) != 0) {
             return new AuxiliaryResolveInfo(token, false, createFailureIntent(origIntent, token),
-                    null /* filters */);
+                    null /* filters */, requestObj.hostDigestPrefixSecure);
         }
         return resolveInfo;
     }
@@ -175,7 +191,7 @@
             InstantAppResolverConnection connection, InstantAppRequest requestObj,
             ActivityInfo instantAppInstaller, Handler callbackHandler) {
         final long startTime = System.currentTimeMillis();
-        final String token = requestObj.responseObj.token;
+        final String token = requestObj.token;
         if (DEBUG_INSTANT) {
             Log.d(TAG, "[" + token + "] Phase2; resolving");
         }
@@ -191,8 +207,8 @@
                     final AuxiliaryResolveInfo instantAppIntentInfo =
                             InstantAppResolver.filterInstantAppIntent(
                                     instantAppResolveInfoList, origIntent, null /*resolvedType*/,
-                                    0 /*userId*/, origIntent.getPackage(), requestObj.digest,
-                                    token);
+                                    0 /*userId*/, origIntent.getPackage(),
+                                    token, requestObj.hostDigestPrefixSecure);
                     if (instantAppIntentInfo != null) {
                         failureIntent = instantAppIntentInfo.failureIntent;
                     } else {
@@ -223,8 +239,7 @@
             }
         };
         try {
-            connection.getInstantAppIntentFilterList(sanitizedIntent,
-                    requestObj.digest.getDigestPrefixSecure(), requestObj.userId, token, callback,
+            connection.getInstantAppIntentFilterList(buildRequestInfo(requestObj), callback,
                     callbackHandler, startTime);
         } catch (ConnectionException e) {
             @ResolutionStatus int resolutionStatus = RESOLUTION_FAILURE;
@@ -356,10 +371,22 @@
         return intent;
     }
 
+    private static InstantAppRequestInfo buildRequestInfo(InstantAppRequest request) {
+        return new InstantAppRequestInfo(
+                sanitizeIntent(request.origIntent),
+                // This must only expose the secured version of the host
+                request.hostDigestPrefixSecure,
+                UserHandle.getUserHandleForUid(request.userId),
+                request.isRequesterInstantApp,
+                request.token
+        );
+    }
+
     private static AuxiliaryResolveInfo filterInstantAppIntent(
-            List<InstantAppResolveInfo> instantAppResolveInfoList,
-            Intent origIntent, String resolvedType, int userId, String packageName,
-            InstantAppDigest digest, String token) {
+            List<InstantAppResolveInfo> instantAppResolveInfoList, Intent origIntent,
+            String resolvedType, int userId, String packageName, String token,
+            int[] hostDigestPrefixSecure) {
+        InstantAppDigest digest = InstantAppResolver.parseDigest(origIntent);
         final int[] shaPrefix = digest.getDigestPrefix();
         final byte[][] digestBytes = digest.getDigestBytes();
         boolean requiresSecondPhase = false;
@@ -404,7 +431,7 @@
         }
         if (filters != null && !filters.isEmpty()) {
             return new AuxiliaryResolveInfo(token, requiresSecondPhase,
-                    createFailureIntent(origIntent, token), filters);
+                    createFailureIntent(origIntent, token), filters, hostDigestPrefixSecure);
         }
         // Hash or filter mis-match; no instant apps for this domain.
         return null;
diff --git a/services/core/java/com/android/server/pm/InstantAppResolverConnection.java b/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
index c0e9f58..0fe2eb1 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.content.pm.InstantAppRequestInfo;
 import android.content.pm.InstantAppResolveInfo;
 import android.os.Binder;
 import android.os.Build;
@@ -85,13 +86,13 @@
         mBgHandler = BackgroundThread.getHandler();
     }
 
-    public List<InstantAppResolveInfo> getInstantAppResolveInfoList(Intent sanitizedIntent,
-            int[] hashPrefix, int userId, String token) throws ConnectionException {
+    public List<InstantAppResolveInfo> getInstantAppResolveInfoList(InstantAppRequestInfo request)
+            throws ConnectionException {
         throwIfCalledOnMainThread();
         IInstantAppResolver target = null;
         try {
             try {
-                target = getRemoteInstanceLazy(token);
+                target = getRemoteInstanceLazy(request.token);
             } catch (TimeoutException e) {
                 throw new ConnectionException(ConnectionException.FAILURE_BIND);
             } catch (InterruptedException e) {
@@ -99,8 +100,7 @@
             }
             try {
                 return mGetInstantAppResolveInfoCaller
-                        .getInstantAppResolveInfoList(target, sanitizedIntent, hashPrefix, userId,
-                                token);
+                        .getInstantAppResolveInfoList(target, request);
             } catch (TimeoutException e) {
                 throw new ConnectionException(ConnectionException.FAILURE_CALL);
             } catch (RemoteException ignore) {
@@ -113,8 +113,8 @@
         return null;
     }
 
-    public void getInstantAppIntentFilterList(Intent sanitizedIntent, int[] hashPrefix, int userId,
-            String token, PhaseTwoCallback callback, Handler callbackHandler, final long startTime)
+    public void getInstantAppIntentFilterList(InstantAppRequestInfo request,
+            PhaseTwoCallback callback, Handler callbackHandler, final long startTime)
             throws ConnectionException {
         final IRemoteCallback remoteCallback = new IRemoteCallback.Stub() {
             @Override
@@ -126,9 +126,8 @@
             }
         };
         try {
-            getRemoteInstanceLazy(token)
-                    .getInstantAppIntentFilterList(sanitizedIntent, hashPrefix, userId, token,
-                            remoteCallback);
+            getRemoteInstanceLazy(request.token)
+                    .getInstantAppIntentFilterList(request, remoteCallback);
         } catch (TimeoutException e) {
             throw new ConnectionException(ConnectionException.FAILURE_BIND);
         } catch (InterruptedException e) {
@@ -352,12 +351,10 @@
             };
         }
 
-        public List<InstantAppResolveInfo> getInstantAppResolveInfoList(
-                IInstantAppResolver target, Intent sanitizedIntent, int[] hashPrefix, int userId,
-                String token) throws RemoteException, TimeoutException {
+        public List<InstantAppResolveInfo> getInstantAppResolveInfoList(IInstantAppResolver target,
+                InstantAppRequestInfo request) throws RemoteException, TimeoutException {
             final int sequence = onBeforeRemoteCall();
-            target.getInstantAppResolveInfoList(sanitizedIntent, hashPrefix, userId, token,
-                    sequence, mCallback);
+            target.getInstantAppResolveInfoList(request, sequence, mCallback);
             return getResultTimed(sequence);
         }
     }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2d7bcd0..1153fb5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -155,6 +155,7 @@
 import android.content.pm.InstallSourceInfo;
 import android.content.pm.InstantAppInfo;
 import android.content.pm.InstantAppRequest;
+import android.content.pm.InstantAppResolveInfo.InstantAppDigest;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.KeySet;
@@ -376,6 +377,7 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.UUID;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
@@ -6143,10 +6145,12 @@
 
     private void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
             Intent origIntent, String resolvedType, String callingPackage,
-            Bundle verificationBundle, int userId) {
+            boolean isRequesterInstantApp, Bundle verificationBundle, int userId) {
         final Message msg = mHandler.obtainMessage(INSTANT_APP_RESOLUTION_PHASE_TWO,
                 new InstantAppRequest(responseObj, origIntent, resolvedType,
-                        callingPackage, userId, verificationBundle, false /*resolveForStart*/));
+                        callingPackage, isRequesterInstantApp, userId, verificationBundle,
+                        false /*resolveForStart*/, responseObj.hostDigestPrefixSecure,
+                        responseObj.token));
         mHandler.sendMessage(msg);
     }
 
@@ -6765,8 +6769,10 @@
             }
         }
         if (addInstant) {
-            result = maybeAddInstantAppInstaller(
-                    result, intent, resolvedType, flags, userId, resolveForStart);
+            String callingPkgName = getInstantAppPackageName(filterCallingUid);
+            boolean isRequesterInstantApp = isInstantApp(callingPkgName, userId);
+            result = maybeAddInstantAppInstaller(result, intent, resolvedType, flags, userId,
+                    resolveForStart, isRequesterInstantApp);
         }
         if (sortResult) {
             Collections.sort(result, RESOLVE_PRIORITY_SORTER);
@@ -6777,7 +6783,8 @@
     }
 
     private List<ResolveInfo> maybeAddInstantAppInstaller(List<ResolveInfo> result, Intent intent,
-            String resolvedType, int flags, int userId, boolean resolveForStart) {
+            String resolvedType, int flags, int userId, boolean resolveForStart,
+            boolean isRequesterInstantApp) {
         // first, check to see if we've got an instant app already installed
         final boolean alreadyResolvedLocally = (flags & PackageManager.MATCH_INSTANT) != 0;
         ResolveInfo localInstantApp = null;
@@ -6825,10 +6832,13 @@
             if (localInstantApp == null) {
                 // we don't have an instant app locally, resolve externally
                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
+                String token = UUID.randomUUID().toString();
+                InstantAppDigest digest = InstantAppResolver.parseDigest(intent);
                 final InstantAppRequest requestObject = new InstantAppRequest(
                         null /*responseObj*/, intent /*origIntent*/, resolvedType,
-                        null /*callingPackage*/, userId, null /*verificationBundle*/,
-                        resolveForStart);
+                        null /*callingPackage*/, isRequesterInstantApp,
+                        userId, null /*verificationBundle*/, resolveForStart,
+                        digest.getDigestPrefixSecure(), token);
                 auxiliaryResponse = InstantAppResolver.doInstantAppResolutionPhaseOne(
                         mInstantAppResolverConnection, requestObject);
                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -22833,10 +22843,10 @@
         @Override
         public void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
                 Intent origIntent, String resolvedType, String callingPackage,
-                Bundle verificationBundle, int userId) {
+                boolean isRequesterInstantApp, Bundle verificationBundle, int userId) {
             PackageManagerService.this.requestInstantAppResolutionPhaseTwo(
-                    responseObj, origIntent, resolvedType, callingPackage, verificationBundle,
-                    userId);
+                    responseObj, origIntent, resolvedType, callingPackage, isRequesterInstantApp,
+                    verificationBundle, userId);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index e8798ff..59a5804 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -24,7 +24,20 @@
       ]
     },
     {
-      "name": "PackageManagerShellCommandTest"
+      "name": "CtsContentTestCases",
+      "options": [
+        {
+          "include-filter": "android.content.pm.cts.PackageManagerShellCommandTest"
+        }
+      ]
+    },
+    {
+      "name": "GtsSecurityHostTestCases",
+      "options": [
+        {
+          "include-filter": "com.google.android.security.gts.PackageVerifierTest"
+        }
+      ]
     }
   ],
   "postsubmit": [
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 4d436c0..5fabdb6 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -351,6 +351,7 @@
      * User restrictions set by {@link com.android.server.devicepolicy.DevicePolicyManagerService}
      * that should be applied to all users, including guests. Only non-empty restriction bundles are
      * stored.
+     * The key is the user id of the user whom the restriction originated from.
      */
     @GuardedBy("mRestrictionsLock")
     private final SparseArray<Bundle> mDevicePolicyGlobalUserRestrictions = new SparseArray<>();
@@ -364,6 +365,7 @@
     /**
      * User restrictions set by {@link com.android.server.devicepolicy.DevicePolicyManagerService}
      * for each user. Only non-empty restriction bundles are stored.
+     * The key is the user id of the user whom the restriction originated from.
      */
     @GuardedBy("mRestrictionsLock")
     private final SparseArray<Bundle> mDevicePolicyLocalUserRestrictions = new SparseArray<>();
@@ -1621,7 +1623,7 @@
     /**
      * See {@link UserManagerInternal#setDevicePolicyUserRestrictions}
      */
-    private void setDevicePolicyUserRestrictionsInner(@UserIdInt int userId,
+    private void setDevicePolicyUserRestrictionsInner(@UserIdInt int originatingUserId,
             @Nullable Bundle restrictions,
             @UserManagerInternal.OwnerType int restrictionOwnerType) {
         final Bundle global = new Bundle();
@@ -1635,16 +1637,16 @@
         synchronized (mRestrictionsLock) {
             // Update global and local restrictions if they were changed.
             globalChanged = updateRestrictionsIfNeededLR(
-                    userId, global, mDevicePolicyGlobalUserRestrictions);
+                    originatingUserId, global, mDevicePolicyGlobalUserRestrictions);
             localChanged = updateRestrictionsIfNeededLR(
-                    userId, local, mDevicePolicyLocalUserRestrictions);
+                    originatingUserId, local, mDevicePolicyLocalUserRestrictions);
 
             if (restrictionOwnerType == UserManagerInternal.OWNER_TYPE_DEVICE_OWNER) {
                 // Remember the global restriction owner userId to be able to make a distinction
                 // in getUserRestrictionSource on who set local policies.
-                mDeviceOwnerUserId = userId;
+                mDeviceOwnerUserId = originatingUserId;
             } else {
-                if (mDeviceOwnerUserId == userId) {
+                if (mDeviceOwnerUserId == originatingUserId) {
                     // When profile owner sets restrictions it passes null global bundle and we
                     // reset global restriction owner userId.
                     // This means this user used to have DO, but now the DO is gone and the user
@@ -1654,15 +1656,16 @@
             }
         }
         if (DBG) {
-            Log.d(LOG_TAG, "setDevicePolicyUserRestrictions: userId=" + userId
-                            + " global=" + global + (globalChanged ? " (changed)" : "")
-                            + " local=" + local + (localChanged ? " (changed)" : "")
+            Log.d(LOG_TAG, "setDevicePolicyUserRestrictions: "
+                    + " originatingUserId=" + originatingUserId
+                    + " global=" + global + (globalChanged ? " (changed)" : "")
+                    + " local=" + local + (localChanged ? " (changed)" : "")
             );
         }
         // Don't call them within the mRestrictionsLock.
         synchronized (mPackagesLock) {
             if (localChanged || globalChanged) {
-                writeUserLP(getUserDataNoChecks(userId));
+                writeUserLP(getUserDataNoChecks(originatingUserId));
             }
         }
 
@@ -1670,7 +1673,7 @@
             if (globalChanged) {
                 applyUserRestrictionsForAllUsersLR();
             } else if (localChanged) {
-                applyUserRestrictionsLR(userId);
+                applyUserRestrictionsLR(originatingUserId);
             }
         }
     }
@@ -4507,9 +4510,10 @@
 
     private class LocalService extends UserManagerInternal {
         @Override
-        public void setDevicePolicyUserRestrictions(@UserIdInt int userId,
-                @Nullable Bundle restrictions, @OwnerType int restrictionOwnerType) {
-            UserManagerService.this.setDevicePolicyUserRestrictionsInner(userId,
+        public void setDevicePolicyUserRestrictions(@UserIdInt int originatingUserId,
+                @Nullable Bundle restrictions,
+                @OwnerType int restrictionOwnerType) {
+            UserManagerService.this.setDevicePolicyUserRestrictionsInner(originatingUserId,
                     restrictions, restrictionOwnerType);
         }
 
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 0beff7a..e0bd0b4 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -411,6 +411,13 @@
     }
 
     /**
+     * @return true if a restriction is settable by profile owner of an organization owned device.
+     */
+    public static boolean canProfileOwnerOfOrganizationOwnedDeviceChange(String restriction) {
+        return PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS.contains(restriction);
+    }
+
+    /**
      * Returns the user restrictions that default to {@code true} for device owners.
      * These user restrictions are local, though. ie only for the device owner's user id.
      */
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 23083c9..674955e 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -98,6 +98,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.AuxiliaryResolveInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
@@ -1309,9 +1310,11 @@
             String resolvedType, int userId) {
         if (auxiliaryResponse != null && auxiliaryResponse.needsPhaseTwo) {
             // request phase two resolution
-            mService.getPackageManagerInternalLocked().requestInstantAppResolutionPhaseTwo(
+            PackageManagerInternal packageManager = mService.getPackageManagerInternalLocked();
+            boolean isRequesterInstantApp = packageManager.isInstantApp(callingPackage, userId);
+            packageManager.requestInstantAppResolutionPhaseTwo(
                     auxiliaryResponse, originalIntent, resolvedType, callingPackage,
-                    verificationBundle, userId);
+                    isRequesterInstantApp, verificationBundle, userId);
         }
         return InstantAppResolver.buildEphemeralInstallerIntent(
                 originalIntent,
diff --git a/services/core/jni/com_android_server_security_VerityUtils.cpp b/services/core/jni/com_android_server_security_VerityUtils.cpp
index 906b568..be11b86 100644
--- a/services/core/jni/com_android_server_security_VerityUtils.cpp
+++ b/services/core/jni/com_android_server_security_VerityUtils.cpp
@@ -24,6 +24,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <linux/fsverity.h>
 #include <string.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
@@ -33,40 +34,6 @@
 
 #include <android-base/unique_fd.h>
 
-// TODO(112037636): Always include once fsverity.h is upstreamed.
-#if __has_include(<linux/fsverity.h>)
-#include <linux/fsverity.h>
-#else
-
-#include <linux/limits.h>
-#include <linux/ioctl.h>
-#include <linux/types.h>
-
-#define FS_VERITY_HASH_ALG_SHA256	1
-
-struct fsverity_enable_arg {
-	__u32 version;
-	__u32 hash_algorithm;
-	__u32 block_size;
-	__u32 salt_size;
-	__u64 salt_ptr;
-	__u32 sig_size;
-	__u32 __reserved1;
-	__u64 sig_ptr;
-	__u64 __reserved2[11];
-};
-
-struct fsverity_digest {
-    __u16 digest_algorithm;
-    __u16 digest_size; /* input/output */
-    __u8 digest[];
-};
-
-#define FS_IOC_ENABLE_VERITY	_IOW('f', 133, struct fsverity_enable_arg)
-#define FS_IOC_MEASURE_VERITY	_IOWR('f', 134, struct fsverity_digest)
-
-#endif
-
 const int kSha256Bytes = 32;
 
 namespace android {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index aa7bf5b..d91ec42e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2447,7 +2447,7 @@
                 Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userId) != 0) {
             profileOwner.ensureUserRestrictions().putBoolean(
                     UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true);
-            saveUserRestrictionsLocked(userId);
+            saveUserRestrictionsLocked(userId, /* parent = */ false);
             mInjector.settingsSecurePutIntForUser(
                     Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userId);
         }
@@ -2478,7 +2478,7 @@
             }
             admin.defaultEnabledRestrictionsAlreadySet.addAll(restrictionsToSet);
             Slog.i(LOG_TAG, "Enabled the following restrictions by default: " + restrictionsToSet);
-            saveUserRestrictionsLocked(userId);
+            saveUserRestrictionsLocked(userId, /* parent = */ false);
         }
     }
 
@@ -8039,7 +8039,7 @@
                 activeAdmin.defaultEnabledRestrictionsAlreadySet.addAll(restrictions);
                 Slog.i(LOG_TAG, "Enabled the following restrictions by default: " + restrictions);
 
-                saveUserRestrictionsLocked(userId);
+                saveUserRestrictionsLocked(userId, /* parent = */ false);
             }
 
             long ident = mInjector.binderClearCallingIdentity();
@@ -10310,24 +10310,33 @@
     }
 
     @Override
-    public void setUserRestriction(ComponentName who, String key, boolean enabledFromThisOwner) {
+    public void setUserRestriction(ComponentName who, String key, boolean enabledFromThisOwner,
+            boolean parent) {
         Preconditions.checkNotNull(who, "ComponentName is null");
         if (!UserRestrictionsUtils.isValidRestriction(key)) {
             return;
         }
 
-        final int userHandle = mInjector.userHandleGetCallingUserId();
+        int userHandle = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
             final ActiveAdmin activeAdmin =
                     getActiveAdminForCallerLocked(who,
-                            DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+                            DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent);
             final boolean isDeviceOwner = isDeviceOwner(who, userHandle);
+
             if (isDeviceOwner) {
                 if (!UserRestrictionsUtils.canDeviceOwnerChange(key)) {
                     throw new SecurityException("Device owner cannot set user restriction " + key);
                 }
-            } else { // profile owner
-                if (!UserRestrictionsUtils.canProfileOwnerChange(key, userHandle)) {
+                if (parent) {
+                    throw new IllegalArgumentException(
+                            "Cannot use the parent instance in Device Owner mode");
+                }
+            } else {
+                if (!(UserRestrictionsUtils.canProfileOwnerChange(key, userHandle) || (
+                        isProfileOwnerOfOrganizationOwnedDevice(activeAdmin) && parent
+                        && UserRestrictionsUtils.canProfileOwnerOfOrganizationOwnedDeviceChange(
+                                key)))) {
                     throw new SecurityException("Profile owner cannot set user restriction " + key);
                 }
             }
@@ -10339,7 +10348,7 @@
             } else {
                 restrictions.remove(key);
             }
-            saveUserRestrictionsLocked(userHandle);
+            saveUserRestrictionsLocked(userHandle, parent);
         }
         final int eventId = enabledFromThisOwner
                 ? DevicePolicyEnums.ADD_USER_RESTRICTION
@@ -10357,9 +10366,9 @@
         }
     }
 
-    private void saveUserRestrictionsLocked(int userId) {
+    private void saveUserRestrictionsLocked(int userId, boolean parent) {
         saveSettingsLocked(userId);
-        pushUserRestrictions(userId);
+        pushUserRestrictions(parent ? getProfileParentId(userId) : userId);
         sendChangedNotification(userId);
     }
 
@@ -10368,6 +10377,7 @@
             final boolean isDeviceOwner = mOwners.isDeviceOwnerUserId(userId);
             Bundle userRestrictions = null;
             final int restrictionOwnerType;
+            final int originatingUserId;
 
             if (isDeviceOwner) {
                 final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
@@ -10377,6 +10387,7 @@
                 userRestrictions = deviceOwner.userRestrictions;
                 addOrRemoveDisableCameraRestriction(userRestrictions, deviceOwner);
                 restrictionOwnerType = UserManagerInternal.OWNER_TYPE_DEVICE_OWNER;
+                originatingUserId = deviceOwner.getUserHandle().getIdentifier();
             } else {
                 final ActiveAdmin profileOwnerOfOrganizationOwnedDevice =
                         getProfileOwnerOfOrganizationOwnedDeviceLocked(userId);
@@ -10391,21 +10402,25 @@
                     userRestrictions = parent.userRestrictions;
                     userRestrictions = addOrRemoveDisableCameraRestriction(userRestrictions,
                             parent);
+                    originatingUserId =
+                            profileOwnerOfOrganizationOwnedDevice.getUserHandle().getIdentifier();
                 } else {
                     final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId);
 
                     if (profileOwner != null) {
                         userRestrictions = profileOwner.userRestrictions;
                         restrictionOwnerType = UserManagerInternal.OWNER_TYPE_PROFILE_OWNER;
+                        originatingUserId = profileOwner.getUserHandle().getIdentifier();
                     } else {
                         restrictionOwnerType = UserManagerInternal.OWNER_TYPE_NO_OWNER;
+                        originatingUserId = userId;
                     }
                     userRestrictions = addOrRemoveDisableCameraRestriction(
                             userRestrictions, userId);
                 }
             }
-            mUserManagerInternal.setDevicePolicyUserRestrictions(userId, userRestrictions,
-                    restrictionOwnerType);
+            mUserManagerInternal.setDevicePolicyUserRestrictions(originatingUserId,
+                    userRestrictions, restrictionOwnerType);
         }
     }
 
@@ -10435,14 +10450,18 @@
     }
 
     @Override
-    public Bundle getUserRestrictions(ComponentName who) {
+    public Bundle getUserRestrictions(ComponentName who, boolean parent) {
         if (!mHasFeature) {
             return null;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
+
         synchronized (getLockObject()) {
             final ActiveAdmin activeAdmin = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent);
+            if (parent) {
+                enforceProfileOwnerOfOrganizationOwnedDevice(activeAdmin);
+            }
             return activeAdmin.userRestrictions;
         }
     }
@@ -11241,7 +11260,7 @@
                 } else {
                     try {
                         setUserRestriction(who, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
-                                (Integer.parseInt(value) == 0) ? true : false);
+                                (Integer.parseInt(value) == 0) ? true : false, /* parent */ false);
                         DevicePolicyEventLogger
                                 .createEvent(DevicePolicyEnums.SET_SECURE_SETTING)
                                 .setAdmin(who)
@@ -11286,7 +11305,7 @@
         Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (getLockObject()) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-            setUserRestriction(who, UserManager.DISALLOW_UNMUTE_DEVICE, on);
+            setUserRestriction(who, UserManager.DISALLOW_UNMUTE_DEVICE, on, /* parent */ false);
             DevicePolicyEventLogger
                     .createEvent(DevicePolicyEnums.SET_MASTER_VOLUME_MUTED)
                     .setAdmin(who)
diff --git a/services/net/java/android/net/TcpKeepalivePacketData.java b/services/net/java/android/net/TcpKeepalivePacketData.java
index 7f2f499..aad75ae 100644
--- a/services/net/java/android/net/TcpKeepalivePacketData.java
+++ b/services/net/java/android/net/TcpKeepalivePacketData.java
@@ -19,7 +19,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.net.SocketKeepalive.InvalidPacketException;
 import android.net.util.IpUtils;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index cf7919b..3910993 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -40,7 +40,6 @@
         "platformprotosnano",
         "hamcrest-library",
         "servicestests-utils",
-        "xml-writer-device-lib",
         "service-appsearch",
         "service-jobscheduler",
     ],
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/AccessibilityGestureDetectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/GestureManifoldTest.java
similarity index 83%
rename from services/tests/servicestests/src/com/android/server/accessibility/gestures/AccessibilityGestureDetectorTest.java
rename to services/tests/servicestests/src/com/android/server/accessibility/gestures/GestureManifoldTest.java
index b707912..538e2d5 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/AccessibilityGestureDetectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/GestureManifoldTest.java
@@ -24,22 +24,21 @@
 
 import android.accessibilityservice.AccessibilityService;
 import android.content.Context;
-import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.PointF;
-import android.util.DisplayMetrics;
-import android.view.GestureDetector;
 import android.view.MotionEvent;
 
+import androidx.test.InstrumentationRegistry;
+
 import org.junit.Before;
 import org.junit.Test;
 
 import java.util.ArrayList;
 
 /**
- * Tests for AccessibilityGestureDetector
+ * Tests for GestureManifold
  */
-public class AccessibilityGestureDetectorTest {
+public class GestureManifoldTest {
 
     // Constants for testRecognizeGesturePath()
     private static final PointF PATH_START = new PointF(300f, 300f);
@@ -47,24 +46,21 @@
     private static final long PATH_STEP_MILLISEC = 100;
 
     // Data used by all tests
-    private AccessibilityGestureDetector mDetector;
-    private AccessibilityGestureDetector.Listener mResultListener;
+    private GestureManifold mManifold;
+    private TouchState mState;
+    private GestureManifold.Listener mResultListener;
 
     @Before
     public void setUp() {
-        // Construct a mock Context.
-        DisplayMetrics displayMetricsMock = mock(DisplayMetrics.class);
-        displayMetricsMock.xdpi = 500;
-        displayMetricsMock.ydpi = 500;
-        Resources mockResources = mock(Resources.class);
-        when(mockResources.getDisplayMetrics()).thenReturn(displayMetricsMock);
-        Context contextMock = mock(Context.class);
-        when(contextMock.getResources()).thenReturn(mockResources);
+        Context context = InstrumentationRegistry.getContext();
+        // Construct a testable GestureManifold.
+        mResultListener = mock(GestureManifold.Listener.class);
+        mState = new TouchState();
+        mManifold = new GestureManifold(context, mResultListener, mState);
+        // Play the role of touch explorer in updating the shared state.
+        when(mResultListener.onGestureStarted()).thenReturn(onGestureStarted());
 
-        // Construct a testable AccessibilityGestureDetector.
-        mResultListener = mock(AccessibilityGestureDetector.Listener.class);
-        GestureDetector doubleTapDetectorMock = mock(GestureDetector.class);
-        mDetector = new AccessibilityGestureDetector(contextMock, mResultListener, doubleTapDetectorMock);
+
     }
 
 
@@ -141,8 +137,8 @@
         // For each path step from start (non-inclusive) to end ... add a motion point.
         for (int step = 1; step < numSteps; ++step) {
             path.add(new PointF(
-                (start.x + (stepX * (float) step)),
-                (start.y + (stepY * (float) step))));
+                    (start.x + (stepX * (float) step)),
+                    (start.y + (stepY * (float) step))));
         }
     }
 
@@ -170,12 +166,22 @@
                     point.x, point.y, 0);
 
             // Send event.
-            mDetector.onMotionEvent(event, event, policyFlags);
+            mState.onReceivedMotionEvent(event);
+            mManifold.onMotionEvent(event, event, policyFlags);
             eventTimeMs += PATH_STEP_MILLISEC;
+            if (mState.isClear()) {
+                mState.startTouchInteracting();
+            }
         }
 
+        mState.clear();
         // Check that correct gesture was recognized.
         verify(mResultListener).onGestureCompleted(
                 argThat(gestureEvent -> gestureEvent.getGestureId() == gestureId));
     }
+
+    private boolean onGestureStarted() {
+        mState.startGestureDetecting();
+        return false;
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
index 4b1ec6f..a4ceadb 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
@@ -74,7 +74,7 @@
     private TouchExplorer mTouchExplorer;
     private long mLastDownTime = Integer.MIN_VALUE;
 
-    // mock package-private AccessibilityGestureDetector class
+    // mock package-private GestureManifold class
     @Rule
     public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
             new DexmakerShareClassLoaderRule();
@@ -108,7 +108,7 @@
     public void setUp() {
         Context context = InstrumentationRegistry.getContext();
         AccessibilityManagerService ams = new AccessibilityManagerService(context);
-        AccessibilityGestureDetector detector = mock(AccessibilityGestureDetector.class);
+        GestureManifold detector = mock(GestureManifold.class);
         mCaptor = new EventCaptor();
         mTouchExplorer = new TouchExplorer(context, ams, detector);
         mTouchExplorer.setNext(mCaptor);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/OWNERS b/services/tests/servicestests/src/com/android/server/biometrics/OWNERS
new file mode 100644
index 0000000..8765c9a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/OWNERS
@@ -0,0 +1,7 @@
+set noparent
+
+kchyn@google.com
+jaggies@google.com
+curtislb@google.com
+ilyamaty@google.com
+joshmccloskey@google.com
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index 7267976..cb99c11 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -22,15 +22,13 @@
 
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.compat.annotation.Change;
-import com.android.compat.annotation.XmlWriter;
-
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.util.UUID;
 
 @RunWith(AndroidJUnit4.class)
@@ -50,18 +48,10 @@
         return dir;
     }
 
-    private void writeChangesToFile(Change[] changes, File f) {
-        XmlWriter writer = new XmlWriter();
-        for (Change change: changes) {
-            writer.addChange(change);
-        }
-        try {
-            f.createNewFile();
-            writer.write(new FileOutputStream(f));
-        } catch (IOException e) {
-            throw new RuntimeException(
-                    "Encountered an error while writing compat config file", e);
-        }
+    private void writeToFile(File dir, String filename, String content) throws IOException {
+        OutputStream os = new FileOutputStream(new File(dir, filename));
+        os.write(content.getBytes());
+        os.close();
     }
 
     @Test
@@ -173,13 +163,15 @@
     }
 
     @Test
-    public void testReadConfig() {
-        Change[] changes = {new Change(1234L, "MY_CHANGE1", false, 2, null), new Change(1235L,
-                "MY_CHANGE2", true, null, "description"), new Change(1236L, "MY_CHANGE3", false,
-                null, "")};
+    public void testReadConfig() throws IOException {
+        String configXml = "<config>"
+                + "<compat-change id=\"1234\" name=\"MY_CHANGE1\" enableAfterTargetSdk=\"2\" />"
+                + "<compat-change id=\"1235\" name=\"MY_CHANGE2\" disabled=\"true\" />"
+                + "<compat-change id=\"1236\" name=\"MY_CHANGE3\" />"
+                + "</config>";
 
         File dir = createTempDir();
-        writeChangesToFile(changes, new File(dir.getPath() + "/platform_compat_config.xml"));
+        writeToFile(dir, "platform_compat_config.xml", configXml);
 
         CompatConfig pc = new CompatConfig();
         pc.initConfigFromLib(dir);
@@ -191,17 +183,18 @@
     }
 
     @Test
-    public void testReadConfigMultipleFiles() {
-        Change[] changes1 = {new Change(1234L, "MY_CHANGE1", false, 2, null)};
-        Change[] changes2 = {new Change(1235L, "MY_CHANGE2", true, null, ""), new Change(1236L,
-                "MY_CHANGE3", false, null, null)};
+    public void testReadConfigMultipleFiles() throws IOException {
+        String configXml1 = "<config>"
+                + "<compat-change id=\"1234\" name=\"MY_CHANGE1\" enableAfterTargetSdk=\"2\" />"
+                + "</config>";
+        String configXml2 = "<config>"
+                + "<compat-change id=\"1235\" name=\"MY_CHANGE2\" disabled=\"true\" />"
+                + "<compat-change id=\"1236\" name=\"MY_CHANGE3\" />"
+                + "</config>";
 
         File dir = createTempDir();
-        writeChangesToFile(changes1,
-                new File(dir.getPath() + "/libcore_platform_compat_config.xml"));
-        writeChangesToFile(changes2,
-                new File(dir.getPath() + "/frameworks_platform_compat_config.xml"));
-
+        writeToFile(dir, "libcore_platform_compat_config.xml", configXml1);
+        writeToFile(dir, "frameworks_platform_compat_config.xml", configXml2);
 
         CompatConfig pc = new CompatConfig();
         pc.initConfigFromLib(dir);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index f54f885..f97c887 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1162,7 +1162,8 @@
                 MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
 
         verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
-                eq(UserHandle.USER_SYSTEM), eq(null),
+                eq(UserHandle.USER_SYSTEM),
+                eq(null),
                 eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
 
         verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
@@ -1966,7 +1967,6 @@
         // TODO Make sure restrictions are written to the file.
     }
 
-    // TODO: (b/138709470) test addUserRestriction as PO of an organization-owned device
     public void testSetUserRestriction_asPoOfOrgOwnedDevice() throws Exception {
         final int MANAGED_PROFILE_USER_ID = DpmMockContext.CALLER_USER_HANDLE;
         final int MANAGED_PROFILE_ADMIN_UID =
@@ -1979,16 +1979,26 @@
         when(getServices().userManager.getProfileParent(MANAGED_PROFILE_USER_ID))
                 .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
 
+        parentDpm.addUserRestriction(admin1, UserManager.DISALLOW_CONFIG_DATE_TIME);
+        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
+                eq(MANAGED_PROFILE_USER_ID),
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_CONFIG_DATE_TIME),
+                eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE));
+        reset(getServices().userManagerInternal);
+
+        parentDpm.clearUserRestriction(admin1, UserManager.DISALLOW_CONFIG_DATE_TIME);
+        reset(getServices().userManagerInternal);
+
         parentDpm.setCameraDisabled(admin1, true);
         verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
-                eq(UserHandle.USER_SYSTEM),
+                eq(MANAGED_PROFILE_USER_ID),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA),
                 eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE));
         reset(getServices().userManagerInternal);
 
         parentDpm.setCameraDisabled(admin1, false);
         verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
-                eq(UserHandle.USER_SYSTEM),
+                eq(MANAGED_PROFILE_USER_ID),
                 MockUtils.checkUserRestrictions(),
                 eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE));
         reset(getServices().userManagerInternal);
diff --git a/services/tests/servicestests/src/com/android/server/om/MockitoUtils.kt b/services/tests/servicestests/src/com/android/server/om/MockitoUtils.kt
new file mode 100644
index 0000000..0f915db
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/om/MockitoUtils.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 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.om
+
+import org.mockito.Answers
+import org.mockito.Mockito
+import org.mockito.invocation.InvocationOnMock
+import org.mockito.stubbing.Answer
+import org.mockito.stubbing.Stubber
+
+// TODO(chiuwinson): Move this entire file to a shared utility module
+// TODO(b/135203078): De-dupe utils added for overlays vs package refactor
+object MockitoUtils {
+    val ANSWER_THROWS = Answer<Any?> {
+        when (val name = it.method.name) {
+            "toString" -> return@Answer Answers.CALLS_REAL_METHODS.answer(it)
+            else -> {
+                val arguments = it.arguments
+                        ?.takeUnless { it.isEmpty() }
+                        ?.joinToString()
+                        ?.let {
+                            "with $it"
+                        }
+                        .orEmpty()
+
+                throw UnsupportedOperationException("${it.mock::class.java.simpleName}#$name " +
+                        "$arguments should not be called")
+            }
+        }
+    }
+}
+
+inline fun <reified T> mock(block: T.() -> Unit = {}) = Mockito.mock(T::class.java).apply(block)
+
+fun <Type> Stubber.whenever(mock: Type) = Mockito.`when`(mock)
+fun <Type : Any?> whenever(mock: Type) = Mockito.`when`(mock)
+
+@Suppress("UNCHECKED_CAST")
+fun <Type : Any?> whenever(mock: Type, block: InvocationOnMock.() -> Any?) =
+        Mockito.`when`(mock).thenAnswer { block(it) }
+
+fun whenever(mock: Unit) = Mockito.`when`(mock).thenAnswer { }
+
+inline fun <reified T> mockThrowOnUnmocked(block: T.() -> Unit): T {
+    val swappingAnswer = object : Answer<Any?> {
+        var delegate: Answer<*> = Answers.RETURNS_DEFAULTS
+
+        override fun answer(invocation: InvocationOnMock?): Any? {
+            return delegate.answer(invocation)
+        }
+    }
+
+    return Mockito.mock(T::class.java, swappingAnswer).apply(block)
+            .also {
+                // To allow when() usage inside block, only swap to throwing afterwards
+                swappingAnswer.delegate = MockitoUtils.ANSWER_THROWS
+            }
+}
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
new file mode 100644
index 0000000..ef12948
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2019 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.om
+
+import android.content.pm.parsing.AndroidPackage
+import android.net.Uri
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.testng.Assert.assertThrows
+
+@RunWith(Parameterized::class)
+class OverlayReferenceMapperTests {
+
+    companion object {
+        private const val TARGET_PACKAGE_NAME = "com.test.target"
+        private const val OVERLAY_PACKAGE_NAME = "com.test.overlay"
+        private const val ACTOR_PACKAGE_NAME = "com.test.actor"
+        private const val ACTOR_NAME = "overlay://test/actorName"
+
+        @JvmStatic
+        @Parameterized.Parameters(name = "deferRebuild {0}")
+        fun parameters() = arrayOf(true, false)
+    }
+
+    private lateinit var mapper: OverlayReferenceMapper
+
+    @JvmField
+    @Parameterized.Parameter(0)
+    var deferRebuild = false
+
+    @Before
+    fun initMapper() {
+        mapper = mapper()
+    }
+
+    @Test
+    fun targetWithOverlay() {
+        val target = mockTarget()
+        val overlay = mockOverlay()
+        val existing = mapper.addInOrder(overlay)
+        assertEmpty()
+        mapper.addInOrder(target, existing = existing)
+        assertMapping(ACTOR_PACKAGE_NAME to setOf(target, overlay))
+        mapper.remove(target)
+        assertEmpty()
+    }
+
+    @Test
+    fun targetWithMultipleOverlays() {
+        val target = mockTarget()
+        val overlay0 = mockOverlay(0)
+        val overlay1 = mockOverlay(1)
+        mapper = mapper(
+                overlayToTargetToOverlayables = mapOf(
+                        overlay0.packageName to mapOf(
+                                target.packageName to target.overlayables.keys
+                        ),
+                        overlay1.packageName to mapOf(
+                                target.packageName to target.overlayables.keys
+                        )
+                )
+        )
+        val existing = mapper.addInOrder(overlay0, overlay1)
+        assertEmpty()
+        mapper.addInOrder(target, existing = existing)
+        assertMapping(ACTOR_PACKAGE_NAME to setOf(target, overlay0, overlay1))
+        mapper.remove(overlay0)
+        assertMapping(ACTOR_PACKAGE_NAME to setOf(target, overlay1))
+        mapper.remove(target)
+        assertEmpty()
+    }
+
+    @Test
+    fun targetWithoutOverlay() {
+        val target = mockTarget()
+        mapper.addInOrder(target)
+        assertMapping(ACTOR_PACKAGE_NAME to setOf(target))
+        mapper.remove(target)
+        assertEmpty()
+    }
+
+    @Test
+    fun overlayWithTarget() {
+        val target = mockTarget()
+        val overlay = mockOverlay()
+        val existing = mapper.addInOrder(target)
+        assertMapping(ACTOR_PACKAGE_NAME to setOf(target))
+        mapper.addInOrder(overlay, existing = existing)
+        assertMapping(ACTOR_PACKAGE_NAME to setOf(target, overlay))
+        mapper.remove(overlay)
+        assertMapping(ACTOR_PACKAGE_NAME to setOf(target))
+    }
+
+    @Test
+    fun overlayWithMultipleTargets() {
+        val target0 = mockTarget(0)
+        val target1 = mockTarget(1)
+        val overlay = mockOverlay()
+        mapper = mapper(
+                overlayToTargetToOverlayables = mapOf(
+                        overlay.packageName to mapOf(
+                                target0.packageName to target0.overlayables.keys,
+                                target1.packageName to target1.overlayables.keys
+                        )
+                )
+        )
+        mapper.addInOrder(target0, target1, overlay)
+        assertMapping(ACTOR_PACKAGE_NAME to setOf(target0, target1, overlay))
+        mapper.remove(target0)
+        assertMapping(ACTOR_PACKAGE_NAME to setOf(target1, overlay))
+        mapper.remove(target1)
+        assertEmpty()
+    }
+
+    @Test
+    fun overlayWithoutTarget() {
+        val overlay = mockOverlay()
+        mapper.addInOrder(overlay)
+        // An overlay can only have visibility exposed through its target
+        assertEmpty()
+        mapper.remove(overlay)
+        assertEmpty()
+    }
+
+    private fun OverlayReferenceMapper.addInOrder(
+        vararg pkgs: AndroidPackage,
+        existing: MutableMap<String, AndroidPackage> = mutableMapOf()
+    ) = pkgs.fold(existing) { map, pkg ->
+        addPkg(pkg, map)
+        map[pkg.packageName] = pkg
+        return@fold map
+    }
+
+    private fun OverlayReferenceMapper.remove(pkg: AndroidPackage) = removePkg(pkg.packageName)
+
+    private fun assertMapping(vararg pairs: Pair<String, Set<AndroidPackage>>) {
+        val expected = pairs.associate { it }
+                .mapValues { pair -> pair.value.map { it.packageName }.toSet() }
+
+        // This validates the API exposed for querying the relationships
+        expected.forEach { (actorPkgName, expectedPkgNames) ->
+            expectedPkgNames.forEach { expectedPkgName ->
+                if (deferRebuild) {
+                    assertThrows(IllegalStateException::class.java) {
+                        mapper.isValidActor(expectedPkgName, actorPkgName)
+                    }
+                    mapper.rebuildIfDeferred()
+                    deferRebuild = false
+                }
+
+                assertThat(mapper.isValidActor(expectedPkgName, actorPkgName)).isTrue()
+            }
+        }
+
+        // This asserts no other relationships are defined besides those tested above
+        assertThat(mapper.actorPkgToPkgs).containsExactlyEntriesIn(expected)
+    }
+
+    private fun assertEmpty() = assertMapping()
+
+    private fun mapper(
+        namedActors: Map<String, Map<String, String>> = Uri.parse(ACTOR_NAME).run {
+            mapOf(authority!! to mapOf(pathSegments.first() to ACTOR_PACKAGE_NAME))
+        },
+        overlayToTargetToOverlayables: Map<String, Map<String, Set<String>>> = mapOf(
+                mockOverlay().packageName to mapOf(
+                        mockTarget().run { packageName to overlayables.keys }
+                )
+        )
+    ) = OverlayReferenceMapper(deferRebuild, object : OverlayReferenceMapper.Provider {
+        override fun getActorPkg(actor: String?) =
+                OverlayActorEnforcer.getPackageNameForActor(actor, namedActors).first
+
+        override fun getTargetToOverlayables(pkg: AndroidPackage) =
+                overlayToTargetToOverlayables[pkg.packageName] ?: emptyMap()
+    })
+
+    private fun mockTarget(increment: Int = 0) = mockThrowOnUnmocked<AndroidPackage> {
+        whenever(packageName) { "$TARGET_PACKAGE_NAME$increment" }
+        whenever(overlayables) { mapOf("overlayableName$increment" to ACTOR_NAME) }
+        whenever(toString()) { "Package{$packageName}" }
+    }
+
+    private fun mockOverlay(increment: Int = 0) = mockThrowOnUnmocked<AndroidPackage> {
+        whenever(packageName) { "$OVERLAY_PACKAGE_NAME$increment" }
+        whenever(overlayables) { emptyMap<String, String>() }
+        whenever(toString()) { "Package{$packageName}" }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index 4fc625a..82bbdcb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -35,6 +35,11 @@
 import android.os.Build;
 import android.os.Process;
 import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import androidx.annotation.NonNull;
+
+import com.android.server.om.OverlayReferenceMapper;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -43,11 +48,18 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
 @RunWith(JUnit4.class)
 public class AppsFilterTest {
 
     private static final int DUMMY_CALLING_UID = 10345;
     private static final int DUMMY_TARGET_UID = 10556;
+    private static final int DUMMY_ACTOR_UID = 10656;
+    private static final int DUMMY_OVERLAY_UID = 10756;
+    private static final int DUMMY_ACTOR_TWO_UID = 10856;
 
     @Mock
     AppsFilter.FeatureConfig mFeatureConfigMock;
@@ -117,7 +129,7 @@
     @Test
     public void testSystemReadyPropogates() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
         appsFilter.onSystemReady();
         verify(mFeatureConfigMock).onSystemReady();
     }
@@ -125,7 +137,8 @@
     @Test
     public void testQueriesAction_FilterMatches() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkg("com.some.package", new IntentFilter("TEST_ACTION")), DUMMY_TARGET_UID);
@@ -138,7 +151,8 @@
     @Test
     public void testQueriesAction_NoMatchingAction_Filters() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkg("com.some.package"), DUMMY_TARGET_UID);
@@ -151,7 +165,8 @@
     @Test
     public void testQueriesAction_NoMatchingActionFilterLowSdk_DoesntFilter() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkg("com.some.package"), DUMMY_TARGET_UID);
@@ -169,7 +184,8 @@
     @Test
     public void testNoQueries_Filters() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkg("com.some.package"), DUMMY_TARGET_UID);
@@ -182,7 +198,8 @@
     @Test
     public void testForceQueryable_DoesntFilter() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                         pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_UID);
@@ -195,7 +212,8 @@
     @Test
     public void testForceQueryableByDevice_SystemCaller_DoesntFilter() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkg("com.some.package"), DUMMY_TARGET_UID,
@@ -209,7 +227,8 @@
     @Test
     public void testForceQueryableByDevice_NonSystemCaller_Filters() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkg("com.some.package"), DUMMY_TARGET_UID);
@@ -224,7 +243,8 @@
     public void testSystemQueryable_DoesntFilter() {
         final AppsFilter appsFilter =
                 new AppsFilter(mFeatureConfigMock, new String[]{},
-                        true /* system force queryable */);
+                        true /* system force queryable */, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkg("com.some.package"), DUMMY_TARGET_UID,
@@ -238,7 +258,8 @@
     @Test
     public void testQueriesPackage_DoesntFilter() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkg("com.some.package"), DUMMY_TARGET_UID);
@@ -253,7 +274,8 @@
         when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class)))
                 .thenReturn(false);
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(
                 appsFilter, pkg("com.some.package"), DUMMY_TARGET_UID);
@@ -266,20 +288,22 @@
     @Test
     public void testSystemUid_DoesntFilter() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkg("com.some.package"), DUMMY_TARGET_UID);
 
         assertFalse(appsFilter.shouldFilterApplication(0, null, target, 0));
-        assertFalse(appsFilter.shouldFilterApplication(
-                Process.FIRST_APPLICATION_UID - 1, null, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(Process.FIRST_APPLICATION_UID - 1,
+                null, target, 0));
     }
 
     @Test
     public void testNonSystemUid_NoCallingSetting_Filters() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkg("com.some.package"), DUMMY_TARGET_UID);
@@ -290,7 +314,8 @@
     @Test
     public void testNoTargetPackage_filters() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = new PackageSettingBuilder()
                 .setName("com.some.package")
@@ -304,6 +329,127 @@
         assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
     }
 
+    @Test
+    public void testActsOnTargetOfOverlay() {
+        final String actorName = "overlay://test/actorName";
+
+        ParsingPackage target = pkg("com.some.package.target")
+                .addOverlayable("overlayableName", actorName);
+        ParsingPackage overlay = pkg("com.some.package.overlay")
+                .setIsOverlay(true)
+                .setOverlayTarget(target.getPackageName())
+                .setOverlayTargetName("overlayableName");
+        ParsingPackage actor = pkg("com.some.package.actor");
+
+        final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false,
+                new OverlayReferenceMapper.Provider() {
+                    @Nullable
+                    @Override
+                    public String getActorPkg(String actorString) {
+                        if (actorName.equals(actorString)) {
+                            return actor.getPackageName();
+                        }
+                        return null;
+                    }
+
+                    @NonNull
+                    @Override
+                    public Map<String, Set<String>> getTargetToOverlayables(
+                            @NonNull AndroidPackage pkg) {
+                        if (overlay.getPackageName().equals(pkg.getPackageName())) {
+                            Map<String, Set<String>> map = new ArrayMap<>();
+                            Set<String> set = new ArraySet<>();
+                            set.add(overlay.getOverlayTargetName());
+                            map.put(overlay.getOverlayTarget(), set);
+                            return map;
+                        }
+                        return Collections.emptyMap();
+                    }
+                });
+        appsFilter.onSystemReady();
+
+        PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_UID);
+        PackageSetting overlaySetting = simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_UID);
+        PackageSetting actorSetting = simulateAddPackage(appsFilter, actor, DUMMY_ACTOR_UID);
+
+        // Actor can see both target and overlay
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_UID, actorSetting,
+                targetSetting, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_UID, actorSetting,
+                overlaySetting, 0));
+
+        // But target/overlay can't see each other
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_UID, targetSetting,
+                overlaySetting, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_UID, overlaySetting,
+                targetSetting, 0));
+
+        // And can't see the actor
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_UID, targetSetting,
+                actorSetting, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_UID, overlaySetting,
+                actorSetting, 0));
+    }
+
+    @Test
+    public void testActsOnTargetOfOverlayThroughSharedUser() {
+        final String actorName = "overlay://test/actorName";
+
+        ParsingPackage target = pkg("com.some.package.target")
+                .addOverlayable("overlayableName", actorName);
+        ParsingPackage overlay = pkg("com.some.package.overlay")
+                .setIsOverlay(true)
+                .setOverlayTarget(target.getPackageName())
+                .setOverlayTargetName("overlayableName");
+        ParsingPackage actorOne = pkg("com.some.package.actor.one");
+        ParsingPackage actorTwo = pkg("com.some.package.actor.two");
+
+        final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false,
+                new OverlayReferenceMapper.Provider() {
+                    @Nullable
+                    @Override
+                    public String getActorPkg(String actorString) {
+                        // Only actorOne is mapped as a valid actor
+                        if (actorName.equals(actorString)) {
+                            return actorOne.getPackageName();
+                        }
+                        return null;
+                    }
+
+                    @NonNull
+                    @Override
+                    public Map<String, Set<String>> getTargetToOverlayables(
+                            @NonNull AndroidPackage pkg) {
+                        if (overlay.getPackageName().equals(pkg.getPackageName())) {
+                            Map<String, Set<String>> map = new ArrayMap<>();
+                            Set<String> set = new ArraySet<>();
+                            set.add(overlay.getOverlayTargetName());
+                            map.put(overlay.getOverlayTarget(), set);
+                            return map;
+                        }
+                        return Collections.emptyMap();
+                    }
+                });
+        appsFilter.onSystemReady();
+
+        PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_UID);
+        PackageSetting overlaySetting = simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_UID);
+        PackageSetting actorOneSetting = simulateAddPackage(appsFilter, actorOne, DUMMY_ACTOR_UID);
+        PackageSetting actorTwoSetting = simulateAddPackage(appsFilter, actorTwo,
+                DUMMY_ACTOR_TWO_UID);
+
+        SharedUserSetting actorSharedSetting = new SharedUserSetting("actorSharedUser",
+                actorOneSetting.pkgFlags, actorOneSetting.pkgPrivateFlags);
+        actorSharedSetting.addPackage(actorOneSetting);
+        actorSharedSetting.addPackage(actorTwoSetting);
+
+        // actorTwo can see both target and overlay
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_TWO_UID, actorSharedSetting,
+                targetSetting, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_TWO_UID, actorSharedSetting,
+                overlaySetting, 0));
+    }
+
     private interface WithSettingBuilder {
         PackageSettingBuilder withBuilder(PackageSettingBuilder builder);
     }
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
index 5baeede..2473997 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
@@ -22,7 +22,7 @@
 
 import java.io.File;
 
-class PackageSettingBuilder {
+public class PackageSettingBuilder {
     private String mName;
     private String mRealName;
     private String mCodePath;
diff --git a/services/usb/java/com/android/server/usb/UsbSerialReader.java b/services/usb/java/com/android/server/usb/UsbSerialReader.java
index 86016bb..095e8e9 100644
--- a/services/usb/java/com/android/server/usb/UsbSerialReader.java
+++ b/services/usb/java/com/android/server/usb/UsbSerialReader.java
@@ -75,12 +75,14 @@
         if (uid != Process.SYSTEM_UID) {
             enforcePackageBelongsToUid(uid, packageName);
 
+            UserHandle user = Binder.getCallingUserHandle();
             int packageTargetSdkVersion;
             long token = Binder.clearCallingIdentity();
             try {
                 PackageInfo pkg;
                 try {
-                    pkg = mContext.getPackageManager().getPackageInfo(packageName, 0);
+                    pkg = mContext.getPackageManager()
+                            .getPackageInfoAsUser(packageName, 0, user.getIdentifier());
                 } catch (PackageManager.NameNotFoundException e) {
                     throw new RemoteException("package " + packageName + " cannot be found");
                 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 001888c..4ca3eee 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2176,7 +2176,7 @@
      * the start of the next month.
      * <p>
      * This setting may be still overridden by explicit user choice. By default,
-     * the platform value will be used.
+     * {@link #DATA_CYCLE_USE_PLATFORM_DEFAULT} will be used.
      */
     public static final String KEY_MONTHLY_DATA_CYCLE_DAY_INT =
             "monthly_data_cycle_day_int";
@@ -2185,10 +2185,7 @@
      * When {@link #KEY_MONTHLY_DATA_CYCLE_DAY_INT}, {@link #KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG},
      * or {@link #KEY_DATA_WARNING_THRESHOLD_BYTES_LONG} are set to this value, the platform default
      * value will be used for that key.
-     *
-     * @hide
      */
-    @Deprecated
     public static final int DATA_CYCLE_USE_PLATFORM_DEFAULT = -1;
 
     /**
@@ -2212,8 +2209,8 @@
      * If the value is set to {@link #DATA_CYCLE_THRESHOLD_DISABLED}, the data usage warning will
      * be disabled.
      * <p>
-     * This setting may be overridden by explicit user choice. By default, the platform value
-     * will be used.
+     * This setting may be overridden by explicit user choice. By default,
+     * {@link #DATA_CYCLE_USE_PLATFORM_DEFAULT} will be used.
      */
     public static final String KEY_DATA_WARNING_THRESHOLD_BYTES_LONG =
             "data_warning_threshold_bytes_long";
@@ -2221,8 +2218,7 @@
     /**
      * Controls if the device should automatically notify the user as they reach
      * their cellular data warning. When set to {@code false} the carrier is
-     * expected to have implemented their own notification mechanism.
-     * @hide
+     * expected to have implemented their own notification mechanism. {@code true} by default.
      */
     public static final String KEY_DATA_WARNING_NOTIFICATION_BOOL =
             "data_warning_notification_bool";
@@ -2244,8 +2240,8 @@
      * phone. If the value is set to {@link #DATA_CYCLE_THRESHOLD_DISABLED}, the data limit will be
      * disabled.
      * <p>
-     * This setting may be overridden by explicit user choice. By default, the platform value
-     * will be used.
+     * This setting may be overridden by explicit user choice. By default,
+     * {@link #DATA_CYCLE_USE_PLATFORM_DEFAULT} will be used.
      */
     public static final String KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG =
             "data_limit_threshold_bytes_long";
@@ -2253,8 +2249,7 @@
     /**
      * Controls if the device should automatically notify the user as they reach
      * their cellular data limit. When set to {@code false} the carrier is
-     * expected to have implemented their own notification mechanism.
-     * @hide
+     * expected to have implemented their own notification mechanism. {@code true} by default.
      */
     public static final String KEY_DATA_LIMIT_NOTIFICATION_BOOL =
             "data_limit_notification_bool";
@@ -2262,8 +2257,7 @@
     /**
      * Controls if the device should automatically notify the user when rapid
      * cellular data usage is observed. When set to {@code false} the carrier is
-     * expected to have implemented their own notification mechanism.
-     * @hide
+     * expected to have implemented their own notification mechanism.  {@code true} by default.
      */
     public static final String KEY_DATA_RAPID_NOTIFICATION_BOOL =
             "data_rapid_notification_bool";
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 6c321e5..b1dd2d8 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -38,6 +38,9 @@
 import android.annotation.WorkerThread;
 import android.app.ActivityThread;
 import android.app.PendingIntent;
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -142,6 +145,14 @@
     private static final String TAG = "TelephonyManager";
 
     /**
+     * To expand the error codes for {@link TelephonyManager#updateAvailableNetworks} and
+     * {@link TelephonyManager#setPreferredOpportunisticDataSubscription}.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
+    private static final long CALLBACK_ON_MORE_ERROR_CODE_CHANGE = 130595455L;
+
+    /**
      * The key to use when placing the result of {@link #requestModemActivityInfo(ResultReceiver)}
      * into the ResultReceiver Bundle.
      * @hide
@@ -10285,19 +10296,25 @@
     }
 
     /**
-     * Action set from carrier signalling broadcast receivers to enable/disable radio
-     * Permissions {@link android.Manifest.permission.MODIFY_PHONE_STATE} is required.
-     * @param subId the subscription ID that this action applies to.
+     * Carrier action to enable or disable the radio.
+     *
+     * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+     * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+     *
      * @param enabled control enable or disable radio.
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
-    public void carrierActionSetRadioEnabled(int subId, boolean enabled) {
+    public void setRadioEnabled(boolean enabled) {
         try {
             ITelephony service = getITelephony();
             if (service != null) {
-                service.carrierActionSetRadioEnabled(subId, enabled);
+                service.carrierActionSetRadioEnabled(
+                        getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), enabled);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#carrierActionSetRadioEnabled", e);
@@ -10305,20 +10322,25 @@
     }
 
     /**
-     * Action set from carrier signalling broadcast receivers to start/stop reporting default
-     * network available events
-     * Permissions {@link android.Manifest.permission.MODIFY_PHONE_STATE} is required.
-     * @param subId the subscription ID that this action applies to.
+     * Carrier action to start or stop reporting default network available events.
+     *
+     * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+     * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+     *
      * @param report control start/stop reporting network status.
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
-    public void carrierActionReportDefaultNetworkStatus(int subId, boolean report) {
+    public void reportDefaultNetworkStatus(boolean report) {
         try {
             ITelephony service = getITelephony();
             if (service != null) {
-                service.carrierActionReportDefaultNetworkStatus(subId, report);
+                service.carrierActionReportDefaultNetworkStatus(
+                        getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), report);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#carrierActionReportDefaultNetworkStatus", e);
@@ -10326,18 +10348,24 @@
     }
 
     /**
-     * Action set from carrier signalling broadcast receivers to reset all carrier actions
-     * Permissions {@link android.Manifest.permission.MODIFY_PHONE_STATE} is required.
-     * @param subId the subscription ID that this action applies to.
+     * Reset all carrier actions previously set by {@link #setRadioEnabled},
+     * {@link #reportDefaultNetworkStatus} and {@link #setCarrierDataEnabled}.
+     *
+     * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+     * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
-    public void carrierActionResetAll(int subId) {
+    public void resetAllCarrierActions() {
         try {
             ITelephony service = getITelephony();
             if (service != null) {
-                service.carrierActionResetAll(subId);
+                service.carrierActionResetAll(
+                        getSubId(SubscriptionManager.getDefaultDataSubscriptionId()));
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#carrierActionResetAll", e);
@@ -11350,7 +11378,11 @@
                 final long identity = Binder.clearCallingIdentity();
                 try {
                     executor.execute(() -> {
-                        callback.accept(SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION);
+                        if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
+                            callback.accept(SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION);
+                        } else {
+                            callback.accept(SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION);
+                        }
                     });
                 } finally {
                     Binder.restoreCallingIdentity(identity);
@@ -11447,7 +11479,11 @@
                     final long identity = Binder.clearCallingIdentity();
                     try {
                         executor.execute(() -> {
-                            callback.accept(UPDATE_AVAILABLE_NETWORKS_REMOTE_SERVICE_EXCEPTION);
+                            if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
+                                callback.accept(UPDATE_AVAILABLE_NETWORKS_REMOTE_SERVICE_EXCEPTION);
+                            } else {
+                                callback.accept(UPDATE_AVAILABLE_NETWORKS_UNKNOWN_FAILURE);
+                            }
                         });
                     } finally {
                         Binder.restoreCallingIdentity(identity);
diff --git a/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java b/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java
index e323592..026677e 100644
--- a/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java
+++ b/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java
@@ -53,6 +53,8 @@
      */
     @Test
     public void testCreateStartDelete() throws Exception {
+        // Disable package verifier for ADB installs.
+        getDevice().executeShellCommand("settings put global verifier_verify_adb_installs 0");
         int iteration = 0;
         final long deadline = System.nanoTime() + TimeUnit.MINUTES.toNanos(TIME_LIMIT_MINUTES);
         while (System.nanoTime() < deadline) {
diff --git a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
index 5cb0d7e..e632aaf 100644
--- a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
+++ b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
@@ -22,8 +22,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
-import android.net.SocketKeepalive.InvalidPacketException;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/tools/localedata/extract_icu_data.py b/tools/localedata/extract_icu_data.py
index 6b4c346..ca1847a 100755
--- a/tools/localedata/extract_icu_data.py
+++ b/tools/localedata/extract_icu_data.py
@@ -176,6 +176,9 @@
     dump_representative_locales(representative_locales)
     return likely_script_dict
 
+def escape_script_variable_name(script):
+    """Escape characters, e.g. '~', in a C++ variable name"""
+    return script.replace("~", "_")
 
 def read_parent_data(icu_data_dir):
     """Read locale parent data from ICU data files."""
@@ -221,7 +224,7 @@
     for script in sorted_scripts:
         parent_dict = script_organized_dict[script]
         print ('const std::unordered_map<uint32_t, uint32_t> %s_PARENTS({'
-            % script.upper())
+            % escape_script_variable_name(script.upper()))
         for locale in sorted(parent_dict.keys()):
             parent = parent_dict[locale]
             print '    {0x%08Xu, 0x%08Xu}, // %s -> %s' % (
@@ -239,7 +242,7 @@
     for script in sorted_scripts:
         print "    {{'%c', '%c', '%c', '%c'}, &%s_PARENTS}," % (
             script[0], script[1], script[2], script[3],
-            script.upper())
+            escape_script_variable_name(script.upper()))
     print '};'
 
 
diff --git a/wifi/tests/Android.mk b/wifi/tests/Android.mk
index 3453d6e..d2c385b4 100644
--- a/wifi/tests/Android.mk
+++ b/wifi/tests/Android.mk
@@ -59,6 +59,8 @@
 
 LOCAL_PACKAGE_NAME := FrameworksWifiApiTests
 LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_COMPATIBILITY_SUITE := \
+    device-tests \
+    mts \
 
 include $(BUILD_PACKAGE)
diff --git a/wifi/tests/AndroidTest.xml b/wifi/tests/AndroidTest.xml
index cae19e4..987fee7 100644
--- a/wifi/tests/AndroidTest.xml
+++ b/wifi/tests/AndroidTest.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <configuration description="Runs Frameworks Wifi API Tests.">
-    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="test-file-name" value="FrameworksWifiApiTests.apk" />
     </target_preparer>
 
diff --git a/wifi/tests/runtests.sh b/wifi/tests/runtests.sh
index 7a0dfb0..4024371 100755
--- a/wifi/tests/runtests.sh
+++ b/wifi/tests/runtests.sh
@@ -16,7 +16,6 @@
 
 set -x # print commands
 
-adb root
 adb wait-for-device
 
 TARGET_ARCH=$($ANDROID_BUILD_TOP/build/soong/soong_ui.bash --dumpvar-mode TARGET_ARCH)