Merge "Adding a level of indirection. Dimens value should live in the framework/base and not the overlay." into qt-dev
diff --git a/core/java/android/view/textclassifier/ActionsModelParamsSupplier.java b/core/java/android/view/textclassifier/ActionsModelParamsSupplier.java
new file mode 100644
index 0000000..6b90588
--- /dev/null
+++ b/core/java/android/view/textclassifier/ActionsModelParamsSupplier.java
@@ -0,0 +1,208 @@
+/*
+ * 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.textclassifier;
+
+import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Base64;
+import android.util.KeyValueListParser;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+import java.lang.ref.WeakReference;
+import java.util.Objects;
+import java.util.function.Supplier;
+
+/**
+ * Parses the {@link Settings.Global#TEXT_CLASSIFIER_ACTION_MODEL_PARAMS} flag.
+ *
+ * @hide
+ */
+public final class ActionsModelParamsSupplier implements
+        Supplier<ActionsModelParamsSupplier.ActionsModelParams> {
+    private static final String TAG = TextClassifier.DEFAULT_LOG_TAG;
+
+    @VisibleForTesting
+    static final String KEY_REQUIRED_MODEL_VERSION = "required_model_version";
+    @VisibleForTesting
+    static final String KEY_REQUIRED_LOCALES = "required_locales";
+    @VisibleForTesting
+    static final String KEY_SERIALIZED_PRECONDITIONS = "serialized_preconditions";
+
+    private final Context mAppContext;
+    private final SettingsObserver mSettingsObserver;
+
+    private final Object mLock = new Object();
+    private final Runnable mOnChangedListener;
+    @Nullable
+    @GuardedBy("mLock")
+    private ActionsModelParams mActionsModelParams;
+    @GuardedBy("mLock")
+    private boolean mParsed = true;
+
+    public ActionsModelParamsSupplier(Context context, @Nullable Runnable onChangedListener) {
+        mAppContext = Preconditions.checkNotNull(context).getApplicationContext();
+        mOnChangedListener = onChangedListener == null ? () -> {} : onChangedListener;
+        mSettingsObserver = new SettingsObserver(mAppContext, () -> {
+            synchronized (mLock) {
+                Log.v(TAG, "Settings.Global.TEXT_CLASSIFIER_ACTION_MODEL_PARAMS is updated");
+                mParsed = true;
+                mOnChangedListener.run();
+            }
+        });
+    }
+
+    /**
+     * Returns the parsed actions params or {@link ActionsModelParams#INVALID} if the value is
+     * invalid.
+     */
+    @Override
+    public ActionsModelParams get() {
+        synchronized (mLock) {
+            if (mParsed) {
+                mActionsModelParams = parse(mAppContext.getContentResolver());
+                mParsed = false;
+            }
+        }
+        return mActionsModelParams;
+    }
+
+    private ActionsModelParams parse(ContentResolver contentResolver) {
+        String settingStr = Settings.Global.getString(contentResolver,
+                Settings.Global.TEXT_CLASSIFIER_ACTION_MODEL_PARAMS);
+        if (TextUtils.isEmpty(settingStr)) {
+            return ActionsModelParams.INVALID;
+        }
+        try {
+            KeyValueListParser keyValueListParser = new KeyValueListParser(',');
+            keyValueListParser.setString(settingStr);
+            int version = keyValueListParser.getInt(KEY_REQUIRED_MODEL_VERSION, -1);
+            if (version == -1) {
+                Log.w(TAG, "ActionsModelParams.Parse, invalid model version");
+                return ActionsModelParams.INVALID;
+            }
+            String locales = keyValueListParser.getString(KEY_REQUIRED_LOCALES, null);
+            if (locales == null) {
+                Log.w(TAG, "ActionsModelParams.Parse, invalid locales");
+                return ActionsModelParams.INVALID;
+            }
+            String serializedPreconditionsStr =
+                    keyValueListParser.getString(KEY_SERIALIZED_PRECONDITIONS, null);
+            if (serializedPreconditionsStr == null) {
+                Log.w(TAG, "ActionsModelParams.Parse, invalid preconditions");
+                return ActionsModelParams.INVALID;
+            }
+            byte[] serializedPreconditions =
+                    Base64.decode(serializedPreconditionsStr, Base64.NO_WRAP);
+            return new ActionsModelParams(version, locales, serializedPreconditions);
+        } catch (Throwable t) {
+            Log.e(TAG, "Invalid TEXT_CLASSIFIER_ACTION_MODEL_PARAMS, ignore", t);
+        }
+        return ActionsModelParams.INVALID;
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            mAppContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * Represents the parsed result.
+     */
+    public static final class ActionsModelParams {
+
+        public static final ActionsModelParams INVALID =
+                new ActionsModelParams(-1, "", new byte[0]);
+
+        /**
+         * The required model version to apply {@code mSerializedPreconditions}.
+         */
+        private final int mRequiredModelVersion;
+
+        /**
+         * The required model locales to apply {@code mSerializedPreconditions}.
+         */
+        private final String mRequiredModelLocales;
+
+        /**
+         * The serialized params that will be applied to the model file, if all requirements are
+         * met. Do not modify.
+         */
+        private final byte[] mSerializedPreconditions;
+
+        public ActionsModelParams(int requiredModelVersion, String requiredModelLocales,
+                byte[] serializedPreconditions) {
+            mRequiredModelVersion = requiredModelVersion;
+            mRequiredModelLocales = Preconditions.checkNotNull(requiredModelLocales);
+            mSerializedPreconditions = Preconditions.checkNotNull(serializedPreconditions);
+        }
+
+        /**
+         * Returns the serialized preconditions. Returns {@code null} if the the model in use does
+         * not meet all the requirements listed in the {@code ActionsModelParams} or the params
+         * are invalid.
+         */
+        @Nullable
+        public byte[] getSerializedPreconditions(ModelFileManager.ModelFile modelInUse) {
+            if (this == INVALID) {
+                return null;
+            }
+            if (modelInUse.getVersion() != mRequiredModelVersion) {
+                Log.w(TAG, String.format(
+                        "Not applying mSerializedPreconditions, required version=%d, actual=%d",
+                        mRequiredModelVersion, modelInUse.getVersion()));
+                return null;
+            }
+            if (!Objects.equals(modelInUse.getSupportedLocalesStr(), mRequiredModelLocales)) {
+                Log.w(TAG, String.format(
+                        "Not applying mSerializedPreconditions, required locales=%s, actual=%s",
+                        mRequiredModelLocales, modelInUse.getSupportedLocalesStr()));
+                return null;
+            }
+            return mSerializedPreconditions;
+        }
+    }
+
+    private static final class SettingsObserver extends ContentObserver {
+
+        private final WeakReference<Runnable> mOnChangedListener;
+
+        SettingsObserver(Context appContext, Runnable listener) {
+            super(null);
+            mOnChangedListener = new WeakReference<>(listener);
+            appContext.getContentResolver().registerContentObserver(
+                    Settings.Global.getUriFor(Settings.Global.TEXT_CLASSIFIER_ACTION_MODEL_PARAMS),
+                    false /* notifyForDescendants */,
+                    this);
+        }
+
+        public void onChange(boolean selfChange) {
+            if (mOnChangedListener.get() != null) {
+                mOnChangedListener.get().run();
+            }
+        }
+    }
+}
diff --git a/core/java/android/view/textclassifier/ModelFileManager.java b/core/java/android/view/textclassifier/ModelFileManager.java
index 8558a46..e04285d 100644
--- a/core/java/android/view/textclassifier/ModelFileManager.java
+++ b/core/java/android/view/textclassifier/ModelFileManager.java
@@ -167,6 +167,7 @@
                         file,
                         version,
                         supportedLocales,
+                        supportedLocalesStr,
                         ModelFile.LANGUAGE_INDEPENDENT.equals(supportedLocalesStr));
             } catch (FileNotFoundException e) {
                 Log.e(DEFAULT_LOG_TAG, "Failed to find " + file.getAbsolutePath(), e);
@@ -201,13 +202,16 @@
         private final File mFile;
         private final int mVersion;
         private final List<Locale> mSupportedLocales;
+        private final String mSupportedLocalesStr;
         private final boolean mLanguageIndependent;
 
         public ModelFile(File file, int version, List<Locale> supportedLocales,
+                String supportedLocalesStr,
                 boolean languageIndependent) {
             mFile = Preconditions.checkNotNull(file);
             mVersion = version;
             mSupportedLocales = Preconditions.checkNotNull(supportedLocales);
+            mSupportedLocalesStr = Preconditions.checkNotNull(supportedLocalesStr);
             mLanguageIndependent = languageIndependent;
         }
 
@@ -237,6 +241,11 @@
             return Collections.unmodifiableList(mSupportedLocales);
         }
 
+        /** Returns the original supported locals string read from the model file. */
+        public String getSupportedLocalesStr() {
+            return mSupportedLocalesStr;
+        }
+
         /**
          * Returns if this model file is preferred to the given one.
          */
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 8f40a3e..323bf59 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -29,6 +29,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Pair;
+import android.view.textclassifier.ActionsModelParamsSupplier.ActionsModelParams;
 import android.view.textclassifier.intent.ClassificationIntentFactory;
 import android.view.textclassifier.intent.LabeledIntent;
 import android.view.textclassifier.intent.LegacyClassificationIntentFactory;
@@ -57,6 +58,7 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.function.Supplier;
 
 /**
  * Default implementation of the {@link TextClassifier} interface.
@@ -124,6 +126,7 @@
 
     private final ClassificationIntentFactory mClassificationIntentFactory;
     private final TemplateIntentFactory mTemplateIntentFactory;
+    private final Supplier<ActionsModelParams> mActionsModelParamsSupplier;
 
     public TextClassifierImpl(
             Context context, TextClassificationConstants settings, TextClassifier fallback) {
@@ -158,6 +161,15 @@
                 ? new TemplateClassificationIntentFactory(
                 mTemplateIntentFactory, new LegacyClassificationIntentFactory())
                 : new LegacyClassificationIntentFactory();
+        mActionsModelParamsSupplier = new ActionsModelParamsSupplier(mContext,
+                () -> {
+                    synchronized (mLock) {
+                        // Clear mActionsImpl here, so that we will create a new
+                        // ActionsSuggestionsModel object with the new flag in the next request.
+                        mActionsImpl = null;
+                        mActionModelInUse = null;
+                    }
+                });
     }
 
     public TextClassifierImpl(Context context, TextClassificationConstants settings) {
@@ -584,10 +596,14 @@
                 final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
                         new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY);
                 try {
-                    if (pfd != null) {
-                        mActionsImpl = new ActionsSuggestionsModel(pfd.getFd());
-                        mActionModelInUse = bestModel;
+                    if (pfd == null) {
+                        Log.d(LOG_TAG, "Failed to read the model file: " + bestModel.getPath());
+                        return null;
                     }
+                    ActionsModelParams params = mActionsModelParamsSupplier.get();
+                    mActionsImpl = new ActionsSuggestionsModel(
+                            pfd.getFd(), params.getSerializedPreconditions(bestModel));
+                    mActionModelInUse = bestModel;
                 } finally {
                     maybeCloseAndLogError(pfd);
                 }
diff --git a/core/jni/android_opengl_EGL15.cpp b/core/jni/android_opengl_EGL15.cpp
index 99bdce2..717b505 100644
--- a/core/jni/android_opengl_EGL15.cpp
+++ b/core/jni/android_opengl_EGL15.cpp
@@ -25,6 +25,7 @@
 #include <utils/misc.h>
 
 #include <assert.h>
+#include <vector>
 #include <EGL/egl.h>
 
 #include <ui/ANativeObjectBase.h>
@@ -206,6 +207,24 @@
     return _env->NewObject(cls, con, reinterpret_cast<jlong>(handle));
 }
 
+struct WrappedEGLAttribs {
+private:
+    std::vector<EGLAttrib> backing; // only for 32-bit
+public:
+    EGLAttrib *attribs;
+    WrappedEGLAttribs(): attribs(nullptr) { };
+    void init(jlong *array, jint size) {
+        if (sizeof(EGLAttrib) != sizeof(jlong)) {
+            for (jint i = 0; i < size; ++i) {
+                backing.push_back(array[i]);
+            }
+            attribs = backing.data();
+        } else {
+            attribs = (EGLAttrib*)array;
+        }
+    }
+};
+
 // --------------------------------------------------------------------------
 /* EGLSync eglCreateSync ( EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list ) */
 static jobject
@@ -216,9 +235,9 @@
     const char * _exceptionMessage = NULL;
     EGLSync _returnValue = (EGLSync) 0;
     EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
-    EGLAttrib *attrib_list_base = (EGLAttrib *) 0;
+    jlong *attrib_list_base = (jlong *) 0;
     jint _remaining;
-    EGLAttrib *attrib_list = (EGLAttrib *) 0;
+    WrappedEGLAttribs attrib_list;
 
     if (!attrib_list_ref) {
         _exception = 1;
@@ -233,14 +252,14 @@
         goto exit;
     }
     _remaining = _env->GetArrayLength(attrib_list_ref) - offset;
-    attrib_list_base = (EGLAttrib *)
+    attrib_list_base = (jlong *)
         _env->GetLongArrayElements(attrib_list_ref, (jboolean *)0);
-    attrib_list = attrib_list_base + offset;
+    attrib_list.init(attrib_list_base + offset, _remaining);
 
     _returnValue = eglCreateSync(
         (EGLDisplay)dpy_native,
         (EGLenum)type,
-        (EGLAttrib *)attrib_list
+        attrib_list.attribs
     );
 
 exit:
@@ -255,6 +274,59 @@
     return toEGLHandle(_env, eglsyncClass, eglsyncConstructor, _returnValue);
 }
 
+/* EGLBoolean eglGetSyncAttrib ( EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value ) */
+static jboolean
+android_eglGetSyncAttrib
+  (JNIEnv *_env, jobject _this, jobject dpy, jobject sync, jint attribute, jlongArray value_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    EGLBoolean _returnValue = (EGLBoolean) 0;
+    EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+    EGLSync sync_native = (EGLSync) fromEGLHandle(_env, eglsyncGetHandleID, sync);
+    jlong *value_base = (jlong *) 0;
+    jint _remaining;
+    EGLAttrib value;
+
+    if (!value_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(value_ref) - offset;
+    value_base = (jlong *)
+        _env->GetLongArrayElements(value_ref, (jboolean *)0);
+
+    _returnValue = eglGetSyncAttrib(
+        (EGLDisplay)dpy_native,
+        (EGLSync)sync_native,
+        (EGLint)attribute,
+        &value
+    );
+
+    if (value_base && _returnValue == EGL_TRUE) {
+        *(value_base + offset) = (jlong) value;
+    }
+
+exit:
+    if (value_base) {
+        _env->ReleaseLongArrayElements(value_ref, (jlong*)value_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+        return JNI_FALSE;
+    }
+    return (jboolean)_returnValue;
+}
+
 /* EGLBoolean eglDestroySync ( EGLDisplay dpy, EGLSync sync ) */
 static jboolean
 android_eglDestroySync
@@ -287,56 +359,6 @@
     return (jint)_returnValue;
 }
 
-/* EGLBoolean eglGetSyncAttrib ( EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value ) */
-static jboolean
-android_eglGetSyncAttrib
-  (JNIEnv *_env, jobject _this, jobject dpy, jobject sync, jint attribute, jlongArray value_ref, jint offset) {
-    jint _exception = 0;
-    const char * _exceptionType = NULL;
-    const char * _exceptionMessage = NULL;
-    EGLBoolean _returnValue = (EGLBoolean) 0;
-    EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
-    EGLSync sync_native = (EGLSync) fromEGLHandle(_env, eglsyncGetHandleID, sync);
-    EGLAttrib *value_base = (EGLAttrib *) 0;
-    jint _remaining;
-    EGLAttrib *value = (EGLAttrib *) 0;
-
-    if (!value_ref) {
-        _exception = 1;
-        _exceptionType = "java/lang/IllegalArgumentException";
-        _exceptionMessage = "value == null";
-        goto exit;
-    }
-    if (offset < 0) {
-        _exception = 1;
-        _exceptionType = "java/lang/IllegalArgumentException";
-        _exceptionMessage = "offset < 0";
-        goto exit;
-    }
-    _remaining = _env->GetArrayLength(value_ref) - offset;
-    value_base = (EGLAttrib *)
-        _env->GetLongArrayElements(value_ref, (jboolean *)0);
-    value = value_base + offset;
-
-    _returnValue = eglGetSyncAttrib(
-        (EGLDisplay)dpy_native,
-        (EGLSync)sync_native,
-        (EGLint)attribute,
-        (EGLAttrib *)value
-    );
-
-exit:
-    if (value_base) {
-        _env->ReleaseLongArrayElements(value_ref, (jlong*)value_base,
-            _exception ? JNI_ABORT: 0);
-    }
-    if (_exception) {
-        jniThrowException(_env, _exceptionType, _exceptionMessage);
-        return JNI_FALSE;
-    }
-    return (jboolean)_returnValue;
-}
-
 /* EGLDisplay eglGetPlatformDisplay ( EGLenum platform, EGLAttrib native_display, const EGLAttrib *attrib_list ) */
 static jobject
 android_eglGetPlatformDisplay
@@ -345,9 +367,9 @@
     const char * _exceptionType = NULL;
     const char * _exceptionMessage = NULL;
     EGLDisplay _returnValue = (EGLDisplay) 0;
-    EGLAttrib *attrib_list_base = (EGLAttrib *) 0;
+    jlong *attrib_list_base = (jlong *) 0;
     jint _remaining;
-    EGLAttrib *attrib_list = (EGLAttrib *) 0;
+    WrappedEGLAttribs attrib_list;
 
     if (!attrib_list_ref) {
         _exception = 1;
@@ -362,14 +384,14 @@
         goto exit;
     }
     _remaining = _env->GetArrayLength(attrib_list_ref) - offset;
-    attrib_list_base = (EGLAttrib *)
+    attrib_list_base = (jlong *)
         _env->GetLongArrayElements(attrib_list_ref, (jboolean *)0);
-    attrib_list = attrib_list_base + offset;
+    attrib_list.init(attrib_list_base + offset, _remaining);
 
     _returnValue = eglGetPlatformDisplay(
         (EGLenum)platform,
         (void *)native_display,
-        (EGLAttrib *)attrib_list
+        attrib_list.attribs
     );
 
 exit:
@@ -398,9 +420,9 @@
     EGLConfig config_native = (EGLConfig) fromEGLHandle(_env, eglconfigGetHandleID, config);
     jint _native_windowRemaining;
     void *native_window = (void *) 0;
-    EGLAttrib *attrib_list_base = (EGLAttrib *) 0;
+    jlong *attrib_list_base = (jlong *) 0;
     jint _attrib_listRemaining;
-    EGLAttrib *attrib_list = (EGLAttrib *) 0;
+    WrappedEGLAttribs attrib_list;
 
     if (!native_window_buf) {
         _exception = 1;
@@ -422,9 +444,9 @@
         goto exit;
     }
     _attrib_listRemaining = _env->GetArrayLength(attrib_list_ref) - offset;
-    attrib_list_base = (EGLAttrib *)
+    attrib_list_base = (jlong *)
         _env->GetLongArrayElements(attrib_list_ref, (jboolean *)0);
-    attrib_list = attrib_list_base + offset;
+    attrib_list.init(attrib_list_base + offset, _attrib_listRemaining);
 
     if (native_window == NULL) {
         char * _native_windowBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
@@ -434,7 +456,7 @@
         (EGLDisplay)dpy_native,
         (EGLConfig)config_native,
         (void *)native_window,
-        (EGLAttrib *)attrib_list
+        attrib_list.attribs
     );
 
 exit:
@@ -487,9 +509,9 @@
     EGLImage _returnValue = (EGLImage) 0;
     EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
     EGLContext context_native = (EGLContext) fromEGLHandle(_env, eglcontextGetHandleID, context);
-    EGLAttrib *attrib_list_base = (EGLAttrib *) 0;
+    jlong *attrib_list_base = (jlong *) 0;
     jint _remaining;
-    EGLAttrib *attrib_list = (EGLAttrib *) 0;
+    WrappedEGLAttribs attrib_list;
 
     if (!attrib_list_ref) {
         _exception = 1;
@@ -504,16 +526,16 @@
         goto exit;
     }
     _remaining = _env->GetArrayLength(attrib_list_ref) - offset;
-    attrib_list_base = (EGLAttrib *)
+    attrib_list_base = (jlong *)
         _env->GetLongArrayElements(attrib_list_ref, (jboolean *)0);
-    attrib_list = attrib_list_base + offset;
+    attrib_list.init(attrib_list_base + offset, _remaining);
 
     _returnValue = eglCreateImage(
         (EGLDisplay)dpy_native,
         (EGLContext)context_native,
         (EGLenum)target,
         (EGLClientBuffer)buffer,
-        (EGLAttrib *)attrib_list
+        attrib_list.attribs
     );
 
 exit:
@@ -527,7 +549,6 @@
     }
     return toEGLHandle(_env, eglimageClass, eglimageConstructor, _returnValue);
 }
-
 /* EGLBoolean eglDestroyImage ( EGLDisplay dpy, EGLImage image ) */
 static jboolean
 android_eglDestroyImage
@@ -548,9 +569,9 @@
 static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"eglCreateSync", "(Landroid/opengl/EGLDisplay;I[JI)Landroid/opengl/EGLSync;", (void *) android_eglCreateSync },
+{"eglGetSyncAttrib", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSync;I[JI)Z", (void *) android_eglGetSyncAttrib },
 {"eglDestroySync", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSync;)Z", (void *) android_eglDestroySync },
 {"eglClientWaitSync", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSync;IJ)I", (void *) android_eglClientWaitSync },
-{"eglGetSyncAttrib", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSync;I[JI)Z", (void *) android_eglGetSyncAttrib },
 {"eglGetPlatformDisplay", "(IJ[JI)Landroid/opengl/EGLDisplay;", (void *) android_eglGetPlatformDisplay },
 {"eglCreatePlatformWindowSurface", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLConfig;Ljava/nio/Buffer;[JI)Landroid/opengl/EGLSurface;", (void *) android_eglCreatePlatformWindowSurface },
 {"eglCreatePlatformPixmapSurface", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLConfig;Ljava/nio/Buffer;[JI)Landroid/opengl/EGLSurface;", (void *) android_eglCreatePlatformPixmapSurface },
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 430b9c5..f599913 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -73,6 +73,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <cutils/ashmem.h>
 #include <cutils/fs.h>
 #include <cutils/multiuser.h>
 #include <private/android_filesystem_config.h>
@@ -1925,6 +1926,11 @@
   if (!SetTaskProfiles(0, {})) {
     ZygoteFailure(env, "zygote", nullptr, "Zygote SetTaskProfiles failed");
   }
+
+  /*
+   * ashmem initialization to avoid dlopen overhead
+   */
+  ashmem_init();
 }
 
 /**
diff --git a/core/tests/coretests/src/android/view/textclassifier/ActionsModelParamsSupplierTest.java b/core/tests/coretests/src/android/view/textclassifier/ActionsModelParamsSupplierTest.java
new file mode 100644
index 0000000..8744997
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textclassifier/ActionsModelParamsSupplierTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.textclassifier;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.Locale;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ActionsModelParamsSupplierTest {
+
+    @Test
+    public void getSerializedPreconditions_validActionsModelParams() {
+        ModelFileManager.ModelFile modelFile = new ModelFileManager.ModelFile(
+                new File("/model/file"),
+                200 /* version */,
+                Collections.singletonList(Locale.forLanguageTag("en")),
+                "en",
+                false);
+        byte[] serializedPreconditions = new byte[]{0x12, 0x24, 0x36};
+        ActionsModelParamsSupplier.ActionsModelParams params =
+                new ActionsModelParamsSupplier.ActionsModelParams(
+                        200 /* version */,
+                        "en",
+                        serializedPreconditions);
+
+        byte[] actual = params.getSerializedPreconditions(modelFile);
+
+        assertThat(actual).isEqualTo(serializedPreconditions);
+    }
+
+    @Test
+    public void getSerializedPreconditions_invalidVersion() {
+        ModelFileManager.ModelFile modelFile = new ModelFileManager.ModelFile(
+                new File("/model/file"),
+                201 /* version */,
+                Collections.singletonList(Locale.forLanguageTag("en")),
+                "en",
+                false);
+        byte[] serializedPreconditions = new byte[]{0x12, 0x24, 0x36};
+        ActionsModelParamsSupplier.ActionsModelParams params =
+                new ActionsModelParamsSupplier.ActionsModelParams(
+                        200 /* version */,
+                        "en",
+                        serializedPreconditions);
+
+        byte[] actual = params.getSerializedPreconditions(modelFile);
+
+        assertThat(actual).isNull();
+    }
+
+    @Test
+    public void getSerializedPreconditions_invalidLocales() {
+        final String LANGUAGE_TAG = "zh";
+        ModelFileManager.ModelFile modelFile = new ModelFileManager.ModelFile(
+                new File("/model/file"),
+                200 /* version */,
+                Collections.singletonList(Locale.forLanguageTag(LANGUAGE_TAG)),
+                LANGUAGE_TAG,
+                false);
+        byte[] serializedPreconditions = new byte[]{0x12, 0x24, 0x36};
+        ActionsModelParamsSupplier.ActionsModelParams params =
+                new ActionsModelParamsSupplier.ActionsModelParams(
+                        200 /* version */,
+                        "en",
+                        serializedPreconditions);
+
+        byte[] actual = params.getSerializedPreconditions(modelFile);
+
+        assertThat(actual).isNull();
+    }
+
+}
diff --git a/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java
index 74b8e3b..79e1406 100644
--- a/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java
@@ -86,7 +86,7 @@
     public void get() {
         ModelFileManager.ModelFile modelFile =
                 new ModelFileManager.ModelFile(
-                        new File("/path/a"), 1, Collections.emptyList(), true);
+                        new File("/path/a"), 1, Collections.emptyList(), "", true);
         when(mModelFileSupplier.get()).thenReturn(Collections.singletonList(modelFile));
 
         List<ModelFileManager.ModelFile> modelFiles = mModelFileManager.listModelFiles();
@@ -100,12 +100,12 @@
         ModelFileManager.ModelFile olderModelFile =
                 new ModelFileManager.ModelFile(
                         new File("/path/a"), 1,
-                        Collections.emptyList(), true);
+                        Collections.emptyList(), "", true);
 
         ModelFileManager.ModelFile newerModelFile =
                 new ModelFileManager.ModelFile(
                         new File("/path/b"), 2,
-                        Collections.emptyList(), true);
+                        Collections.emptyList(), "", true);
         when(mModelFileSupplier.get())
                 .thenReturn(Arrays.asList(olderModelFile, newerModelFile));
 
@@ -121,12 +121,12 @@
         ModelFileManager.ModelFile languageIndependentModelFile =
                 new ModelFileManager.ModelFile(
                         new File("/path/a"), 1,
-                        Collections.emptyList(), true);
+                        Collections.emptyList(), "", true);
 
         ModelFileManager.ModelFile languageDependentModelFile =
                 new ModelFileManager.ModelFile(
                         new File("/path/b"), 1,
-                        Collections.singletonList(locale), false);
+                        Collections.singletonList(locale), locale.toLanguageTag(), false);
         when(mModelFileSupplier.get())
                 .thenReturn(
                         Arrays.asList(languageIndependentModelFile, languageDependentModelFile));
@@ -143,12 +143,12 @@
         ModelFileManager.ModelFile languageIndependentModelFile =
                 new ModelFileManager.ModelFile(
                         new File("/path/a"), 1,
-                        Collections.emptyList(), true);
+                        Collections.emptyList(), "", true);
 
         ModelFileManager.ModelFile languageDependentModelFile =
                 new ModelFileManager.ModelFile(
                         new File("/path/b"), 1,
-                        Collections.singletonList(locale), false);
+                        Collections.singletonList(locale), locale.toLanguageTag(), false);
 
         when(mModelFileSupplier.get())
                 .thenReturn(
@@ -165,12 +165,13 @@
         ModelFileManager.ModelFile languageIndependentModelFile =
                 new ModelFileManager.ModelFile(
                         new File("/path/a"), 1,
-                        Collections.emptyList(), true);
+                        Collections.emptyList(), "", true);
 
         ModelFileManager.ModelFile languageDependentModelFile =
                 new ModelFileManager.ModelFile(
                         new File("/path/b"), 1,
-                        Collections.singletonList(DEFAULT_LOCALE), false);
+                        Collections.singletonList(
+                                DEFAULT_LOCALE), DEFAULT_LOCALE.toLanguageTag(), false);
 
         when(mModelFileSupplier.get())
                 .thenReturn(
@@ -187,12 +188,12 @@
         ModelFileManager.ModelFile matchButOlderModel =
                 new ModelFileManager.ModelFile(
                         new File("/path/a"), 1,
-                        Collections.singletonList(Locale.forLanguageTag("fr")), false);
+                        Collections.singletonList(Locale.forLanguageTag("fr")), "fr", false);
 
         ModelFileManager.ModelFile mismatchButNewerModel =
                 new ModelFileManager.ModelFile(
                         new File("/path/b"), 2,
-                        Collections.singletonList(Locale.forLanguageTag("ja")), false);
+                        Collections.singletonList(Locale.forLanguageTag("ja")), "ja", false);
 
         when(mModelFileSupplier.get())
                 .thenReturn(
@@ -209,12 +210,12 @@
         ModelFileManager.ModelFile matchLocaleModel =
                 new ModelFileManager.ModelFile(
                         new File("/path/b"), 1,
-                        Collections.singletonList(Locale.forLanguageTag("ja")), false);
+                        Collections.singletonList(Locale.forLanguageTag("ja")), "ja", false);
 
         ModelFileManager.ModelFile languageIndependentModel =
                 new ModelFileManager.ModelFile(
                         new File("/path/a"), 2,
-                        Collections.emptyList(), true);
+                        Collections.emptyList(), "", true);
         when(mModelFileSupplier.get())
                 .thenReturn(
                         Arrays.asList(matchLocaleModel, languageIndependentModel));
@@ -231,12 +232,12 @@
         ModelFileManager.ModelFile modelA =
                 new ModelFileManager.ModelFile(
                         new File("/path/a"), 1,
-                        Collections.singletonList(Locale.forLanguageTag("ja")), false);
+                        Collections.singletonList(Locale.forLanguageTag("ja")), "ja", false);
 
         ModelFileManager.ModelFile modelB =
                 new ModelFileManager.ModelFile(
                         new File("/path/a"), 1,
-                        Collections.singletonList(Locale.forLanguageTag("ja")), false);
+                        Collections.singletonList(Locale.forLanguageTag("ja")), "ja", false);
 
         assertThat(modelA).isEqualTo(modelB);
     }
@@ -246,12 +247,12 @@
         ModelFileManager.ModelFile modelA =
                 new ModelFileManager.ModelFile(
                         new File("/path/a"), 1,
-                        Collections.singletonList(Locale.forLanguageTag("ja")), false);
+                        Collections.singletonList(Locale.forLanguageTag("ja")), "ja", false);
 
         ModelFileManager.ModelFile modelB =
                 new ModelFileManager.ModelFile(
                         new File("/path/b"), 1,
-                        Collections.singletonList(Locale.forLanguageTag("ja")), false);
+                        Collections.singletonList(Locale.forLanguageTag("ja")), "ja", false);
 
         assertThat(modelA).isNotEqualTo(modelB);
     }
@@ -262,7 +263,7 @@
         ModelFileManager.ModelFile modelA =
                 new ModelFileManager.ModelFile(
                         new File("/path/a"), 1,
-                        Collections.singletonList(Locale.forLanguageTag("ja")), false);
+                        Collections.singletonList(Locale.forLanguageTag("ja")), "ja", false);
 
         assertThat(modelA.getPath()).isEqualTo("/path/a");
     }
@@ -272,7 +273,7 @@
         ModelFileManager.ModelFile modelA =
                 new ModelFileManager.ModelFile(
                         new File("/path/a"), 1,
-                        Collections.singletonList(Locale.forLanguageTag("ja")), false);
+                        Collections.singletonList(Locale.forLanguageTag("ja")), "ja", false);
 
         assertThat(modelA.getName()).isEqualTo("a");
     }
@@ -282,12 +283,12 @@
         ModelFileManager.ModelFile modelA =
                 new ModelFileManager.ModelFile(
                         new File("/path/a"), 1,
-                        Collections.singletonList(Locale.forLanguageTag("ja")), false);
+                        Collections.singletonList(Locale.forLanguageTag("ja")), "ja", false);
 
         ModelFileManager.ModelFile modelB =
                 new ModelFileManager.ModelFile(
                         new File("/path/b"), 2,
-                        Collections.emptyList(), true);
+                        Collections.emptyList(), "", true);
 
         assertThat(modelA.isPreferredTo(modelB)).isTrue();
     }
@@ -297,12 +298,12 @@
         ModelFileManager.ModelFile modelA =
                 new ModelFileManager.ModelFile(
                         new File("/path/a"), 2,
-                        Collections.singletonList(Locale.forLanguageTag("ja")), false);
+                        Collections.singletonList(Locale.forLanguageTag("ja")), "ja", false);
 
         ModelFileManager.ModelFile modelB =
                 new ModelFileManager.ModelFile(
                         new File("/path/b"), 1,
-                        Collections.emptyList(), false);
+                        Collections.emptyList(), "", false);
 
         assertThat(modelA.isPreferredTo(modelB)).isTrue();
     }
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 55f1911..3a33678 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -558,7 +558,7 @@
         private int mContentType = CONTENT_TYPE_UNKNOWN;
         private int mSource = MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID;
         private int mFlags = 0x0;
-        private boolean mMuteHapticChannels = false;
+        private boolean mMuteHapticChannels = true;
         private HashSet<String> mTags = new HashSet<String>();
         private Bundle mBundle;
 
@@ -889,7 +889,7 @@
 
         /**
          * Specifying if haptic should be muted or not when playing audio-haptic coupled data.
-         * By default, haptic channels are enabled.
+         * By default, haptic channels are disabled.
          * @param muted true to force muting haptic channels.
          * @return the same Builder instance.
          */
diff --git a/media/java/android/media/audiopolicy/AudioProductStrategy.java b/media/java/android/media/audiopolicy/AudioProductStrategy.java
index 48500e01..c1c255f 100644
--- a/media/java/android/media/audiopolicy/AudioProductStrategy.java
+++ b/media/java/android/media/audiopolicy/AudioProductStrategy.java
@@ -262,7 +262,7 @@
                 || (attr.getContentType() == refAttr.getContentType()))
             && ((refAttr.getAllFlags() == 0)
                 || (attr.getAllFlags() != 0
-                && (attr.getAllFlags() & refAttr.getAllFlags()) == attr.getAllFlags()))
+                && (attr.getAllFlags() & refAttr.getAllFlags()) == refAttr.getAllFlags()))
             && ((refFormattedTags.length() == 0) || refFormattedTags.equals(cliFormattedTags));
     }
 
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 5c3d780..04545e8 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -93,7 +93,7 @@
 
     shared_libs: [
         "liblog",
-        "libmedia_omx",
+        "libgui",
         "libnativewindow",
         "libui",
         "libutils",
diff --git a/opengl/java/android/opengl/EGL15.java b/opengl/java/android/opengl/EGL15.java
index bd845e7..93acc67 100644
--- a/opengl/java/android/opengl/EGL15.java
+++ b/opengl/java/android/opengl/EGL15.java
@@ -85,6 +85,19 @@
         int offset
     );
 
+    /**
+    * C function EGLBoolean eglGetSyncAttrib ( EGLDisplay dpy, EGLSync sync, EGLint attribute,
+    *                                          EGLAttrib *value )
+    */
+
+    public static native boolean eglGetSyncAttrib(
+            EGLDisplay dpy,
+            EGLSync sync,
+            int attribute,
+            long[] value,
+            int offset
+    );
+
     // C function EGLBoolean eglDestroySync ( EGLDisplay dpy, EGLSync sync )
 
     public static native boolean eglDestroySync(
@@ -101,16 +114,6 @@
         long timeout
     );
 
-    // C function EGLBoolean eglGetSyncAttrib ( EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value )
-
-    public static native boolean eglGetSyncAttrib(
-        EGLDisplay dpy,
-        EGLSync sync,
-        int attribute,
-        long[] value,
-        int offset
-    );
-
     // C function EGLDisplay eglGetPlatformDisplay ( EGLenum platform, EGLAttrib native_display, const EGLAttrib *attrib_list )
 
     public static native EGLDisplay eglGetPlatformDisplay(
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index b1998c4..00b1c9e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -64,6 +64,8 @@
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * Renders bubbles in a stack and handles animating expanded and collapsed states.
@@ -164,6 +166,8 @@
     int[] mTempLoc = new int[2];
     RectF mTempRect = new RectF();
 
+    private final List<Rect> mSystemGestureExclusionRects = Collections.singletonList(new Rect());
+
     private ViewTreeObserver.OnPreDrawListener mViewUpdater =
             new ViewTreeObserver.OnPreDrawListener() {
                 @Override
@@ -175,6 +179,9 @@
                 }
             };
 
+    private ViewTreeObserver.OnDrawListener mSystemGestureExcludeUpdater =
+            this::updateSystemGestureExcludeRects;
+
     private ViewClippingUtil.ClippingParameters mClippingParameters =
             new ViewClippingUtil.ClippingParameters() {
 
@@ -296,6 +303,9 @@
                     () -> mExpandedBubble.expandedView.updateInsets(insets));
             return view.onApplyWindowInsets(insets);
         });
+
+        // This must be a separate OnDrawListener since it should be called for every draw.
+        getViewTreeObserver().addOnDrawListener(mSystemGestureExcludeUpdater);
     }
 
     /**
@@ -362,6 +372,22 @@
         return false;
     }
 
+    private void updateSystemGestureExcludeRects() {
+        // Exclude the region occupied by the first BubbleView in the stack
+        Rect excludeZone = mSystemGestureExclusionRects.get(0);
+        if (mBubbleContainer.getChildCount() > 0) {
+            View firstBubble = mBubbleContainer.getChildAt(0);
+            excludeZone.set(firstBubble.getLeft(), firstBubble.getTop(), firstBubble.getRight(),
+                    firstBubble.getBottom());
+            excludeZone.offset((int) (firstBubble.getTranslationX() + 0.5f),
+                    (int) (firstBubble.getTranslationY() + 0.5f));
+            mBubbleContainer.setSystemGestureExclusionRects(mSystemGestureExclusionRects);
+        } else {
+            excludeZone.setEmpty();
+            mBubbleContainer.setSystemGestureExclusionRects(Collections.emptyList());
+        }
+    }
+
     /**
      * Updates the visibility of the 'dot' indicating an update on the bubble.
      * @param key the {@link NotificationEntry#key} associated with the bubble.
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index bd72976..c256fb2 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -956,6 +956,9 @@
     // The NetworkAgent Wifi usability score has changed in a way that may
     // impact connectivity
     TYPE_WIFI_USABILITY_SCORE_BREACH = 20;
+
+    // Link probe was performed
+    TYPE_LINK_PROBE = 21;
   }
 
   enum FrameworkDisconnectReason {
@@ -1077,6 +1080,18 @@
   // Prediction horizon (in second) of Wifi usability score provided by external
   // system app
   optional int32 last_prediction_horizon_sec = 16 [default = -1];
+
+  // Only valid if event type == TYPE_LINK_PROBE.
+  // true if link probe succeeded, false otherwise.
+  optional bool link_probe_was_success = 17;
+
+  // Only valid if event type == TYPE_LINK_PROBE and link_probe_was_success == true.
+  // Elapsed time, in milliseconds, of a successful link probe.
+  optional int32 link_probe_success_elapsed_time_ms = 18;
+
+  // Only valid if event type == TYPE_LINK_PROBE and link_probe_was_success == false.
+  // Failure reason for an unsuccessful link probe.
+  optional LinkProbeStats.LinkProbeFailureReason link_probe_failure_reason = 19;
 }
 
 // Wi-Fi Aware metrics
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e7dac9d..0f4e123 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2362,33 +2362,6 @@
     }
 
     /**
-     * Used to obtain task ID when user taps on coordinate (x, y) in this display, and outside
-     * current task in focus.
-     *
-     * This returns the task ID of the foremost task at (x, y) if the task is not home. Otherwise it
-     * returns -1.
-     *
-     * @param x horizontal coordinate of the tap position
-     * @param y vertical coordinate of the tap position
-     * @return the task ID if a non-home task is found; -1 if not
-     */
-    int taskForTapOutside(int x, int y) {
-        for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-            final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
-            if (stack.isActivityTypeHome() && !stack.inMultiWindowMode()) {
-                // We skip not only home stack, but also everything behind home because user can't
-                // see them when home stack is isn't in multi-window mode.
-                break;
-            }
-            final int taskId = stack.taskIdFromPoint(x, y);
-            if (taskId != -1) {
-                return taskId;
-            }
-        }
-        return -1;
-    }
-
-    /**
      * Returns true if the input point is within an app window.
      */
     boolean pointWithinAppWindow(int x, int y) {
diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java
index cdcb857..3929a12 100644
--- a/services/core/java/com/android/server/wm/TaskPositioningController.java
+++ b/services/core/java/com/android/server/wm/TaskPositioningController.java
@@ -127,7 +127,6 @@
 
     void handleTapOutsideTask(DisplayContent displayContent, int x, int y) {
         mHandler.post(() -> {
-            int taskId = -1;
             synchronized (mService.mGlobalLock) {
                 final Task task = displayContent.findTaskForResizePoint(x, y);
                 if (task != null) {
@@ -135,15 +134,10 @@
                             task.preserveOrientationOnResize(), x, y)) {
                         return;
                     }
-                    taskId = task.mTaskId;
-                } else {
-                    taskId = displayContent.taskForTapOutside(x, y);
-                }
-            }
-            if (taskId >= 0) {
-                try {
-                    mActivityManager.setFocusedTask(taskId);
-                } catch (RemoteException e) {
+                    try {
+                        mActivityManager.setFocusedTask(task.mTaskId);
+                    } catch (RemoteException e) {
+                    }
                 }
             }
         });
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index e6b8112..09baf8c 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1458,31 +1458,6 @@
         return false;
     }
 
-    int taskIdFromPoint(int x, int y) {
-        getBounds(mTmpRect);
-        if (!mTmpRect.contains(x, y) || isAdjustedForMinimizedDockedStack()) {
-            return -1;
-        }
-
-        for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = mChildren.get(taskNdx);
-            final WindowState win = task.getTopVisibleAppMainWindow();
-            if (win == null) {
-                continue;
-            }
-            // We need to use the task's dim bounds (which is derived from the visible bounds of its
-            // apps windows) for any touch-related tests. Can't use the task's original bounds
-            // because it might be adjusted to fit the content frame. For example, the presence of
-            // the IME adjusting the windows frames when the app window is the IME target.
-            task.getDimBounds(mTmpRect);
-            if (mTmpRect.contains(x, y)) {
-                return task.mTaskId;
-            }
-        }
-
-        return -1;
-    }
-
     void findTaskForResizePoint(int x, int y, int delta,
             DisplayContent.TaskForResizePointSearchResult results) {
         if (!getWindowConfiguration().canResizeTask()) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8dfb02e..ce496f4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7587,12 +7587,36 @@
             return;
         }
 
-        final DisplayContent displayContent = touchedWindow.getDisplayContent();
+        handleTaskFocusChange(touchedWindow.getTask());
+        handleDisplayFocusChange(touchedWindow);
+    }
+
+    private void handleTaskFocusChange(Task task) {
+        if (task == null) {
+            return;
+        }
+
+        final TaskStack stack = task.mStack;
+        // We ignore home stack since we don't want home stack to move to front when touched.
+        // Specifically, in freeform we don't want tapping on home to cause the freeform apps to go
+        // behind home. See b/117376413
+        if (stack.isActivityTypeHome()) {
+            return;
+        }
+
+        try {
+            mActivityTaskManager.setFocusedTask(task.mTaskId);
+        } catch (RemoteException e) {
+        }
+    }
+
+    private void handleDisplayFocusChange(WindowState window) {
+        final DisplayContent displayContent = window.getDisplayContent();
         if (displayContent == null) {
             return;
         }
 
-        if (!touchedWindow.canReceiveKeys()) {
+        if (!window.canReceiveKeys()) {
             // If the window that received the input event cannot receive keys, don't move the
             // display it's on to the top since that window won't be able to get focus anyway.
             return;
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index b0a2055..49909f6 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -367,6 +367,7 @@
 
   application_action["uses-library"].Action(RequiredNameIsNotEmpty);
   application_action["library"].Action(RequiredNameIsNotEmpty);
+  application_action["profileable"];
 
   xml::XmlNodeAction& static_library_action = application_action["static-library"];
   static_library_action.Action(RequiredNameIsJavaPackage);
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index 4842f62..3f1ee36 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -671,6 +671,24 @@
       {}, "application", xml::kSchemaAndroid, "debuggable", "true"), NotNull());
 }
 
+TEST_F(ManifestFixerTest, ApplicationProfileable) {
+  std::string shell = R"(
+      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android">
+        <application>
+          <profileable android:shell="true"/>
+        </application>
+      </manifest>)";
+  EXPECT_THAT(Verify(shell), NotNull());
+  std::string noshell = R"(
+      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android">
+        <application>
+          <profileable/>
+        </application>
+      </manifest>)";
+  EXPECT_THAT(Verify(noshell), NotNull());
+}
 
 TEST_F(ManifestFixerTest, IgnoreNamespacedElements) {
   std::string input = R"EOF(