Merge "Remove an extra line in a comment."
diff --git a/Android.bp b/Android.bp
index 80f1c37..2dc1cc3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12,6 +12,19 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+// Build ext.jar
+// ============================================================
+java_library {
+    name: "ext",
+    no_framework_libs: true,
+    static_libs: [
+        "libphonenumber-platform",
+        "nist-sip",
+        "tagsoup",
+    ],
+    dxflags: ["--core-library"],
+}
+
 // ====  c++ proto device library  ==============================
 cc_library {
     name: "libplatformprotos",
@@ -21,6 +34,11 @@
         include_dirs: ["external/protobuf/src"],
     },
 
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+    ],
     target: {
         host: {
             proto: {
diff --git a/Android.mk b/Android.mk
index 6186c55..6470e34 100644
--- a/Android.mk
+++ b/Android.mk
@@ -570,6 +570,7 @@
 	../../system/update_engine/binder_bindings/android/os/IUpdateEngineCallback.aidl \
 
 LOCAL_SRC_FILES += \
+	../../system/core/storaged/binder/android/os/IStoraged.aidl \
 	../../system/netd/server/binder/android/net/INetd.aidl \
 	../../system/vold/binder/android/os/IVold.aidl \
 	../../system/vold/binder/android/os/IVoldListener.aidl \
@@ -587,6 +588,17 @@
 	lowpan/java/android/net/lowpan/ILowpanManagerListener.aidl \
 	lowpan/java/android/net/lowpan/ILowpanManager.aidl
 
+# StatsLog generated functions
+statslog_src_dir := $(call intermediates-dir-for,JAVA_LIBRARIES,framework,,COMMON)/statslog
+gen := $(statslog_src_dir)/android/util/StatsLog.java
+$(gen): PRIVATE_PATH := $(LOCAL_PATH)
+$(gen): PRIVATE_CUSTOM_TOOL = $(HOST_OUT_EXECUTABLES)/stats-log-api-gen --java $@
+$(gen): $(HOST_OUT_EXECUTABLES)/stats-log-api-gen
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(gen)
+statslog_src_dir:=
+gen:=
+
 # FRAMEWORKS_BASE_JAVA_SRC_DIRS comes from build/core/pathmap.mk
 LOCAL_AIDL_INCLUDES += \
       $(FRAMEWORKS_BASE_JAVA_SRC_DIRS) \
@@ -597,6 +609,7 @@
 	frameworks/av/drm/libmediadrm/aidl \
 	frameworks/av/media/libaudioclient/aidl \
 	frameworks/native/aidl/gui \
+	system/core/storaged/binder \
 	system/netd/server/binder \
 	system/vold/binder \
 	system/bt/binder
@@ -637,6 +650,8 @@
 
 LOCAL_MODULE := framework
 
+LOCAL_JAVAC_SHARD_SIZE := 150
+
 LOCAL_DX_FLAGS := --core-library --multi-dex
 LOCAL_JACK_FLAGS := --multi-dex native
 
@@ -1527,35 +1542,6 @@
 
 include $(BUILD_DROIDDOC)
 
-# Build ext.jar
-# ============================================================
-
-ext_dirs := \
-	../../external/nist-sip/java \
-	../../external/tagsoup/src \
-
-ext_src_files := $(call all-java-files-under,$(ext_dirs))
-
-# ====  the library  =========================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(ext_src_files)
-
-LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart
-LOCAL_STATIC_JAVA_LIBRARIES := libphonenumber-platform
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE := ext
-
-LOCAL_DX_FLAGS := --core-library
-
-ifneq ($(INCREMENTAL_BUILDS),)
-    LOCAL_PROGUARD_ENABLED := disabled
-    LOCAL_JACK_ENABLED := incremental
-endif
-
-include $(BUILD_JAVA_LIBRARY)
-
 # ====  java proto host library  ==============================
 include $(CLEAR_VARS)
 LOCAL_MODULE := platformprotos
diff --git a/apct-tests/perftests/core/src/android/database/SQLiteDatabaseIoPerfTest.java b/apct-tests/perftests/core/src/android/database/SQLiteDatabaseIoPerfTest.java
new file mode 100644
index 0000000..7c5316d
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/database/SQLiteDatabaseIoPerfTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.database;
+
+import android.app.Activity;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.Bundle;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.internal.util.Preconditions;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Performance tests for measuring amount of data written during typical DB operations
+ *
+ * <p>To run: bit CorePerfTests:android.database.SQLiteDatabaseIoPerfTest
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class SQLiteDatabaseIoPerfTest {
+    private static final String TAG = "SQLiteDatabaseIoPerfTest";
+    private static final String DB_NAME = "db_io_perftest";
+    private static final int DEFAULT_DATASET_SIZE = 500;
+
+    private Long mWriteBytes;
+
+    private SQLiteDatabase mDatabase;
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mContext.deleteDatabase(DB_NAME);
+        mDatabase = mContext.openOrCreateDatabase(DB_NAME, Context.MODE_PRIVATE, null);
+        mDatabase.execSQL("CREATE TABLE T1 "
+                + "(_ID INTEGER PRIMARY KEY, COL_A INTEGER, COL_B VARCHAR(100), COL_C REAL)");
+    }
+
+    @After
+    public void tearDown() {
+        mDatabase.close();
+        mContext.deleteDatabase(DB_NAME);
+    }
+
+    @Test
+    public void testDatabaseModifications() {
+        startMeasuringWrites();
+        ContentValues cv = new ContentValues();
+        String[] whereArg = new String[1];
+        for (int i = 0; i < DEFAULT_DATASET_SIZE; i++) {
+            cv.put("_ID", i);
+            cv.put("COL_A", i);
+            cv.put("COL_B", "NewValue");
+            cv.put("COL_C", 1.0);
+            assertEquals(i, mDatabase.insert("T1", null, cv));
+        }
+        cv = new ContentValues();
+        for (int i = 0; i < DEFAULT_DATASET_SIZE; i++) {
+            cv.put("COL_B", "UpdatedValue");
+            cv.put("COL_C", 1.1);
+            whereArg[0] = String.valueOf(i);
+            assertEquals(1, mDatabase.update("T1", cv, "_ID=?", whereArg));
+        }
+        for (int i = 0; i < DEFAULT_DATASET_SIZE; i++) {
+            whereArg[0] = String.valueOf(i);
+            assertEquals(1, mDatabase.delete("T1", "_ID=?", whereArg));
+        }
+        // Make sure all changes are written to disk
+        mDatabase.close();
+        long bytes = endMeasuringWrites();
+        sendResults("testDatabaseModifications" , bytes);
+    }
+
+    @Test
+    public void testInsertsWithTransactions() {
+        startMeasuringWrites();
+        final int txSize = 10;
+        ContentValues cv = new ContentValues();
+        for (int i = 0; i < DEFAULT_DATASET_SIZE * 5; i++) {
+            if (i % txSize == 0) {
+                mDatabase.beginTransaction();
+            }
+            if (i % txSize == txSize-1) {
+                mDatabase.setTransactionSuccessful();
+                mDatabase.endTransaction();
+
+            }
+            cv.put("_ID", i);
+            cv.put("COL_A", i);
+            cv.put("COL_B", "NewValue");
+            cv.put("COL_C", 1.0);
+            assertEquals(i, mDatabase.insert("T1", null, cv));
+        }
+        // Make sure all changes are written to disk
+        mDatabase.close();
+        long bytes = endMeasuringWrites();
+        sendResults("testInsertsWithTransactions" , bytes);
+    }
+
+    private void startMeasuringWrites() {
+        Preconditions.checkState(mWriteBytes == null, "Measurement already started");
+        mWriteBytes = getIoStats().get("write_bytes");
+    }
+
+    private long endMeasuringWrites() {
+        Preconditions.checkState(mWriteBytes != null, "Measurement wasn't started");
+        Long newWriteBytes = getIoStats().get("write_bytes");
+        return newWriteBytes - mWriteBytes;
+    }
+
+    private void sendResults(String testName, long writeBytes) {
+        Log.i(TAG, testName + " write_bytes: " + writeBytes);
+        Bundle status = new Bundle();
+        status.putLong("write_bytes", writeBytes);
+        InstrumentationRegistry.getInstrumentation().sendStatus(Activity.RESULT_OK, status);
+    }
+
+    private static Map<String, Long> getIoStats() {
+        String ioStat = "/proc/self/io";
+        Map<String, Long> results = new ArrayMap<>();
+        try {
+            List<String> lines = Files.readAllLines(new File(ioStat).toPath());
+            for (String line : lines) {
+                line = line.trim();
+                String[] split = line.split(":");
+                if (split.length == 2) {
+                    try {
+                        String key = split[0].trim();
+                        Long value = Long.valueOf(split[1].trim());
+                        results.put(key, value);
+                    } catch (NumberFormatException e) {
+                        Log.e(TAG, "Cannot parse number from " + line);
+                    }
+                } else if (line.isEmpty()) {
+                    Log.e(TAG, "Cannot parse line " + line);
+                }
+            }
+        } catch (IOException e) {
+            Log.e(TAG, "Can't read: " + ioStat, e);
+        }
+        return results;
+    }
+
+}
diff --git a/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java b/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java
new file mode 100644
index 0000000..7a32c0c
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.database;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Random;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Performance tests for typical CRUD operations and loading rows into the Cursor
+ *
+ * <p>To run: bit CorePerfTests:android.database.SQLiteDatabasePerfTest
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class SQLiteDatabasePerfTest {
+    // TODO b/64262688 Add Concurrency tests to compare WAL vs DELETE read/write
+    private static final String DB_NAME = "dbperftest";
+    private static final int DEFAULT_DATASET_SIZE = 1000;
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+    private SQLiteDatabase mDatabase;
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mContext.deleteDatabase(DB_NAME);
+        mDatabase = mContext.openOrCreateDatabase(DB_NAME, Context.MODE_PRIVATE, null);
+        mDatabase.execSQL("CREATE TABLE T1 "
+                + "(_ID INTEGER PRIMARY KEY, COL_A INTEGER, COL_B VARCHAR(100), COL_C REAL)");
+        mDatabase.execSQL("CREATE TABLE T2 ("
+                + "_ID INTEGER PRIMARY KEY, COL_A VARCHAR(100), T1_ID INTEGER,"
+                + "FOREIGN KEY(T1_ID) REFERENCES T1 (_ID))");
+    }
+
+    @After
+    public void tearDown() {
+        mDatabase.close();
+        mContext.deleteDatabase(DB_NAME);
+    }
+
+    @Test
+    public void testSelect() {
+        insertT1TestDataSet();
+
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        Random rnd = new Random(0);
+        while (state.keepRunning()) {
+            int index = rnd.nextInt(DEFAULT_DATASET_SIZE);
+            try (Cursor cursor = mDatabase.rawQuery("SELECT _ID, COL_A, COL_B, COL_C FROM T1 "
+                    + "WHERE _ID=?", new String[]{String.valueOf(index)})) {
+                assertTrue(cursor.moveToNext());
+                assertEquals(index, cursor.getInt(0));
+                assertEquals(index, cursor.getInt(1));
+                assertEquals("T1Value" + index, cursor.getString(2));
+                assertEquals(1.1 * index, cursor.getDouble(3), 0.0000001d);
+            }
+        }
+    }
+
+    @Test
+    public void testSelectMultipleRows() {
+        insertT1TestDataSet();
+
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        Random rnd = new Random(0);
+        final int querySize = 50;
+        while (state.keepRunning()) {
+            int index = rnd.nextInt(DEFAULT_DATASET_SIZE - querySize - 1);
+            try (Cursor cursor = mDatabase.rawQuery("SELECT _ID, COL_A, COL_B, COL_C FROM T1 "
+                            + "WHERE _ID BETWEEN ? and ? ORDER BY _ID",
+                    new String[]{String.valueOf(index), String.valueOf(index + querySize - 1)})) {
+                int i = 0;
+                while(cursor.moveToNext()) {
+                    assertEquals(index, cursor.getInt(0));
+                    assertEquals(index, cursor.getInt(1));
+                    assertEquals("T1Value" + index, cursor.getString(2));
+                    assertEquals(1.1 * index, cursor.getDouble(3), 0.0000001d);
+                    index++;
+                    i++;
+                }
+                assertEquals(querySize, i);
+            }
+        }
+    }
+
+    @Test
+    public void testInnerJoin() {
+        mDatabase.setForeignKeyConstraintsEnabled(true);
+        mDatabase.beginTransaction();
+        insertT1TestDataSet();
+        insertT2TestDataSet();
+        mDatabase.setTransactionSuccessful();
+        mDatabase.endTransaction();
+
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        Random rnd = new Random(0);
+        while (state.keepRunning()) {
+            int index = rnd.nextInt(1000);
+            try (Cursor cursor = mDatabase.rawQuery(
+                    "SELECT T1._ID, T1.COL_A, T1.COL_B, T1.COL_C, T2.COL_A FROM T1 "
+                    + "INNER JOIN T2 on T2.T1_ID=T1._ID WHERE T1._ID = ?",
+                    new String[]{String.valueOf(index)})) {
+                assertTrue(cursor.moveToNext());
+                assertEquals(index, cursor.getInt(0));
+                assertEquals(index, cursor.getInt(1));
+                assertEquals("T1Value" + index, cursor.getString(2));
+                assertEquals(1.1 * index, cursor.getDouble(3), 0.0000001d);
+                assertEquals("T2Value" + index, cursor.getString(4));
+            }
+        }
+    }
+
+    @Test
+    public void testInsert() {
+        insertT1TestDataSet();
+
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        ContentValues cv = new ContentValues();
+        cv.put("_ID", DEFAULT_DATASET_SIZE);
+        cv.put("COL_B", "NewValue");
+        cv.put("COL_C", 1.1);
+        String[] deleteArgs = new String[]{String.valueOf(DEFAULT_DATASET_SIZE)};
+        while (state.keepRunning()) {
+            assertEquals(DEFAULT_DATASET_SIZE, mDatabase.insert("T1", null, cv));
+            state.pauseTiming();
+            assertEquals(1, mDatabase.delete("T1", "_ID=?", deleteArgs));
+            state.resumeTiming();
+        }
+    }
+
+    @Test
+    public void testDelete() {
+        insertT1TestDataSet();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        String[] deleteArgs = new String[]{String.valueOf(DEFAULT_DATASET_SIZE)};
+        Object[] insertsArgs = new Object[]{DEFAULT_DATASET_SIZE, DEFAULT_DATASET_SIZE,
+                "ValueToDelete", 1.1};
+
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            mDatabase.execSQL("INSERT INTO T1 VALUES (?, ?, ?, ?)", insertsArgs);
+            state.resumeTiming();
+            assertEquals(1, mDatabase.delete("T1", "_ID=?", deleteArgs));
+        }
+    }
+
+    @Test
+    public void testUpdate() {
+        insertT1TestDataSet();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        Random rnd = new Random(0);
+        int i = 0;
+        ContentValues cv = new ContentValues();
+        String[] argArray = new String[1];
+        while (state.keepRunning()) {
+            int id = rnd.nextInt(DEFAULT_DATASET_SIZE);
+            cv.put("COL_A", i);
+            cv.put("COL_B", "UpdatedValue");
+            cv.put("COL_C", i);
+            argArray[0] = String.valueOf(id);
+            assertEquals(1, mDatabase.update("T1", cv, "_ID=?", argArray));
+            i++;
+        }
+    }
+
+    private void insertT1TestDataSet() {
+        mDatabase.beginTransaction();
+        for (int i = 0; i < DEFAULT_DATASET_SIZE; i++) {
+            mDatabase.execSQL("INSERT INTO T1 VALUES (?, ?, ?, ?)",
+                    new Object[]{i, i, "T1Value" + i, i * 1.1});
+        }
+        mDatabase.setTransactionSuccessful();
+        mDatabase.endTransaction();
+    }
+
+    private void insertT2TestDataSet() {
+        mDatabase.beginTransaction();
+        for (int i = 0; i < DEFAULT_DATASET_SIZE; i++) {
+            mDatabase.execSQL("INSERT INTO T2 VALUES (?, ?, ?)",
+                    new Object[]{i, "T2Value" + i, i});
+        }
+        mDatabase.setTransactionSuccessful();
+        mDatabase.endTransaction();
+    }
+}
+
diff --git a/api/current.txt b/api/current.txt
index df9438c..df8b7ef 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -35,6 +35,7 @@
     field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
     field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
     field public static final java.lang.String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
+    field public static final java.lang.String BIND_SLICE = "android.permission.BIND_SLICE";
     field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
     field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
     field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
@@ -1441,6 +1442,7 @@
     field public static final int trimPathEnd = 16843785; // 0x1010409
     field public static final int trimPathOffset = 16843786; // 0x101040a
     field public static final int trimPathStart = 16843784; // 0x1010408
+    field public static final int ttcIndex = 16844143; // 0x101056f
     field public static final int tunerCount = 16844061; // 0x101051d
     field public static final int turnScreenOn = 16844138; // 0x101056a
     field public static final int type = 16843169; // 0x10101a1
@@ -4006,8 +4008,10 @@
   }
 
   public static class ActivityManager.TaskDescription implements android.os.Parcelable {
-    ctor public ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap, int);
-    ctor public ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap);
+    ctor public deprecated ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap, int);
+    ctor public ActivityManager.TaskDescription(java.lang.String, int, int);
+    ctor public deprecated ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap);
+    ctor public ActivityManager.TaskDescription(java.lang.String, int);
     ctor public ActivityManager.TaskDescription(java.lang.String);
     ctor public ActivityManager.TaskDescription();
     ctor public ActivityManager.TaskDescription(android.app.ActivityManager.TaskDescription);
@@ -4023,6 +4027,7 @@
   public class ActivityOptions {
     method public android.graphics.Rect getLaunchBounds();
     method public int getLaunchDisplayId();
+    method public boolean getLockTaskMode();
     method public static android.app.ActivityOptions makeBasic();
     method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int);
     method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
@@ -4035,6 +4040,7 @@
     method public android.app.ActivityOptions setAppVerificationBundle(android.os.Bundle);
     method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect);
     method public android.app.ActivityOptions setLaunchDisplayId(int);
+    method public android.app.ActivityOptions setLockTaskMode(boolean);
     method public android.os.Bundle toBundle();
     method public void update(android.app.ActivityOptions);
     field public static final java.lang.String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
@@ -5644,8 +5650,10 @@
     method public static java.lang.String suppressedEffectsToString(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.NotificationManager.Policy> CREATOR;
+    field public static final int PRIORITY_CATEGORY_ALARMS = 32; // 0x20
     field public static final int PRIORITY_CATEGORY_CALLS = 8; // 0x8
     field public static final int PRIORITY_CATEGORY_EVENTS = 2; // 0x2
+    field public static final int PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER = 64; // 0x40
     field public static final int PRIORITY_CATEGORY_MESSAGES = 4; // 0x4
     field public static final int PRIORITY_CATEGORY_REMINDERS = 1; // 0x1
     field public static final int PRIORITY_CATEGORY_REPEAT_CALLERS = 16; // 0x10
@@ -6670,6 +6678,9 @@
     method public int getInputType();
     method public int getLeft();
     method public android.os.LocaleList getLocaleList();
+    method public int getMaxTextEms();
+    method public int getMaxTextLength();
+    method public int getMinTextEms();
     method public int getScrollX();
     method public int getScrollY();
     method public java.lang.CharSequence getText();
@@ -6934,6 +6945,88 @@
 
 }
 
+package android.app.slice {
+
+  public final class Slice implements android.os.Parcelable {
+    ctor protected Slice(android.os.Parcel);
+    method public static android.app.slice.Slice bindSlice(android.content.ContentResolver, android.net.Uri);
+    method public int describeContents();
+    method public java.util.List<java.lang.String> getHints();
+    method public java.util.List<android.app.slice.SliceItem> getItems();
+    method public android.net.Uri getUri();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.slice.Slice> CREATOR;
+    field public static final java.lang.String HINT_ACTIONS = "actions";
+    field public static final java.lang.String HINT_HORIZONTAL = "horizontal";
+    field public static final java.lang.String HINT_LARGE = "large";
+    field public static final java.lang.String HINT_LIST = "list";
+    field public static final java.lang.String HINT_LIST_ITEM = "list_item";
+    field public static final java.lang.String HINT_MESSAGE = "message";
+    field public static final java.lang.String HINT_NO_TINT = "no_tint";
+    field public static final java.lang.String HINT_PARTIAL = "partial";
+    field public static final java.lang.String HINT_SELECTED = "selected";
+    field public static final java.lang.String HINT_SOURCE = "source";
+    field public static final java.lang.String HINT_TITLE = "title";
+  }
+
+  public static class Slice.Builder {
+    ctor public Slice.Builder(android.net.Uri);
+    ctor public Slice.Builder(android.app.slice.Slice.Builder);
+    method public android.app.slice.Slice.Builder addAction(android.app.PendingIntent, android.app.slice.Slice);
+    method public android.app.slice.Slice.Builder addColor(int, java.lang.String...);
+    method public android.app.slice.Slice.Builder addColor(int, java.util.List<java.lang.String>);
+    method public android.app.slice.Slice.Builder addHints(java.lang.String...);
+    method public android.app.slice.Slice.Builder addHints(java.util.List<java.lang.String>);
+    method public android.app.slice.Slice.Builder addIcon(android.graphics.drawable.Icon, java.lang.String...);
+    method public android.app.slice.Slice.Builder addIcon(android.graphics.drawable.Icon, java.util.List<java.lang.String>);
+    method public android.app.slice.Slice.Builder addRemoteInput(android.app.RemoteInput, java.util.List<java.lang.String>);
+    method public android.app.slice.Slice.Builder addRemoteInput(android.app.RemoteInput, java.lang.String...);
+    method public android.app.slice.Slice.Builder addSubSlice(android.app.slice.Slice);
+    method public android.app.slice.Slice.Builder addText(java.lang.CharSequence, java.lang.String...);
+    method public android.app.slice.Slice.Builder addText(java.lang.CharSequence, java.util.List<java.lang.String>);
+    method public android.app.slice.Slice.Builder addTimestamp(long, java.lang.String...);
+    method public android.app.slice.Slice.Builder addTimestamp(long, java.util.List<java.lang.String>);
+    method public android.app.slice.Slice build();
+  }
+
+  public final class SliceItem implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.app.PendingIntent getAction();
+    method public int getColor();
+    method public java.util.List<java.lang.String> getHints();
+    method public android.graphics.drawable.Icon getIcon();
+    method public android.app.RemoteInput getRemoteInput();
+    method public android.app.slice.Slice getSlice();
+    method public java.lang.CharSequence getText();
+    method public long getTimestamp();
+    method public int getType();
+    method public boolean hasHint(java.lang.String);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.slice.SliceItem> CREATOR;
+    field public static final int TYPE_ACTION = 4; // 0x4
+    field public static final int TYPE_COLOR = 6; // 0x6
+    field public static final int TYPE_IMAGE = 3; // 0x3
+    field public static final int TYPE_REMOTE_INPUT = 9; // 0x9
+    field public static final int TYPE_SLICE = 1; // 0x1
+    field public static final int TYPE_TEXT = 2; // 0x2
+    field public static final int TYPE_TIMESTAMP = 8; // 0x8
+  }
+
+  public abstract class SliceProvider extends android.content.ContentProvider {
+    ctor public SliceProvider();
+    method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
+    method public final java.lang.String getType(android.net.Uri);
+    method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
+    method public abstract android.app.slice.Slice onBindSlice(android.net.Uri);
+    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
+    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal);
+    method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
+    field public static final java.lang.String SLICE_TYPE = "vnd.android.slice";
+  }
+
+}
+
 package android.app.usage {
 
   public final class ConfigurationStats implements android.os.Parcelable {
@@ -11000,6 +11093,7 @@
     method public android.content.ComponentName getActivity();
     method public java.util.Set<java.lang.String> getCategories();
     method public java.lang.CharSequence getDisabledMessage();
+    method public int getDisabledReason();
     method public android.os.PersistableBundle getExtras();
     method public java.lang.String getId();
     method public android.content.Intent getIntent();
@@ -11018,6 +11112,13 @@
     method public boolean isPinned();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR;
+    field public static final int DISABLED_REASON_APP_CHANGED = 2; // 0x2
+    field public static final int DISABLED_REASON_BACKUP_NOT_SUPPORTED = 101; // 0x65
+    field public static final int DISABLED_REASON_BY_APP = 1; // 0x1
+    field public static final int DISABLED_REASON_NOT_DISABLED = 0; // 0x0
+    field public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103; // 0x67
+    field public static final int DISABLED_REASON_SIGNATURE_MISMATCH = 102; // 0x66
+    field public static final int DISABLED_REASON_VERSION_LOWER = 100; // 0x64
     field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
   }
 
@@ -11590,6 +11691,7 @@
 
   public class CursorWindow extends android.database.sqlite.SQLiteClosable implements android.os.Parcelable {
     ctor public CursorWindow(java.lang.String);
+    ctor public CursorWindow(java.lang.String, long);
     ctor public deprecated CursorWindow(boolean);
     method public boolean allocRow();
     method public void clear();
@@ -25652,6 +25754,7 @@
     method public java.lang.String getName();
     method public int getTruncationLengthBits();
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final java.lang.String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))";
     field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)";
     field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)";
     field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)";
@@ -25699,6 +25802,7 @@
   public static class IpSecTransform.Builder {
     ctor public IpSecTransform.Builder(android.content.Context);
     method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+    method public android.net.IpSecTransform.Builder setAuthenticatedEncryption(int, android.net.IpSecAlgorithm);
     method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
     method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
     method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
@@ -34970,6 +35074,7 @@
     field public static final java.lang.String ACTION_DEVICE_INFO_SETTINGS = "android.settings.DEVICE_INFO_SETTINGS";
     field public static final java.lang.String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS";
     field public static final java.lang.String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS";
+    field public static final java.lang.String ACTION_FINGERPRINT_ENROLL = "android.settings.FINGERPRINT_ENROLL";
     field public static final java.lang.String ACTION_HARD_KEYBOARD_SETTINGS = "android.settings.HARD_KEYBOARD_SETTINGS";
     field public static final java.lang.String ACTION_HOME_SETTINGS = "android.settings.HOME_SETTINGS";
     field public static final java.lang.String ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS = "android.settings.IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS";
@@ -37101,6 +37206,19 @@
     field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
   }
 
+  public final class BatchUpdates implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.autofill.BatchUpdates> CREATOR;
+  }
+
+  public static class BatchUpdates.Builder {
+    ctor public BatchUpdates.Builder();
+    method public android.service.autofill.BatchUpdates build();
+    method public android.service.autofill.BatchUpdates.Builder transformChild(int, android.service.autofill.Transformation);
+    method public android.service.autofill.BatchUpdates.Builder updateTemplate(android.widget.RemoteViews);
+  }
+
   public final class CharSequenceTransformation implements android.os.Parcelable android.service.autofill.Transformation {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
@@ -37122,6 +37240,7 @@
   public static class CustomDescription.Builder {
     ctor public CustomDescription.Builder(android.widget.RemoteViews);
     method public android.service.autofill.CustomDescription.Builder addChild(int, android.service.autofill.Transformation);
+    method public android.service.autofill.CustomDescription.Builder batchUpdate(android.service.autofill.Validator, android.service.autofill.BatchUpdates);
     method public android.service.autofill.CustomDescription build();
   }
 
@@ -37165,10 +37284,15 @@
   }
 
   public static final class FillEventHistory.Event {
+    method public java.util.Map<android.view.autofill.AutofillId, java.lang.String> getChangedFields();
     method public android.os.Bundle getClientState();
     method public java.lang.String getDatasetId();
+    method public java.util.Set<java.lang.String> getIgnoredDatasetIds();
+    method public java.util.Map<android.view.autofill.AutofillId, java.util.Set<java.lang.String>> getManuallyEnteredField();
+    method public java.util.Set<java.lang.String> getSelectedDatasetIds();
     method public int getType();
     field public static final int TYPE_AUTHENTICATION_SELECTED = 2; // 0x2
+    field public static final int TYPE_CONTEXT_COMMITTED = 4; // 0x4
     field public static final int TYPE_DATASET_AUTHENTICATION_SELECTED = 1; // 0x1
     field public static final int TYPE_DATASET_SELECTED = 0; // 0x0
     field public static final int TYPE_SAVE_SHOWN = 3; // 0x3
@@ -37189,6 +37313,7 @@
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.autofill.FillResponse> CREATOR;
+    field public static final int FLAG_TRACK_CONTEXT_COMMITED = 1; // 0x1
   }
 
   public static final class FillResponse.Builder {
@@ -37197,6 +37322,7 @@
     method public android.service.autofill.FillResponse build();
     method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
     method public android.service.autofill.FillResponse.Builder setClientState(android.os.Bundle);
+    method public android.service.autofill.FillResponse.Builder setFlags(int);
     method public android.service.autofill.FillResponse.Builder setIgnoredIds(android.view.autofill.AutofillId...);
     method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
   }
@@ -37241,6 +37367,7 @@
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.autofill.SaveInfo> CREATOR;
+    field public static final int FLAG_DONT_SAVE_ON_FINISH = 2; // 0x2
     field public static final int FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE = 1; // 0x1
     field public static final int NEGATIVE_BUTTON_STYLE_CANCEL = 0; // 0x0
     field public static final int NEGATIVE_BUTTON_STYLE_REJECT = 1; // 0x1
@@ -37262,6 +37389,7 @@
     method public android.service.autofill.SaveInfo.Builder setFlags(int);
     method public android.service.autofill.SaveInfo.Builder setNegativeAction(int, android.content.IntentSender);
     method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]);
+    method public android.service.autofill.SaveInfo.Builder setTriggerId(android.view.autofill.AutofillId);
     method public android.service.autofill.SaveInfo.Builder setValidator(android.service.autofill.Validator);
   }
 
@@ -40035,8 +40163,12 @@
     field public static final java.lang.String EXTRA_MBMS_DOWNLOAD_RESULT = "android.telephony.extra.MBMS_DOWNLOAD_RESULT";
     field public static final java.lang.String EXTRA_MBMS_FILE_INFO = "android.telephony.extra.MBMS_FILE_INFO";
     field public static final int RESULT_CANCELLED = 2; // 0x2
+    field public static final int RESULT_DOWNLOAD_FAILURE = 6; // 0x6
     field public static final int RESULT_EXPIRED = 3; // 0x3
+    field public static final int RESULT_FILE_ROOT_UNREACHABLE = 8; // 0x8
     field public static final int RESULT_IO_ERROR = 4; // 0x4
+    field public static final int RESULT_OUT_OF_STORAGE = 7; // 0x7
+    field public static final int RESULT_SERVICE_ID_NOT_DEFINED = 5; // 0x5
     field public static final int RESULT_SUCCESSFUL = 1; // 0x1
     field public static final int STATUS_ACTIVELY_DOWNLOADING = 1; // 0x1
     field public static final int STATUS_PENDING_DOWNLOAD = 2; // 0x2
@@ -46997,6 +47129,9 @@
     method public abstract void setInputType(int);
     method public abstract void setLocaleList(android.os.LocaleList);
     method public abstract void setLongClickable(boolean);
+    method public void setMaxTextEms(int);
+    method public void setMaxTextLength(int);
+    method public void setMinTextEms(int);
     method public abstract void setOpaque(boolean);
     method public abstract void setSelected(boolean);
     method public abstract void setText(java.lang.CharSequence);
@@ -51935,6 +52070,7 @@
     method public android.graphics.Typeface getTypeface();
     method public android.text.style.URLSpan[] getUrls();
     method public boolean hasSelection();
+    method public void invalidate(int, int, int, int);
     method public boolean isAllCaps();
     method public boolean isCursorVisible();
     method public boolean isElegantTextHeight();
diff --git a/api/system-current.txt b/api/system-current.txt
index 752e0be..007316f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -58,6 +58,7 @@
     field public static final java.lang.String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE";
     field public static final java.lang.String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
     field public static final java.lang.String BIND_SETTINGS_SUGGESTIONS_SERVICE = "android.permission.BIND_SETTINGS_SUGGESTIONS_SERVICE";
+    field public static final java.lang.String BIND_SLICE = "android.permission.BIND_SLICE";
     field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
     field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
     field public static final java.lang.String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
@@ -1579,6 +1580,7 @@
     field public static final int trimPathEnd = 16843785; // 0x1010409
     field public static final int trimPathOffset = 16843786; // 0x101040a
     field public static final int trimPathStart = 16843784; // 0x1010408
+    field public static final int ttcIndex = 16844143; // 0x101056f
     field public static final int tunerCount = 16844061; // 0x101051d
     field public static final int turnScreenOn = 16844138; // 0x101056a
     field public static final int type = 16843169; // 0x10101a1
@@ -4168,8 +4170,10 @@
   }
 
   public static class ActivityManager.TaskDescription implements android.os.Parcelable {
-    ctor public ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap, int);
-    ctor public ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap);
+    ctor public deprecated ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap, int);
+    ctor public ActivityManager.TaskDescription(java.lang.String, int, int);
+    ctor public deprecated ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap);
+    ctor public ActivityManager.TaskDescription(java.lang.String, int);
     ctor public ActivityManager.TaskDescription(java.lang.String);
     ctor public ActivityManager.TaskDescription();
     ctor public ActivityManager.TaskDescription(android.app.ActivityManager.TaskDescription);
@@ -4185,6 +4189,7 @@
   public class ActivityOptions {
     method public android.graphics.Rect getLaunchBounds();
     method public int getLaunchDisplayId();
+    method public boolean getLockTaskMode();
     method public static android.app.ActivityOptions makeBasic();
     method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int);
     method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
@@ -4197,6 +4202,7 @@
     method public android.app.ActivityOptions setAppVerificationBundle(android.os.Bundle);
     method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect);
     method public android.app.ActivityOptions setLaunchDisplayId(int);
+    method public android.app.ActivityOptions setLockTaskMode(boolean);
     method public android.os.Bundle toBundle();
     method public void update(android.app.ActivityOptions);
     field public static final java.lang.String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
@@ -5852,8 +5858,10 @@
     method public static java.lang.String suppressedEffectsToString(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.NotificationManager.Policy> CREATOR;
+    field public static final int PRIORITY_CATEGORY_ALARMS = 32; // 0x20
     field public static final int PRIORITY_CATEGORY_CALLS = 8; // 0x8
     field public static final int PRIORITY_CATEGORY_EVENTS = 2; // 0x2
+    field public static final int PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER = 64; // 0x40
     field public static final int PRIORITY_CATEGORY_MESSAGES = 4; // 0x4
     field public static final int PRIORITY_CATEGORY_REMINDERS = 1; // 0x1
     field public static final int PRIORITY_CATEGORY_REPEAT_CALLERS = 16; // 0x10
@@ -6921,6 +6929,9 @@
     method public int getInputType();
     method public int getLeft();
     method public android.os.LocaleList getLocaleList();
+    method public int getMaxTextEms();
+    method public int getMaxTextLength();
+    method public int getMinTextEms();
     method public int getScrollX();
     method public int getScrollY();
     method public java.lang.CharSequence getText();
@@ -7377,6 +7388,88 @@
 
 }
 
+package android.app.slice {
+
+  public final class Slice implements android.os.Parcelable {
+    ctor protected Slice(android.os.Parcel);
+    method public static android.app.slice.Slice bindSlice(android.content.ContentResolver, android.net.Uri);
+    method public int describeContents();
+    method public java.util.List<java.lang.String> getHints();
+    method public java.util.List<android.app.slice.SliceItem> getItems();
+    method public android.net.Uri getUri();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.slice.Slice> CREATOR;
+    field public static final java.lang.String HINT_ACTIONS = "actions";
+    field public static final java.lang.String HINT_HORIZONTAL = "horizontal";
+    field public static final java.lang.String HINT_LARGE = "large";
+    field public static final java.lang.String HINT_LIST = "list";
+    field public static final java.lang.String HINT_LIST_ITEM = "list_item";
+    field public static final java.lang.String HINT_MESSAGE = "message";
+    field public static final java.lang.String HINT_NO_TINT = "no_tint";
+    field public static final java.lang.String HINT_PARTIAL = "partial";
+    field public static final java.lang.String HINT_SELECTED = "selected";
+    field public static final java.lang.String HINT_SOURCE = "source";
+    field public static final java.lang.String HINT_TITLE = "title";
+  }
+
+  public static class Slice.Builder {
+    ctor public Slice.Builder(android.net.Uri);
+    ctor public Slice.Builder(android.app.slice.Slice.Builder);
+    method public android.app.slice.Slice.Builder addAction(android.app.PendingIntent, android.app.slice.Slice);
+    method public android.app.slice.Slice.Builder addColor(int, java.lang.String...);
+    method public android.app.slice.Slice.Builder addColor(int, java.util.List<java.lang.String>);
+    method public android.app.slice.Slice.Builder addHints(java.lang.String...);
+    method public android.app.slice.Slice.Builder addHints(java.util.List<java.lang.String>);
+    method public android.app.slice.Slice.Builder addIcon(android.graphics.drawable.Icon, java.lang.String...);
+    method public android.app.slice.Slice.Builder addIcon(android.graphics.drawable.Icon, java.util.List<java.lang.String>);
+    method public android.app.slice.Slice.Builder addRemoteInput(android.app.RemoteInput, java.util.List<java.lang.String>);
+    method public android.app.slice.Slice.Builder addRemoteInput(android.app.RemoteInput, java.lang.String...);
+    method public android.app.slice.Slice.Builder addSubSlice(android.app.slice.Slice);
+    method public android.app.slice.Slice.Builder addText(java.lang.CharSequence, java.lang.String...);
+    method public android.app.slice.Slice.Builder addText(java.lang.CharSequence, java.util.List<java.lang.String>);
+    method public android.app.slice.Slice.Builder addTimestamp(long, java.lang.String...);
+    method public android.app.slice.Slice.Builder addTimestamp(long, java.util.List<java.lang.String>);
+    method public android.app.slice.Slice build();
+  }
+
+  public final class SliceItem implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.app.PendingIntent getAction();
+    method public int getColor();
+    method public java.util.List<java.lang.String> getHints();
+    method public android.graphics.drawable.Icon getIcon();
+    method public android.app.RemoteInput getRemoteInput();
+    method public android.app.slice.Slice getSlice();
+    method public java.lang.CharSequence getText();
+    method public long getTimestamp();
+    method public int getType();
+    method public boolean hasHint(java.lang.String);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.slice.SliceItem> CREATOR;
+    field public static final int TYPE_ACTION = 4; // 0x4
+    field public static final int TYPE_COLOR = 6; // 0x6
+    field public static final int TYPE_IMAGE = 3; // 0x3
+    field public static final int TYPE_REMOTE_INPUT = 9; // 0x9
+    field public static final int TYPE_SLICE = 1; // 0x1
+    field public static final int TYPE_TEXT = 2; // 0x2
+    field public static final int TYPE_TIMESTAMP = 8; // 0x8
+  }
+
+  public abstract class SliceProvider extends android.content.ContentProvider {
+    ctor public SliceProvider();
+    method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
+    method public final java.lang.String getType(android.net.Uri);
+    method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
+    method public abstract android.app.slice.Slice onBindSlice(android.net.Uri);
+    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
+    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal);
+    method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
+    field public static final java.lang.String SLICE_TYPE = "vnd.android.slice";
+  }
+
+}
+
 package android.app.usage {
 
   public final class CacheQuotaHint implements android.os.Parcelable {
@@ -7709,6 +7802,7 @@
     method public boolean disableBLE();
     method public boolean enable();
     method public boolean enableBLE();
+    method public boolean enableNoAutoConnect();
     method public java.lang.String getAddress();
     method public android.bluetooth.le.BluetoothLeAdvertiser getBluetoothLeAdvertiser();
     method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner();
@@ -8098,6 +8192,7 @@
   }
 
   public final class BluetoothDevice implements android.os.Parcelable {
+    method public boolean cancelBondProcess();
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback);
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int);
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int);
@@ -8115,7 +8210,9 @@
     method public android.os.ParcelUuid[] getUuids();
     method public boolean isConnected();
     method public boolean isEncrypted();
+    method public boolean removeBond();
     method public boolean setPairingConfirmation(boolean);
+    method public boolean setPhonebookAccessPermission(int);
     method public boolean setPin(byte[]);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final java.lang.String ACTION_ACL_CONNECTED = "android.bluetooth.device.action.ACL_CONNECTED";
@@ -8346,11 +8443,14 @@
   }
 
   public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
+    method public boolean connect(android.bluetooth.BluetoothDevice);
+    method public boolean disconnect(android.bluetooth.BluetoothDevice);
     method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
     method public int getConnectionState(android.bluetooth.BluetoothDevice);
     method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
     method public boolean isAudioConnected(android.bluetooth.BluetoothDevice);
     method public boolean sendVendorSpecificResultCode(android.bluetooth.BluetoothDevice, java.lang.String, java.lang.String);
+    method public boolean setPriority(android.bluetooth.BluetoothDevice, int);
     method public boolean startVoiceRecognition(android.bluetooth.BluetoothDevice);
     method public boolean stopVoiceRecognition(android.bluetooth.BluetoothDevice);
     field public static final java.lang.String ACTION_AUDIO_STATE_CHANGED = "android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED";
@@ -11723,6 +11823,7 @@
     method public android.content.ComponentName getActivity();
     method public java.util.Set<java.lang.String> getCategories();
     method public java.lang.CharSequence getDisabledMessage();
+    method public int getDisabledReason();
     method public android.os.PersistableBundle getExtras();
     method public java.lang.String getId();
     method public android.content.Intent getIntent();
@@ -11741,6 +11842,13 @@
     method public boolean isPinned();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR;
+    field public static final int DISABLED_REASON_APP_CHANGED = 2; // 0x2
+    field public static final int DISABLED_REASON_BACKUP_NOT_SUPPORTED = 101; // 0x65
+    field public static final int DISABLED_REASON_BY_APP = 1; // 0x1
+    field public static final int DISABLED_REASON_NOT_DISABLED = 0; // 0x0
+    field public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103; // 0x67
+    field public static final int DISABLED_REASON_SIGNATURE_MISMATCH = 102; // 0x66
+    field public static final int DISABLED_REASON_VERSION_LOWER = 100; // 0x64
     field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
   }
 
@@ -12327,6 +12435,7 @@
 
   public class CursorWindow extends android.database.sqlite.SQLiteClosable implements android.os.Parcelable {
     ctor public CursorWindow(java.lang.String);
+    ctor public CursorWindow(java.lang.String, long);
     ctor public deprecated CursorWindow(boolean);
     method public boolean allocRow();
     method public void clear();
@@ -27887,6 +27996,7 @@
     method public java.lang.String getName();
     method public int getTruncationLengthBits();
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final java.lang.String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))";
     field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)";
     field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)";
     field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)";
@@ -27934,6 +28044,7 @@
   public static class IpSecTransform.Builder {
     ctor public IpSecTransform.Builder(android.content.Context);
     method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+    method public android.net.IpSecTransform.Builder setAuthenticatedEncryption(int, android.net.IpSecAlgorithm);
     method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
     method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
     method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
@@ -38027,6 +38138,7 @@
     field public static final java.lang.String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS";
     field public static final java.lang.String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS";
     field public static final java.lang.String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
+    field public static final java.lang.String ACTION_FINGERPRINT_ENROLL = "android.settings.FINGERPRINT_ENROLL";
     field public static final java.lang.String ACTION_HARD_KEYBOARD_SETTINGS = "android.settings.HARD_KEYBOARD_SETTINGS";
     field public static final java.lang.String ACTION_HOME_SETTINGS = "android.settings.HOME_SETTINGS";
     field public static final java.lang.String ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS = "android.settings.IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS";
@@ -40196,6 +40308,19 @@
     field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
   }
 
+  public final class BatchUpdates implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.autofill.BatchUpdates> CREATOR;
+  }
+
+  public static class BatchUpdates.Builder {
+    ctor public BatchUpdates.Builder();
+    method public android.service.autofill.BatchUpdates build();
+    method public android.service.autofill.BatchUpdates.Builder transformChild(int, android.service.autofill.Transformation);
+    method public android.service.autofill.BatchUpdates.Builder updateTemplate(android.widget.RemoteViews);
+  }
+
   public final class CharSequenceTransformation implements android.os.Parcelable android.service.autofill.Transformation {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
@@ -40217,6 +40342,7 @@
   public static class CustomDescription.Builder {
     ctor public CustomDescription.Builder(android.widget.RemoteViews);
     method public android.service.autofill.CustomDescription.Builder addChild(int, android.service.autofill.Transformation);
+    method public android.service.autofill.CustomDescription.Builder batchUpdate(android.service.autofill.Validator, android.service.autofill.BatchUpdates);
     method public android.service.autofill.CustomDescription build();
   }
 
@@ -40260,10 +40386,15 @@
   }
 
   public static final class FillEventHistory.Event {
+    method public java.util.Map<android.view.autofill.AutofillId, java.lang.String> getChangedFields();
     method public android.os.Bundle getClientState();
     method public java.lang.String getDatasetId();
+    method public java.util.Set<java.lang.String> getIgnoredDatasetIds();
+    method public java.util.Map<android.view.autofill.AutofillId, java.util.Set<java.lang.String>> getManuallyEnteredField();
+    method public java.util.Set<java.lang.String> getSelectedDatasetIds();
     method public int getType();
     field public static final int TYPE_AUTHENTICATION_SELECTED = 2; // 0x2
+    field public static final int TYPE_CONTEXT_COMMITTED = 4; // 0x4
     field public static final int TYPE_DATASET_AUTHENTICATION_SELECTED = 1; // 0x1
     field public static final int TYPE_DATASET_SELECTED = 0; // 0x0
     field public static final int TYPE_SAVE_SHOWN = 3; // 0x3
@@ -40284,6 +40415,7 @@
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.autofill.FillResponse> CREATOR;
+    field public static final int FLAG_TRACK_CONTEXT_COMMITED = 1; // 0x1
   }
 
   public static final class FillResponse.Builder {
@@ -40292,6 +40424,7 @@
     method public android.service.autofill.FillResponse build();
     method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
     method public android.service.autofill.FillResponse.Builder setClientState(android.os.Bundle);
+    method public android.service.autofill.FillResponse.Builder setFlags(int);
     method public android.service.autofill.FillResponse.Builder setIgnoredIds(android.view.autofill.AutofillId...);
     method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
   }
@@ -40336,6 +40469,7 @@
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.autofill.SaveInfo> CREATOR;
+    field public static final int FLAG_DONT_SAVE_ON_FINISH = 2; // 0x2
     field public static final int FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE = 1; // 0x1
     field public static final int NEGATIVE_BUTTON_STYLE_CANCEL = 0; // 0x0
     field public static final int NEGATIVE_BUTTON_STYLE_REJECT = 1; // 0x1
@@ -40357,6 +40491,7 @@
     method public android.service.autofill.SaveInfo.Builder setFlags(int);
     method public android.service.autofill.SaveInfo.Builder setNegativeAction(int, android.content.IntentSender);
     method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]);
+    method public android.service.autofill.SaveInfo.Builder setTriggerId(android.view.autofill.AutofillId);
     method public android.service.autofill.SaveInfo.Builder setValidator(android.service.autofill.Validator);
   }
 
@@ -40967,6 +41102,7 @@
     method public android.os.IBinder onBind(android.content.Intent);
     method public abstract java.util.List<android.service.settings.suggestions.Suggestion> onGetSuggestions();
     method public abstract void onSuggestionDismissed(android.service.settings.suggestions.Suggestion);
+    method public abstract void onSuggestionLaunched(android.service.settings.suggestions.Suggestion);
   }
 
 }
@@ -43544,8 +43680,12 @@
     field public static final java.lang.String EXTRA_MBMS_FILE_INFO = "android.telephony.extra.MBMS_FILE_INFO";
     field public static final java.lang.String MBMS_DOWNLOAD_SERVICE_ACTION = "android.telephony.action.EmbmsDownload";
     field public static final int RESULT_CANCELLED = 2; // 0x2
+    field public static final int RESULT_DOWNLOAD_FAILURE = 6; // 0x6
     field public static final int RESULT_EXPIRED = 3; // 0x3
+    field public static final int RESULT_FILE_ROOT_UNREACHABLE = 8; // 0x8
     field public static final int RESULT_IO_ERROR = 4; // 0x4
+    field public static final int RESULT_OUT_OF_STORAGE = 7; // 0x7
+    field public static final int RESULT_SERVICE_ID_NOT_DEFINED = 5; // 0x5
     field public static final int RESULT_SUCCESSFUL = 1; // 0x1
     field public static final int STATUS_ACTIVELY_DOWNLOADING = 1; // 0x1
     field public static final int STATUS_PENDING_DOWNLOAD = 2; // 0x2
@@ -50722,6 +50862,9 @@
     method public abstract void setInputType(int);
     method public abstract void setLocaleList(android.os.LocaleList);
     method public abstract void setLongClickable(boolean);
+    method public void setMaxTextEms(int);
+    method public void setMaxTextLength(int);
+    method public void setMinTextEms(int);
     method public abstract void setOpaque(boolean);
     method public abstract void setSelected(boolean);
     method public abstract void setText(java.lang.CharSequence);
@@ -56031,6 +56174,7 @@
     method public android.graphics.Typeface getTypeface();
     method public android.text.style.URLSpan[] getUrls();
     method public boolean hasSelection();
+    method public void invalidate(int, int, int, int);
     method public boolean isAllCaps();
     method public boolean isCursorVisible();
     method public boolean isElegantTextHeight();
diff --git a/api/test-current.txt b/api/test-current.txt
index 08b297b..faccb6b 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -35,6 +35,7 @@
     field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
     field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
     field public static final java.lang.String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
+    field public static final java.lang.String BIND_SLICE = "android.permission.BIND_SLICE";
     field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
     field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
     field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
@@ -1441,6 +1442,7 @@
     field public static final int trimPathEnd = 16843785; // 0x1010409
     field public static final int trimPathOffset = 16843786; // 0x101040a
     field public static final int trimPathStart = 16843784; // 0x1010408
+    field public static final int ttcIndex = 16844143; // 0x101056f
     field public static final int tunerCount = 16844061; // 0x101051d
     field public static final int turnScreenOn = 16844138; // 0x101056a
     field public static final int type = 16843169; // 0x10101a1
@@ -4026,13 +4028,17 @@
   }
 
   public static class ActivityManager.TaskDescription implements android.os.Parcelable {
-    ctor public ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap, int);
-    ctor public ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap);
+    ctor public deprecated ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap, int);
+    ctor public ActivityManager.TaskDescription(java.lang.String, int, int);
+    ctor public deprecated ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap);
+    ctor public ActivityManager.TaskDescription(java.lang.String, int);
     ctor public ActivityManager.TaskDescription(java.lang.String);
     ctor public ActivityManager.TaskDescription();
     ctor public ActivityManager.TaskDescription(android.app.ActivityManager.TaskDescription);
     method public int describeContents();
     method public android.graphics.Bitmap getIcon();
+    method public java.lang.String getIconFilename();
+    method public int getIconResource();
     method public java.lang.String getLabel();
     method public int getPrimaryColor();
     method public void readFromParcel(android.os.Parcel);
@@ -4043,6 +4049,7 @@
   public class ActivityOptions {
     method public android.graphics.Rect getLaunchBounds();
     method public int getLaunchDisplayId();
+    method public boolean getLockTaskMode();
     method public static android.app.ActivityOptions makeBasic();
     method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int);
     method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
@@ -4058,6 +4065,7 @@
     method public android.app.ActivityOptions setLaunchDisplayId(int);
     method public void setLaunchTaskId(int);
     method public void setLaunchWindowingMode(int);
+    method public android.app.ActivityOptions setLockTaskMode(boolean);
     method public void setTaskOverlay(boolean, boolean);
     method public android.os.Bundle toBundle();
     method public void update(android.app.ActivityOptions);
@@ -5670,8 +5678,10 @@
     method public static java.lang.String suppressedEffectsToString(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.NotificationManager.Policy> CREATOR;
+    field public static final int PRIORITY_CATEGORY_ALARMS = 32; // 0x20
     field public static final int PRIORITY_CATEGORY_CALLS = 8; // 0x8
     field public static final int PRIORITY_CATEGORY_EVENTS = 2; // 0x2
+    field public static final int PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER = 64; // 0x40
     field public static final int PRIORITY_CATEGORY_MESSAGES = 4; // 0x4
     field public static final int PRIORITY_CATEGORY_REMINDERS = 1; // 0x1
     field public static final int PRIORITY_CATEGORY_REPEAT_CALLERS = 16; // 0x10
@@ -6739,6 +6749,9 @@
     method public int getInputType();
     method public int getLeft();
     method public android.os.LocaleList getLocaleList();
+    method public int getMaxTextEms();
+    method public int getMaxTextLength();
+    method public int getMinTextEms();
     method public int getScrollX();
     method public int getScrollY();
     method public java.lang.CharSequence getText();
@@ -7003,6 +7016,88 @@
 
 }
 
+package android.app.slice {
+
+  public final class Slice implements android.os.Parcelable {
+    ctor protected Slice(android.os.Parcel);
+    method public static android.app.slice.Slice bindSlice(android.content.ContentResolver, android.net.Uri);
+    method public int describeContents();
+    method public java.util.List<java.lang.String> getHints();
+    method public java.util.List<android.app.slice.SliceItem> getItems();
+    method public android.net.Uri getUri();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.slice.Slice> CREATOR;
+    field public static final java.lang.String HINT_ACTIONS = "actions";
+    field public static final java.lang.String HINT_HORIZONTAL = "horizontal";
+    field public static final java.lang.String HINT_LARGE = "large";
+    field public static final java.lang.String HINT_LIST = "list";
+    field public static final java.lang.String HINT_LIST_ITEM = "list_item";
+    field public static final java.lang.String HINT_MESSAGE = "message";
+    field public static final java.lang.String HINT_NO_TINT = "no_tint";
+    field public static final java.lang.String HINT_PARTIAL = "partial";
+    field public static final java.lang.String HINT_SELECTED = "selected";
+    field public static final java.lang.String HINT_SOURCE = "source";
+    field public static final java.lang.String HINT_TITLE = "title";
+  }
+
+  public static class Slice.Builder {
+    ctor public Slice.Builder(android.net.Uri);
+    ctor public Slice.Builder(android.app.slice.Slice.Builder);
+    method public android.app.slice.Slice.Builder addAction(android.app.PendingIntent, android.app.slice.Slice);
+    method public android.app.slice.Slice.Builder addColor(int, java.lang.String...);
+    method public android.app.slice.Slice.Builder addColor(int, java.util.List<java.lang.String>);
+    method public android.app.slice.Slice.Builder addHints(java.lang.String...);
+    method public android.app.slice.Slice.Builder addHints(java.util.List<java.lang.String>);
+    method public android.app.slice.Slice.Builder addIcon(android.graphics.drawable.Icon, java.lang.String...);
+    method public android.app.slice.Slice.Builder addIcon(android.graphics.drawable.Icon, java.util.List<java.lang.String>);
+    method public android.app.slice.Slice.Builder addRemoteInput(android.app.RemoteInput, java.util.List<java.lang.String>);
+    method public android.app.slice.Slice.Builder addRemoteInput(android.app.RemoteInput, java.lang.String...);
+    method public android.app.slice.Slice.Builder addSubSlice(android.app.slice.Slice);
+    method public android.app.slice.Slice.Builder addText(java.lang.CharSequence, java.lang.String...);
+    method public android.app.slice.Slice.Builder addText(java.lang.CharSequence, java.util.List<java.lang.String>);
+    method public android.app.slice.Slice.Builder addTimestamp(long, java.lang.String...);
+    method public android.app.slice.Slice.Builder addTimestamp(long, java.util.List<java.lang.String>);
+    method public android.app.slice.Slice build();
+  }
+
+  public final class SliceItem implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.app.PendingIntent getAction();
+    method public int getColor();
+    method public java.util.List<java.lang.String> getHints();
+    method public android.graphics.drawable.Icon getIcon();
+    method public android.app.RemoteInput getRemoteInput();
+    method public android.app.slice.Slice getSlice();
+    method public java.lang.CharSequence getText();
+    method public long getTimestamp();
+    method public int getType();
+    method public boolean hasHint(java.lang.String);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.slice.SliceItem> CREATOR;
+    field public static final int TYPE_ACTION = 4; // 0x4
+    field public static final int TYPE_COLOR = 6; // 0x6
+    field public static final int TYPE_IMAGE = 3; // 0x3
+    field public static final int TYPE_REMOTE_INPUT = 9; // 0x9
+    field public static final int TYPE_SLICE = 1; // 0x1
+    field public static final int TYPE_TEXT = 2; // 0x2
+    field public static final int TYPE_TIMESTAMP = 8; // 0x8
+  }
+
+  public abstract class SliceProvider extends android.content.ContentProvider {
+    ctor public SliceProvider();
+    method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
+    method public final java.lang.String getType(android.net.Uri);
+    method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
+    method public abstract android.app.slice.Slice onBindSlice(android.net.Uri);
+    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
+    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal);
+    method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
+    field public static final java.lang.String SLICE_TYPE = "vnd.android.slice";
+  }
+
+}
+
 package android.app.usage {
 
   public final class ConfigurationStats implements android.os.Parcelable {
@@ -10509,6 +10604,7 @@
     method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int);
     method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List<java.lang.String>);
     field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
+    field public static final int FLAG_MATCH_ALL_PINNED = 1024; // 0x400
     field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1
     field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8
     field public static final int FLAG_MATCH_PINNED = 2; // 0x2
@@ -11081,6 +11177,7 @@
     method public android.content.ComponentName getActivity();
     method public java.util.Set<java.lang.String> getCategories();
     method public java.lang.CharSequence getDisabledMessage();
+    method public int getDisabledReason();
     method public android.os.PersistableBundle getExtras();
     method public java.lang.String getId();
     method public android.content.Intent getIntent();
@@ -11097,8 +11194,16 @@
     method public boolean isEnabled();
     method public boolean isImmutable();
     method public boolean isPinned();
+    method public boolean isVisibleToPublisher();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR;
+    field public static final int DISABLED_REASON_APP_CHANGED = 2; // 0x2
+    field public static final int DISABLED_REASON_BACKUP_NOT_SUPPORTED = 101; // 0x65
+    field public static final int DISABLED_REASON_BY_APP = 1; // 0x1
+    field public static final int DISABLED_REASON_NOT_DISABLED = 0; // 0x0
+    field public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103; // 0x67
+    field public static final int DISABLED_REASON_SIGNATURE_MISMATCH = 102; // 0x66
+    field public static final int DISABLED_REASON_VERSION_LOWER = 100; // 0x64
     field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
   }
 
@@ -11673,6 +11778,7 @@
 
   public class CursorWindow extends android.database.sqlite.SQLiteClosable implements android.os.Parcelable {
     ctor public CursorWindow(java.lang.String);
+    ctor public CursorWindow(java.lang.String, long);
     ctor public deprecated CursorWindow(boolean);
     method public boolean allocRow();
     method public void clear();
@@ -25848,6 +25954,7 @@
     method public java.lang.String getName();
     method public int getTruncationLengthBits();
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final java.lang.String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))";
     field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)";
     field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)";
     field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)";
@@ -25895,6 +26002,7 @@
   public static class IpSecTransform.Builder {
     ctor public IpSecTransform.Builder(android.content.Context);
     method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+    method public android.net.IpSecTransform.Builder setAuthenticatedEncryption(int, android.net.IpSecAlgorithm);
     method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
     method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
     method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
@@ -35237,6 +35345,7 @@
     field public static final java.lang.String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS";
     field public static final java.lang.String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS";
     field public static final java.lang.String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
+    field public static final java.lang.String ACTION_FINGERPRINT_ENROLL = "android.settings.FINGERPRINT_ENROLL";
     field public static final java.lang.String ACTION_HARD_KEYBOARD_SETTINGS = "android.settings.HARD_KEYBOARD_SETTINGS";
     field public static final java.lang.String ACTION_HOME_SETTINGS = "android.settings.HOME_SETTINGS";
     field public static final java.lang.String ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS = "android.settings.IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS";
@@ -35383,6 +35492,7 @@
     method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String);
     method public static final deprecated void setLocationProviderEnabled(android.content.ContentResolver, java.lang.String, boolean);
     field public static final java.lang.String ACCESSIBILITY_DISPLAY_INVERSION_ENABLED = "accessibility_display_inversion_enabled";
+    field public static final java.lang.String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED = "accessibility_display_magnification_enabled";
     field public static final java.lang.String ACCESSIBILITY_ENABLED = "accessibility_enabled";
     field public static final deprecated java.lang.String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password";
     field public static final deprecated java.lang.String ADB_ENABLED = "adb_enabled";
@@ -37387,7 +37497,20 @@
     field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
   }
 
-  public final class CharSequenceTransformation implements android.os.Parcelable android.service.autofill.Transformation {
+  public final class BatchUpdates implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.autofill.BatchUpdates> CREATOR;
+  }
+
+  public static class BatchUpdates.Builder {
+    ctor public BatchUpdates.Builder();
+    method public android.service.autofill.BatchUpdates build();
+    method public android.service.autofill.BatchUpdates.Builder transformChild(int, android.service.autofill.Transformation);
+    method public android.service.autofill.BatchUpdates.Builder updateTemplate(android.widget.RemoteViews);
+  }
+
+  public final class CharSequenceTransformation extends android.service.autofill.InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation {
     method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int) throws java.lang.Exception;
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
@@ -37409,6 +37532,7 @@
   public static class CustomDescription.Builder {
     ctor public CustomDescription.Builder(android.widget.RemoteViews);
     method public android.service.autofill.CustomDescription.Builder addChild(int, android.service.autofill.Transformation);
+    method public android.service.autofill.CustomDescription.Builder batchUpdate(android.service.autofill.Validator, android.service.autofill.BatchUpdates);
     method public android.service.autofill.CustomDescription build();
   }
 
@@ -37452,10 +37576,15 @@
   }
 
   public static final class FillEventHistory.Event {
+    method public java.util.Map<android.view.autofill.AutofillId, java.lang.String> getChangedFields();
     method public android.os.Bundle getClientState();
     method public java.lang.String getDatasetId();
+    method public java.util.Set<java.lang.String> getIgnoredDatasetIds();
+    method public java.util.Map<android.view.autofill.AutofillId, java.util.Set<java.lang.String>> getManuallyEnteredField();
+    method public java.util.Set<java.lang.String> getSelectedDatasetIds();
     method public int getType();
     field public static final int TYPE_AUTHENTICATION_SELECTED = 2; // 0x2
+    field public static final int TYPE_CONTEXT_COMMITTED = 4; // 0x4
     field public static final int TYPE_DATASET_AUTHENTICATION_SELECTED = 1; // 0x1
     field public static final int TYPE_DATASET_SELECTED = 0; // 0x0
     field public static final int TYPE_SAVE_SHOWN = 3; // 0x3
@@ -37476,6 +37605,7 @@
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.autofill.FillResponse> CREATOR;
+    field public static final int FLAG_TRACK_CONTEXT_COMMITED = 1; // 0x1
   }
 
   public static final class FillResponse.Builder {
@@ -37484,11 +37614,12 @@
     method public android.service.autofill.FillResponse build();
     method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
     method public android.service.autofill.FillResponse.Builder setClientState(android.os.Bundle);
+    method public android.service.autofill.FillResponse.Builder setFlags(int);
     method public android.service.autofill.FillResponse.Builder setIgnoredIds(android.view.autofill.AutofillId...);
     method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
   }
 
-  public final class ImageTransformation implements android.os.Parcelable android.service.autofill.Transformation {
+  public final class ImageTransformation extends android.service.autofill.InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation {
     method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int) throws java.lang.Exception;
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
@@ -37507,7 +37638,16 @@
     ctor public InternalSanitizer();
   }
 
-  public final class LuhnChecksumValidator implements android.os.Parcelable android.service.autofill.Validator {
+  public abstract class InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation {
+    ctor public InternalTransformation();
+  }
+
+  public abstract class InternalValidator implements android.os.Parcelable android.service.autofill.Validator {
+    ctor public InternalValidator();
+    method public abstract boolean isValid(android.service.autofill.ValueFinder);
+  }
+
+  public final class LuhnChecksumValidator extends android.service.autofill.InternalValidator implements android.os.Parcelable android.service.autofill.Validator {
     ctor public LuhnChecksumValidator(android.view.autofill.AutofillId...);
     method public int describeContents();
     method public boolean isValid(android.service.autofill.ValueFinder);
@@ -37515,7 +37655,7 @@
     field public static final android.os.Parcelable.Creator<android.service.autofill.LuhnChecksumValidator> CREATOR;
   }
 
-  public final class RegexValidator implements android.os.Parcelable android.service.autofill.Validator {
+  public final class RegexValidator extends android.service.autofill.InternalValidator implements android.os.Parcelable android.service.autofill.Validator {
     ctor public RegexValidator(android.view.autofill.AutofillId, java.util.regex.Pattern);
     method public int describeContents();
     method public boolean isValid(android.service.autofill.ValueFinder);
@@ -37535,6 +37675,7 @@
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.autofill.SaveInfo> CREATOR;
+    field public static final int FLAG_DONT_SAVE_ON_FINISH = 2; // 0x2
     field public static final int FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE = 1; // 0x1
     field public static final int NEGATIVE_BUTTON_STYLE_CANCEL = 0; // 0x0
     field public static final int NEGATIVE_BUTTON_STYLE_REJECT = 1; // 0x1
@@ -37556,6 +37697,7 @@
     method public android.service.autofill.SaveInfo.Builder setFlags(int);
     method public android.service.autofill.SaveInfo.Builder setNegativeAction(int, android.content.IntentSender);
     method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]);
+    method public android.service.autofill.SaveInfo.Builder setTriggerId(android.view.autofill.AutofillId);
     method public android.service.autofill.SaveInfo.Builder setValidator(android.service.autofill.Validator);
   }
 
@@ -40416,8 +40558,12 @@
     field public static final java.lang.String EXTRA_MBMS_DOWNLOAD_RESULT = "android.telephony.extra.MBMS_DOWNLOAD_RESULT";
     field public static final java.lang.String EXTRA_MBMS_FILE_INFO = "android.telephony.extra.MBMS_FILE_INFO";
     field public static final int RESULT_CANCELLED = 2; // 0x2
+    field public static final int RESULT_DOWNLOAD_FAILURE = 6; // 0x6
     field public static final int RESULT_EXPIRED = 3; // 0x3
+    field public static final int RESULT_FILE_ROOT_UNREACHABLE = 8; // 0x8
     field public static final int RESULT_IO_ERROR = 4; // 0x4
+    field public static final int RESULT_OUT_OF_STORAGE = 7; // 0x7
+    field public static final int RESULT_SERVICE_ID_NOT_DEFINED = 5; // 0x5
     field public static final int RESULT_SUCCESSFUL = 1; // 0x1
     field public static final int STATUS_ACTIVELY_DOWNLOADING = 1; // 0x1
     field public static final int STATUS_PENDING_DOWNLOAD = 2; // 0x2
@@ -47577,6 +47723,9 @@
     method public abstract void setInputType(int);
     method public abstract void setLocaleList(android.os.LocaleList);
     method public abstract void setLongClickable(boolean);
+    method public void setMaxTextEms(int);
+    method public void setMaxTextLength(int);
+    method public void setMinTextEms(int);
     method public abstract void setOpaque(boolean);
     method public abstract void setSelected(boolean);
     method public abstract void setText(java.lang.CharSequence);
@@ -52529,6 +52678,7 @@
     method public android.graphics.Typeface getTypeface();
     method public android.text.style.URLSpan[] getUrls();
     method public boolean hasSelection();
+    method public void invalidate(int, int, int, int);
     method public boolean isAllCaps();
     method public boolean isCursorVisible();
     method public boolean isElegantTextHeight();
diff --git a/cmds/am/Android.bp b/cmds/am/Android.bp
index 7eb4edf..bb16df1 100644
--- a/cmds/am/Android.bp
+++ b/cmds/am/Android.bp
@@ -4,6 +4,7 @@
 cc_library_host_static {
     name: "libinstrumentation",
     srcs: ["**/*.proto"],
+    cflags: ["-Wall", "-Werror"],
     proto: {
         type: "full",
         export_proto_headers: true,
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 6526123..d1af71d 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -260,9 +260,9 @@
     sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
             dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
 
-    SurfaceComposerClient::openGlobalTransaction();
-    control->setLayer(0x40000000);
-    SurfaceComposerClient::closeGlobalTransaction();
+    SurfaceComposerClient::Transaction t;
+    t.setLayer(control, 0x40000000)
+        .apply();
 
     sp<Surface> s = control->getSurface();
 
diff --git a/cmds/incidentd/src/Privacy.cpp b/cmds/incidentd/src/Privacy.cpp
index e7969e7..140b12c 100644
--- a/cmds/incidentd/src/Privacy.cpp
+++ b/cmds/incidentd/src/Privacy.cpp
@@ -30,6 +30,9 @@
 bool
 Privacy::IsMessageType() const { return type == TYPE_MESSAGE; }
 
+uint64_t
+Privacy::EncodedFieldId() const { return (uint64_t)type << 32 | field_id; }
+
 bool
 Privacy::IsStringType() const { return type == TYPE_STRING; }
 
diff --git a/cmds/incidentd/src/Privacy.h b/cmds/incidentd/src/Privacy.h
index 7f1977e..f514f19 100644
--- a/cmds/incidentd/src/Privacy.h
+++ b/cmds/incidentd/src/Privacy.h
@@ -40,6 +40,8 @@
     bool IsMessageType() const;
     bool IsStringType() const;
     bool HasChildren() const;
+    uint64_t EncodedFieldId() const;
+
     const Privacy* lookup(uint32_t fieldId) const;
 };
 
diff --git a/cmds/incidentd/src/PrivacyBuffer.cpp b/cmds/incidentd/src/PrivacyBuffer.cpp
index 37f6ed7..d926ea7 100644
--- a/cmds/incidentd/src/PrivacyBuffer.cpp
+++ b/cmds/incidentd/src/PrivacyBuffer.cpp
@@ -20,7 +20,6 @@
 #include "io_util.h"
 
 #include <android/util/protobuf.h>
-#include <deque>
 
 using namespace android::util;
 
@@ -28,37 +27,41 @@
  * Write the field to buf based on the wire type, iterator will point to next field.
  * If skip is set to true, no data will be written to buf. Return number of bytes written.
  */
-static size_t
-write_field_or_skip(EncodedBuffer::iterator* iter, EncodedBuffer* buf, uint8_t wireType, bool skip)
+void
+PrivacyBuffer::writeFieldOrSkip(uint32_t fieldTag, bool skip)
 {
-    EncodedBuffer::Pointer snapshot = iter->rp()->copy();
+    uint8_t wireType = read_wire_type(fieldTag);
     size_t bytesToWrite = 0;
-    uint64_t varint = 0;
+    uint32_t varint = 0;
+
     switch (wireType) {
         case WIRE_TYPE_VARINT:
-            varint = iter->readRawVarint();
-            if(!skip) return buf->writeRawVarint64(varint);
-            break;
+            varint = mData.readRawVarint();
+            if (!skip) {
+                mProto.writeRawVarint(fieldTag);
+                mProto.writeRawVarint(varint);
+            }
+            return;
         case WIRE_TYPE_FIXED64:
+            if (!skip) mProto.writeRawVarint(fieldTag);
             bytesToWrite = 8;
             break;
         case WIRE_TYPE_LENGTH_DELIMITED:
-            bytesToWrite = iter->readRawVarint();
-            if(!skip) buf->writeRawVarint32(bytesToWrite);
+            bytesToWrite = mData.readRawVarint();
+            if(!skip) mProto.writeLengthDelimitedHeader(read_field_id(fieldTag), bytesToWrite);
             break;
         case WIRE_TYPE_FIXED32:
+            if (!skip) mProto.writeRawVarint(fieldTag);
             bytesToWrite = 4;
             break;
     }
     if (skip) {
-        iter->rp()->move(bytesToWrite);
+        mData.rp()->move(bytesToWrite);
     } else {
         for (size_t i=0; i<bytesToWrite; i++) {
-            *buf->writeBuffer() = iter->next();
-            buf->wp()->move();
+            mProto.writeRawByte(mData.next());
         }
     }
-    return skip ? 0 : iter->rp()->pos() - snapshot.pos();
 }
 
 /**
@@ -68,46 +71,27 @@
  * The iterator must point to the head of a protobuf formatted field for successful operation.
  * After exit with NO_ERROR, iterator points to the next protobuf field's head.
  */
-static status_t
-stripField(EncodedBuffer::iterator* iter, EncodedBuffer* buf, const Privacy* parentPolicy, const PrivacySpec& spec)
+status_t
+PrivacyBuffer::stripField(const Privacy* parentPolicy, const PrivacySpec& spec)
 {
-    if (!iter->hasNext() || parentPolicy == NULL) return BAD_VALUE;
-    uint32_t varint = iter->readRawVarint();
-    uint8_t wireType = read_wire_type(varint);
-    uint32_t fieldId = read_field_id(varint);
-    const Privacy* policy = parentPolicy->lookup(fieldId);
+    if (!mData.hasNext() || parentPolicy == NULL) return BAD_VALUE;
+    uint32_t fieldTag = mData.readRawVarint();
+    const Privacy* policy = parentPolicy->lookup(read_field_id(fieldTag));
+
     if (policy == NULL || !policy->IsMessageType() || !policy->HasChildren()) {
         bool skip = !spec.CheckPremission(policy);
-        size_t amt = buf->size();
-        if (!skip) amt += buf->writeHeader(fieldId, wireType);
-        amt += write_field_or_skip(iter, buf, wireType, skip); // point to head of next field
-        return buf->size() != amt ? BAD_VALUE : NO_ERROR;
+        // iterator will point to head of next field
+        writeFieldOrSkip(fieldTag, skip);
+        return NO_ERROR;
     }
     // current field is message type and its sub-fields have extra privacy policies
-    deque<EncodedBuffer*> q;
-    uint32_t msgSize = iter->readRawVarint();
-    size_t finalSize = 0;
-    EncodedBuffer::Pointer start = iter->rp()->copy();
-    while (iter->rp()->pos() - start.pos() != msgSize) {
-        EncodedBuffer* v = new EncodedBuffer();
-        status_t err = stripField(iter, v, policy, spec);
+    uint32_t msgSize = mData.readRawVarint();
+    EncodedBuffer::Pointer start = mData.rp()->copy();
+    while (mData.rp()->pos() - start.pos() != msgSize) {
+        long long token = mProto.start(policy->EncodedFieldId());
+        status_t err = stripField(policy, spec);
         if (err != NO_ERROR) return err;
-        if (v->size() == 0) continue;
-        q.push_back(v);
-        finalSize += v->size();
-    }
-
-    buf->writeHeader(fieldId, wireType);
-    buf->writeRawVarint32(finalSize);
-    while (!q.empty()) {
-        EncodedBuffer* subField = q.front();
-        EncodedBuffer::iterator it = subField->begin();
-        while (it.hasNext()) {
-            *buf->writeBuffer() = it.next();
-            buf->wp()->move();
-        }
-        q.pop_front();
-        delete subField;
+        mProto.end(token);
     }
     return NO_ERROR;
 }
@@ -116,7 +100,7 @@
 PrivacyBuffer::PrivacyBuffer(const Privacy* policy, EncodedBuffer::iterator& data)
         :mPolicy(policy),
          mData(data),
-         mBuffer(0),
+         mProto(),
          mSize(0)
 {
 }
@@ -134,11 +118,11 @@
         return NO_ERROR;
     }
     while (mData.hasNext()) {
-        status_t err = stripField(&mData, &mBuffer, mPolicy, spec);
+        status_t err = stripField(mPolicy, spec);
         if (err != NO_ERROR) return err;
     }
     if (mData.bytesRead() != mData.size()) return BAD_VALUE;
-    mSize = mBuffer.size();
+    mSize = mProto.size();
     mData.rp()->rewind(); // rewind the read pointer back to beginning after the strip.
     return NO_ERROR;
 }
@@ -147,7 +131,7 @@
 PrivacyBuffer::clear()
 {
     mSize = 0;
-    mBuffer.wp()->rewind();
+    mProto = ProtoOutputStream();
 }
 
 size_t
@@ -157,7 +141,7 @@
 PrivacyBuffer::flush(int fd)
 {
     status_t err = NO_ERROR;
-    EncodedBuffer::iterator iter = size() == mData.size() ? mData : mBuffer.begin();
+    EncodedBuffer::iterator iter = size() == mData.size() ? mData : mProto.data();
     while (iter.readBuffer() != NULL) {
         err = write_all(fd, iter.readBuffer(), iter.currentToRead());
         iter.rp()->move(iter.currentToRead());
diff --git a/cmds/incidentd/src/PrivacyBuffer.h b/cmds/incidentd/src/PrivacyBuffer.h
index 720b38e..c9ca9a7 100644
--- a/cmds/incidentd/src/PrivacyBuffer.h
+++ b/cmds/incidentd/src/PrivacyBuffer.h
@@ -20,6 +20,7 @@
 #include "Privacy.h"
 
 #include <android/util/EncodedBuffer.h>
+#include <android/util/ProtoOutputStream.h>
 #include <stdint.h>
 #include <utils/Errors.h>
 
@@ -60,8 +61,11 @@
     const Privacy* mPolicy;
     EncodedBuffer::iterator& mData;
 
-    EncodedBuffer mBuffer;
+    ProtoOutputStream mProto;
     size_t mSize;
+
+    status_t stripField(const Privacy* parentPolicy, const PrivacySpec& spec);
+    void writeFieldOrSkip(uint32_t fieldTag, bool skip);
 };
 
 #endif // PRIVACY_BUFFER_H
\ No newline at end of file
diff --git a/cmds/incidentd/src/Reporter.cpp b/cmds/incidentd/src/Reporter.cpp
index 917b70d..34930aa 100644
--- a/cmds/incidentd/src/Reporter.cpp
+++ b/cmds/incidentd/src/Reporter.cpp
@@ -48,6 +48,10 @@
 
 ReportRequest::~ReportRequest()
 {
+    if (fd >= 0) {
+        // clean up the opened file descriptor
+        close(fd);
+    }
 }
 
 bool
diff --git a/cmds/incidentd/src/report_directory.cpp b/cmds/incidentd/src/report_directory.cpp
index 110902c..65030b3 100644
--- a/cmds/incidentd/src/report_directory.cpp
+++ b/cmds/incidentd/src/report_directory.cpp
@@ -97,7 +97,8 @@
         err = BAD_VALUE;
         goto done;
     }
-    if (st.st_uid != AID_SYSTEM || st.st_gid != AID_SYSTEM) {
+    if ((st.st_uid != AID_SYSTEM && st.st_uid != AID_ROOT) ||
+        (st.st_gid != AID_SYSTEM && st.st_gid != AID_ROOT)) {
         ALOGE("No incident reports today. Owner is %d and group is %d on report directory %s",
                 st.st_uid, st.st_gid, directory);
         err = BAD_VALUE;
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index c5c38f5..60ec8a9 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -1570,11 +1570,19 @@
     private static int showUsage() {
         System.err.println("usage: pm path [--user USER_ID] PACKAGE");
         System.err.println("       pm dump PACKAGE");
-        System.err.println("       pm install [-lrtsfd] [-i PACKAGE] [--user USER_ID] [PATH]");
-        System.err.println("       pm install-create [-lrtsfdp] [-i PACKAGE] [-S BYTES]");
-        System.err.println("               [--install-location 0/1/2]");
-        System.err.println("               [--force-uuid internal|UUID]");
-        System.err.println("       pm install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH]");
+        System.err.println("       pm install [-lrtsfdg] [-i PACKAGE] [--user USER_ID]");
+        System.err.println("               [-p INHERIT_PACKAGE] [--install-location 0/1/2]");
+        System.err.println("               [--originating-uri URI] [---referrer URI]");
+        System.err.println("               [--abi ABI_NAME] [--force-sdk]");
+        System.err.println("               [--preload] [--instantapp] [--full] [--dont-kill]");
+        System.err.println("               [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES] [PATH|-]");
+        System.err.println("       pm install-create [-lrtsfdg] [-i PACKAGE] [--user USER_ID]");
+        System.err.println("               [-p INHERIT_PACKAGE] [--install-location 0/1/2]");
+        System.err.println("               [--originating-uri URI] [---referrer URI]");
+        System.err.println("               [--abi ABI_NAME] [--force-sdk]");
+        System.err.println("               [--preload] [--instantapp] [--full] [--dont-kill]");
+        System.err.println("               [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]");
+        System.err.println("       pm install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH|-]");
         System.err.println("       pm install-commit SESSION_ID");
         System.err.println("       pm install-abandon SESSION_ID");
         System.err.println("       pm uninstall [-k] [--user USER_ID] [--versionCode VERSION_CODE] PACKAGE");
@@ -1613,15 +1621,27 @@
         System.err.println("pm install: install a single legacy package");
         System.err.println("pm install-create: create an install session");
         System.err.println("    -l: forward lock application");
-        System.err.println("    -r: replace existing application");
+        System.err.println("    -r: allow replacement of existing application");
         System.err.println("    -t: allow test packages");
-        System.err.println("    -i: specify the installer package name");
+        System.err.println("    -i: specify package name of installer owning the app");
         System.err.println("    -s: install application on sdcard");
         System.err.println("    -f: install application on internal flash");
         System.err.println("    -d: allow version code downgrade (debuggable packages only)");
-        System.err.println("    -p: partial application install");
+        System.err.println("    -p: partial application install (new split on top of existing pkg)");
         System.err.println("    -g: grant all runtime permissions");
         System.err.println("    -S: size in bytes of entire session");
+        System.err.println("    --dont-kill: installing a new feature split, don't kill running app");
+        System.err.println("    --originating-uri: set URI where app was downloaded from");
+        System.err.println("    --referrer: set URI that instigated the install of the app");
+        System.err.println("    --pkg: specify expected package name of app being installed");
+        System.err.println("    --abi: override the default ABI of the platform");
+        System.err.println("    --instantapp: cause the app to be installed as an ephemeral install app");
+        System.err.println("    --full: cause the app to be installed as a non-ephemeral full app");
+        System.err.println("    --install-location: force the install location:");
+        System.err.println("        0=auto, 1=internal only, 2=prefer external");
+        System.err.println("    --force-uuid: force install on to disk volume with given UUID");
+        System.err.println("    --force-sdk: allow install even when existing app targets platform");
+        System.err.println("        codename but new one targets a final API level");
         System.err.println("");
         System.err.println("pm install-write: write a package into existing session; path may");
         System.err.println("  be '-' to read from stdin");
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
new file mode 100644
index 0000000..4ebca84
--- /dev/null
+++ b/cmds/statsd/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 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.
+//
+
+// ==========================================================
+// Build the library for use on the host
+// ==========================================================
+cc_library_host_shared {
+    name: "libstats_proto_host",
+    srcs: [
+        "src/stats_events.proto",
+    ],
+
+    shared_libs: [
+        "libplatformprotos",
+    ],
+
+    proto: {
+        type: "full",
+        export_proto_headers: true,
+    },
+}
+
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 4c95007..3c2f2d5 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -14,22 +14,56 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-# ================
-# proto static lib
-# ================
-include $(CLEAR_VARS)
+statsd_common_src := \
+    ../../core/java/android/os/IStatsCompanionService.aidl \
+    ../../core/java/android/os/IStatsManager.aidl \
+    src/stats_log.proto \
+    src/statsd_config.proto \
+    src/stats_events_copy.proto \
+    src/anomaly/AnomalyMonitor.cpp \
+    src/condition/CombinationConditionTracker.cpp \
+    src/condition/condition_util.cpp \
+    src/condition/SimpleConditionTracker.cpp \
+    src/condition/ConditionWizard.cpp \
+    src/config/ConfigKey.cpp \
+    src/config/ConfigListener.cpp \
+    src/config/ConfigManager.cpp \
+    src/external/KernelWakelockPuller.cpp \
+    src/external/StatsPullerManager.cpp \
+    src/logd/LogEvent.cpp \
+    src/logd/LogListener.cpp \
+    src/logd/LogReader.cpp \
+    src/matchers/CombinationLogMatchingTracker.cpp \
+    src/matchers/matcher_util.cpp \
+    src/matchers/SimpleLogMatchingTracker.cpp \
+    src/metrics/CountAnomalyTracker.cpp \
+    src/metrics/CountMetricProducer.cpp \
+    src/metrics/DurationMetricProducer.cpp \
+    src/metrics/MetricsManager.cpp \
+    src/metrics/metrics_manager_util.cpp \
+    src/packages/UidMap.cpp \
+    src/storage/DropboxReader.cpp \
+    src/storage/DropboxWriter.cpp \
+    src/StatsLogProcessor.cpp \
+    src/StatsService.cpp \
+    src/stats_util.cpp
 
-LOCAL_MODULE := statsd_proto
-LOCAL_MODULE_TAGS := optional
+statsd_common_c_includes := \
+    $(LOCAL_PATH)/src
 
-LOCAL_SRC_FILES := $(call all-proto-files-under, src)
+statsd_common_aidl_includes := \
+    $(LOCAL_PATH)/../../core/java
 
-LOCAL_PROTOC_FLAGS :=
-LOCAL_PROTOC_OPTIMIZE_TYPE := lite-static
-
-include $(BUILD_STATIC_LIBRARY)
-
-STATSD_PROTO_INCLUDES := $(local-generated-sources-dir)/src/$(LOCAL_PATH)
+statsd_common_shared_libraries := \
+    libbase \
+    libbinder \
+    libcutils \
+    libincident \
+    liblog \
+    libselinux \
+    libutils \
+    libservices \
+    libandroidfw
 
 # =========
 # statsd
@@ -40,9 +74,8 @@
 LOCAL_MODULE := statsd
 
 LOCAL_SRC_FILES := \
-    ../../core/java/android/os/IStatsCompanionService.aidl \
-    ../../core/java/android/os/IStatsManager.aidl \
-    $(call all-cpp-files-under,src) \
+    $(statsd_common_src) \
+    src/main.cpp
 
 LOCAL_CFLAGS += \
     -Wall \
@@ -60,24 +93,12 @@
     LOCAL_CFLAGS += \
             -Os
 endif
+LOCAL_PROTOC_OPTIMIZE_TYPE := lite-static
 
-LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/../../core/java
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/src \
-	STATSD_PROTO_INCLUDES
+LOCAL_AIDL_INCLUDES := $(statsd_common_c_includes)
+LOCAL_C_INCLUDES += $(statsd_common_c_includes)
 
-LOCAL_STATIC_LIBRARIES := statsd_proto
-
-LOCAL_SHARED_LIBRARIES := \
-        libbase \
-        libbinder \
-        libcutils \
-        libincident \
-        liblog \
-        libselinux \
-        libutils \
-        libservices \
-        libandroidfw \
-        libprotobuf-cpp-lite \
+LOCAL_SHARED_LIBRARIES := $(statsd_common_shared_libraries)
 
 LOCAL_MODULE_CLASS := EXECUTABLES
 
@@ -85,6 +106,7 @@
 
 include $(BUILD_EXECUTABLE)
 
+
 # ==============
 # statsd_test
 # ==============
@@ -95,8 +117,8 @@
 LOCAL_COMPATIBILITY_SUITE := device-tests
 LOCAL_MODULE_TAGS := tests
 
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/src \
-	STATSD_PROTO_INCLUDES
+LOCAL_AIDL_INCLUDES := $(statsd_common_c_includes)
+LOCAL_C_INCLUDES += $(statsd_common_c_includes)
 
 LOCAL_CFLAGS += \
     -Wall \
@@ -107,38 +129,27 @@
     -Wno-unused-parameter
 
 LOCAL_SRC_FILES := \
-    src/stats_log.proto \
-    src/statsd_config.proto \
-    ../../core/java/android/os/IStatsCompanionService.aidl \
-    ../../core/java/android/os/IStatsManager.aidl \
-    src/StatsService.cpp \
-    src/AnomalyMonitor.cpp \
-    src/stats_util.cpp \
-    src/LogEntryPrinter.cpp \
-    src/LogReader.cpp \
-    src/matchers/matcher_util.cpp \
-    src/condition/SimpleConditionTracker.cpp \
-    src/condition/CombinationConditionTracker.cpp \
-    src/matchers/SimpleLogMatchingTracker.cpp \
-    src/matchers/CombinationLogMatchingTracker.cpp \
-    src/metrics/metrics_manager_util.cpp \
-    src/metrics/CountMetricProducer.cpp \
-    src/metrics/CountAnomalyTracker.cpp \
-    src/condition/condition_util.cpp \
-    src/UidMap.cpp \
-    $(call all-cpp-files-under, tests) \
+    $(statsd_common_src) \
+    tests/AnomalyMonitor_test.cpp \
+    tests/ConditionTracker_test.cpp \
+    tests/ConfigManager_test.cpp \
+    tests/indexed_priority_queue_test.cpp \
+    tests/LogEntryMatcher_test.cpp \
+    tests/LogReader_test.cpp \
+    tests/MetricsManager_test.cpp \
+    tests/UidMap_test.cpp
+
 
 LOCAL_STATIC_LIBRARIES := \
-    libgmock \
-    statsd_proto \
+    libgmock
 
-LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    libbinder \
-    libcutils \
-    liblog \
-    libselinux \
-    libutils \
-    libprotobuf-cpp-lite \
+LOCAL_SHARED_LIBRARIES := $(statsd_common_shared_libraries)
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := lite
+
+statsd_common_src:=
+statsd_common_aidl_includes:=
+statsd_common_c_includes:=
 
 include $(BUILD_NATIVE_TEST)
+
diff --git a/cmds/statsd/src/AnomalyMonitor.cpp b/cmds/statsd/src/AnomalyMonitor.cpp
deleted file mode 100644
index 4fbbc7a..0000000
--- a/cmds/statsd/src/AnomalyMonitor.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "AnomalyMonitor"
-#define DEBUG true
-
-#include "AnomalyMonitor.h"
-
-#include <cutils/log.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-AnomalyMonitor::AnomalyMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec)
-    : mRegisteredAlarmTimeSec(0), mMinUpdateTimeSec(minDiffToUpdateRegisteredAlarmTimeSec) {
-}
-
-AnomalyMonitor::~AnomalyMonitor() {
-}
-
-void AnomalyMonitor::setStatsCompanionService(sp<IStatsCompanionService> statsCompanionService) {
-    std::lock_guard<std::mutex> lock(mLock);
-    sp<IStatsCompanionService> tmpForLock = mStatsCompanionService;
-    mStatsCompanionService = statsCompanionService;
-    if (statsCompanionService == nullptr) {
-        if (DEBUG) ALOGD("Erasing link to statsCompanionService");
-        return;
-    }
-    if (DEBUG) ALOGD("Creating link to statsCompanionService");
-    const sp<const AnomalyAlarm> top = mPq.top();
-    if (top != nullptr) {
-        updateRegisteredAlarmTime_l(top->timestampSec);
-    }
-}
-
-void AnomalyMonitor::add(sp<const AnomalyAlarm> alarm) {
-    std::lock_guard<std::mutex> lock(mLock);
-    if (alarm == nullptr) {
-        ALOGW("Asked to add a null alarm.");
-        return;
-    }
-    if (alarm->timestampSec < 1) {
-        // forbidden since a timestamp 0 is used to indicate no alarm registered
-        ALOGW("Asked to add a 0-time alarm.");
-        return;
-    }
-    // TODO: Ensure that refractory period is respected.
-    if (DEBUG) ALOGD("Adding alarm with time %u", alarm->timestampSec);
-    mPq.push(alarm);
-    if (mRegisteredAlarmTimeSec < 1 ||
-        alarm->timestampSec + mMinUpdateTimeSec < mRegisteredAlarmTimeSec) {
-        updateRegisteredAlarmTime_l(alarm->timestampSec);
-    }
-}
-
-void AnomalyMonitor::remove(sp<const AnomalyAlarm> alarm) {
-    std::lock_guard<std::mutex> lock(mLock);
-    if (alarm == nullptr) {
-        ALOGW("Asked to remove a null alarm.");
-        return;
-    }
-    if (DEBUG) ALOGD("Removing alarm with time %u", alarm->timestampSec);
-    mPq.remove(alarm);
-    if (mPq.empty()) {
-        if (DEBUG) ALOGD("Queue is empty. Cancel any alarm.");
-        mRegisteredAlarmTimeSec = 0;
-        if (mStatsCompanionService != nullptr) {
-            mStatsCompanionService->cancelAnomalyAlarm();
-        }
-        return;
-    }
-    uint32_t soonestAlarmTimeSec = mPq.top()->timestampSec;
-    if (DEBUG) ALOGD("Soonest alarm is %u", soonestAlarmTimeSec);
-    if (soonestAlarmTimeSec > mRegisteredAlarmTimeSec + mMinUpdateTimeSec) {
-        updateRegisteredAlarmTime_l(soonestAlarmTimeSec);
-    }
-}
-
-// More efficient than repeatedly calling remove(mPq.top()) since it batches the
-// updates to the registered alarm.
-unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>
-                AnomalyMonitor::popSoonerThan(uint32_t timestampSec) {
-
-    if (DEBUG) ALOGD("Removing alarms with time <= %u", timestampSec);
-    unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> oldAlarms;
-    std::lock_guard<std::mutex> lock(mLock);
-
-    for (sp<const AnomalyAlarm> t = mPq.top();
-                t != nullptr && t->timestampSec <= timestampSec; t = mPq.top()) {
-        oldAlarms.insert(t);
-        mPq.pop(); // remove t
-    }
-    // Always update registered alarm time (if anything has changed).
-    if (!oldAlarms.empty()) {
-        if (mPq.empty()) {
-            if (DEBUG) ALOGD("Queue is empty. Cancel any alarm.");
-            mRegisteredAlarmTimeSec = 0;
-            if (mStatsCompanionService != nullptr) {
-                mStatsCompanionService->cancelAnomalyAlarm();
-            }
-        } else {
-            // Always update the registered alarm in this case (unlike remove()).
-            updateRegisteredAlarmTime_l(mPq.top()->timestampSec);
-        }
-    }
-    return oldAlarms;
-}
-
-void AnomalyMonitor::updateRegisteredAlarmTime_l(uint32_t timestampSec) {
-    if (DEBUG) ALOGD("Updating reg alarm time to %u", timestampSec);
-    mRegisteredAlarmTimeSec = timestampSec;
-    if (mStatsCompanionService != nullptr) {
-        mStatsCompanionService->setAnomalyAlarm(secToMs(mRegisteredAlarmTimeSec));
-    }
-}
-
-int64_t AnomalyMonitor::secToMs(uint32_t timeSec) {
-    return ((int64_t)timeSec) * 1000;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/AnomalyMonitor.h b/cmds/statsd/src/AnomalyMonitor.h
deleted file mode 100644
index 7c6e5e8..0000000
--- a/cmds/statsd/src/AnomalyMonitor.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANOMALY_MONITOR_H
-#define ANOMALY_MONITOR_H
-
-#include <android/os/IStatsCompanionService.h>
-#include <indexed_priority_queue.h>
-#include <utils/RefBase.h>
-
-#include <unordered_set>
-#include <queue>
-#include <vector>
-
-using namespace android;
-
-using android::os::IStatsCompanionService;
-using std::unordered_set;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * Represents an alarm, associated with some aggregate metric, holding a
- * projected time at which the metric is expected to exceed its anomaly
- * threshold.
- * Timestamps are in seconds since epoch in a uint32, so will fail in year 2106.
- */
-struct AnomalyAlarm : public RefBase {
-    AnomalyAlarm(uint32_t timestampSec) : timestampSec(timestampSec) {
-    }
-
-    const uint32_t timestampSec;
-
-    /** AnomalyAlarm a is smaller (higher priority) than b if its timestamp is sooner. */
-    struct SmallerTimestamp {
-        bool operator()(sp<const AnomalyAlarm> a, sp<const AnomalyAlarm> b) const {
-            return (a->timestampSec < b->timestampSec);
-        }
-    };
-};
-
-/**
- * Manages alarms for Anomaly Detection.
- */
-class AnomalyMonitor : public RefBase {
-public:
-    /**
-     * @param minDiffToUpdateRegisteredAlarmTimeSec If the soonest alarm differs
-     * from the registered alarm by more than this amount, update the registered
-     * alarm.
-     */
-    AnomalyMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec);
-    ~AnomalyMonitor();
-
-    /**
-     * Tells AnomalyMonitor what IStatsCompanionService to use and, if
-     * applicable, immediately registers an existing alarm with it.
-     * If nullptr, AnomalyMonitor will continue to add/remove alarms, but won't
-     * update IStatsCompanionService (until such time as it is set non-null).
-     */
-    void setStatsCompanionService(sp<IStatsCompanionService> statsCompanionService);
-
-    /**
-     * Adds the given alarm (reference) to the queue.
-     */
-    void add(sp<const AnomalyAlarm> alarm);
-
-    /**
-     * Removes the given alarm (reference) from the queue.
-     * Note that alarm comparison is reference-based; if another alarm exists
-     * with the same timestampSec, that alarm will still remain in the queue.
-     */
-    void remove(sp<const AnomalyAlarm> alarm);
-
-    /**
-     * Returns and removes all alarms whose timestamp <= the given timestampSec.
-     * Always updates the registered alarm if return is non-empty.
-     */
-    unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>
-                    popSoonerThan(uint32_t timestampSec);
-
-    /**
-     * Returns the projected alarm timestamp that is registered with
-     * StatsCompanionService. This may not be equal to the soonest alarm,
-     * but should be within minDiffToUpdateRegisteredAlarmTimeSec of it.
-     */
-    uint32_t getRegisteredAlarmTimeSec() const {
-        return mRegisteredAlarmTimeSec;
-    }
-
-private:
-    std::mutex mLock;
-
-    /**
-     * Timestamp (seconds since epoch) of the alarm registered with
-     * StatsCompanionService. This, in general, may not be equal to the soonest
-     * alarm stored in mPq, but should be within minUpdateTimeSec of it.
-     * A value of 0 indicates that no alarm is currently registered.
-     */
-    uint32_t mRegisteredAlarmTimeSec;
-
-    /**
-     * Priority queue of alarms, prioritized by soonest alarm.timestampSec.
-     */
-    indexed_priority_queue<AnomalyAlarm, AnomalyAlarm::SmallerTimestamp> mPq;
-
-    /**
-     * Binder interface for communicating with StatsCompanionService.
-     */
-    sp<IStatsCompanionService> mStatsCompanionService = nullptr;
-
-    /**
-     * Amount by which the soonest projected alarm must differ from
-     * mRegisteredAlarmTimeSec before updateRegisteredAlarmTime_l is called.
-     */
-    uint32_t mMinUpdateTimeSec;
-
-    /**
-     * Updates the alarm registered with StatsCompanionService to the given time.
-     * Also correspondingly updates mRegisteredAlarmTimeSec.
-     */
-    void updateRegisteredAlarmTime_l(uint32_t timestampSec);
-
-    /** Converts uint32 timestamp in seconds to a Java long in msec. */
-    int64_t secToMs(uint32_t timeSec);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#endif  // ANOMALY_MONITOR_H
\ No newline at end of file
diff --git a/cmds/statsd/src/DropboxReader.cpp b/cmds/statsd/src/DropboxReader.cpp
deleted file mode 100644
index 430e7af..0000000
--- a/cmds/statsd/src/DropboxReader.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <android-base/file.h>
-#include <android/os/DropBoxManager.h>
-#include <androidfw/ZipUtils.h>
-
-#include "DropboxReader.h"
-
-using android::String16;
-using android::ZipUtils;
-using android::base::unique_fd;
-using android::binder::Status;
-using android::os::DropBoxManager;
-using android::sp;
-using std::vector;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-status_t DropboxReader::readStatsLogs(FILE* out, const string& tag, long msec) {
-    sp<DropBoxManager> dropbox = new DropBoxManager();
-    StatsLogReport logReport;
-
-    long timestamp = msec;
-    // instead of while(true), put a hard limit 1000. Dropbox won't have more than 1000 files.
-    for (int i = 0; i < 1000; i++) {
-        DropBoxManager::Entry entry;
-        Status status = dropbox->getNextEntry(String16(tag.c_str()), timestamp, &entry);
-        if (!status.isOk()) {
-            ALOGD("No more entries, or failed to read. We can't tell unfortunately.");
-            return android::OK;
-        }
-
-        const unique_fd& fd = entry.getFd();
-
-        // use this timestamp for next query.
-        timestamp = entry.getTimestamp();
-
-        if (entry.getFlags() & DropBoxManager::IS_GZIPPED) {
-            if (!parseFromGzipFile(fd, logReport)) {
-                // Failed to parse from the file. Continue to fetch the next entry.
-                continue;
-            }
-        } else {
-            if (!parseFromFile(fd, logReport)) {
-                // Failed to parse from the file. Continue to fetch the next entry.
-                continue;
-            }
-        }
-
-        printLog(out, logReport);
-    }
-    return android::OK;
-}
-
-bool DropboxReader::parseFromGzipFile(const unique_fd& fd, StatsLogReport& logReport) {
-    FILE* file = fdopen(fd, "r");
-    bool result = false;
-    bool scanResult;
-    int method;
-    long compressedLen;
-    long uncompressedLen;
-    unsigned long crc32;
-    scanResult = ZipUtils::examineGzip(file, &method, &uncompressedLen, &compressedLen, &crc32);
-    if (scanResult && method == kCompressDeflated) {
-        vector<uint8_t> buf(uncompressedLen);
-        if (ZipUtils::inflateToBuffer(file, &buf[0], uncompressedLen, compressedLen)) {
-            if (logReport.ParseFromArray(&buf[0], uncompressedLen)) {
-                result = true;
-            }
-        }
-    } else {
-        ALOGE("This isn't a valid deflated gzip file");
-    }
-    fclose(file);
-    return result;
-}
-
-// parse a non zipped file.
-bool DropboxReader::parseFromFile(const unique_fd& fd, StatsLogReport& logReport) {
-    string content;
-    if (!android::base::ReadFdToString(fd, &content)) {
-        ALOGE("Failed to read file");
-        return false;
-    }
-    if (!logReport.ParseFromString(content)) {
-        ALOGE("failed to parse log entry from data");
-        return false;
-    }
-    return true;
-}
-
-void DropboxReader::printLog(FILE* out, const StatsLogReport& logReport) {
-    fprintf(out, "start_time_ns=%lld, end_time_ns=%lld, ", logReport.start_report_nanos(),
-            logReport.end_report_nanos());
-    for (int i = 0; i < logReport.event_metrics().data_size(); i++) {
-        EventMetricData eventMetricData = logReport.event_metrics().data(i);
-        // TODO: Pretty-print the proto.
-        // fprintf(out, "EventMetricData=%s", eventMetricData.SerializeAsString().c_str());
-    }
-    fprintf(out, "\n");
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/DropboxWriter.cpp b/cmds/statsd/src/DropboxWriter.cpp
deleted file mode 100644
index b72e530..0000000
--- a/cmds/statsd/src/DropboxWriter.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android/os/DropBoxManager.h>
-
-#include "DropboxWriter.h"
-
-using android::String16;
-using android::binder::Status;
-using android::os::DropBoxManager;
-using android::sp;
-using std::vector;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-DropboxWriter::DropboxWriter(const string& tag) : mTag(tag), mLogReport(), mBufferSize(0) {
-}
-
-void DropboxWriter::addEventMetricData(const EventMetricData& eventMetricData) {
-    flushIfNecessary(eventMetricData);
-    EventMetricData* newEntry = mLogReport.mutable_event_metrics()->add_data();
-    newEntry->CopyFrom(eventMetricData);
-    mBufferSize += eventMetricData.ByteSize();
-}
-
-void DropboxWriter::flushIfNecessary(const EventMetricData& eventMetricData) {
-    if (eventMetricData.ByteSize() + mBufferSize > kMaxSerializedBytes) {
-        flush();
-    }
-}
-
-void DropboxWriter::flush() {
-    // now we get an exact byte size of the output
-    const int numBytes = mLogReport.ByteSize();
-    vector<uint8_t> buffer(numBytes);
-    sp<DropBoxManager> dropbox = new DropBoxManager();
-    mLogReport.SerializeToArray(&buffer[0], numBytes);
-    Status status = dropbox->addData(String16(mTag.c_str()), &buffer[0], numBytes, 0 /* no flag */);
-    if (!status.isOk()) {
-        ALOGE("failed to write to dropbox");
-        // TODO: What to do if flush fails??
-    }
-    mLogReport.Clear();
-    mBufferSize = 0;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/KernelWakelockPuller.cpp b/cmds/statsd/src/KernelWakelockPuller.cpp
deleted file mode 100644
index 1798f9d..0000000
--- a/cmds/statsd/src/KernelWakelockPuller.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "KernelWakelockPuller.h"
-#include <android/os/IStatsCompanionService.h>
-#include <binder/IPCThreadState.h>
-#include <cutils/log.h>
-#include <private/android_filesystem_config.h>
-#include "StatsPuller.h"
-#include "StatsService.h"
-
-using namespace android;
-using namespace android::base;
-using namespace android::binder;
-using namespace android::os;
-using namespace std;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-const int KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS = 20;
-
-// The reading and parsing are implemented in Java. It is not difficult to port over. But for now
-// let StatsCompanionService handle that and send the data back.
-String16 KernelWakelockPuller::pull() {
-    sp<IStatsCompanionService> statsCompanion = StatsService::getStatsCompanionService();
-    String16 returned_value("");
-    if (statsCompanion != NULL) {
-      Status status = statsCompanion->pullData(KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS,
-                                             &returned_value);
-      if (!status.isOk()) {
-          ALOGW("error pulling kernel wakelock");
-      }
-      ALOGD("KernelWakelockPuller::pull succeeded!");
-      // TODO: remove this when we integrate into aggregation chain.
-      ALOGD("%s", String8(returned_value).string());
-      return returned_value;
-    } else {
-        ALOGW("statsCompanion not found!");
-        return String16();
-    }
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/KernelWakelockPuller.h b/cmds/statsd/src/KernelWakelockPuller.h
deleted file mode 100644
index 1c16f87..0000000
--- a/cmds/statsd/src/KernelWakelockPuller.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef STATSD_KERNELWAKELOCKPULLER_H
-#define STATSD_KERNELWAKELOCKPULLER_H
-
-#include <utils/String16.h>
-#include "StatsPuller.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class KernelWakelockPuller : public StatsPuller {
-public:
-    // a number of stats need to be pulled from StatsCompanionService
-    //
-    const static int PULL_CODE_KERNEL_WAKELOCKS;
-    String16 pull() override;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#endif  // STATSD_KERNELWAKELOCKPULLER_H
diff --git a/cmds/statsd/src/Log.h b/cmds/statsd/src/Log.h
new file mode 100644
index 0000000..7852709
--- /dev/null
+++ b/cmds/statsd/src/Log.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file must be included at the top of the file. Other header files
+ * occasionally include log.h, and if LOG_TAG isn't set when that happens
+ * we'll get a preprocesser error when we try to define it here.
+ */
+
+#pragma once
+
+#define LOG_TAG "statsd"
+
+#include <log/log.h>
+
+#define VLOG(...) \
+    if (DEBUG) ALOGD(__VA_ARGS__);
diff --git a/cmds/statsd/src/LogEntryPrinter.cpp b/cmds/statsd/src/LogEntryPrinter.cpp
deleted file mode 100644
index 63465b0..0000000
--- a/cmds/statsd/src/LogEntryPrinter.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <LogEntryPrinter.h>
-
-#include <log/event_tag_map.h>
-#include <log/logprint.h>
-#include <utils/Errors.h>
-
-using namespace android;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-LogEntryPrinter::LogEntryPrinter(int out) : m_out(out) {
-    // Initialize the EventTagMap, which is how we know the names of the numeric event tags.
-    // If this fails, we can't print well, but something will print.
-    m_tags = android_openEventTagMap(NULL);
-
-    // Printing format
-    m_format = android_log_format_new();
-    android_log_setPrintFormat(m_format, FORMAT_THREADTIME);
-}
-
-LogEntryPrinter::~LogEntryPrinter() {
-    if (m_tags != NULL) {
-        android_closeEventTagMap(m_tags);
-    }
-    android_log_format_free(m_format);
-}
-
-void LogEntryPrinter::OnLogEvent(const log_msg& msg) {
-    status_t err;
-    AndroidLogEntry entry;
-    char buf[1024];
-
-    err = android_log_processBinaryLogBuffer(&(const_cast<log_msg*>(&msg)->entry_v1), &entry,
-                                             m_tags, buf, sizeof(buf));
-    if (err == NO_ERROR) {
-        android_log_printLogLine(m_format, m_out, &entry);
-    } else {
-        printf("log entry: %s\n", buf);
-        fflush(stdout);
-    }
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/LogEntryPrinter.h b/cmds/statsd/src/LogEntryPrinter.h
deleted file mode 100644
index 4f79028..0000000
--- a/cmds/statsd/src/LogEntryPrinter.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef LOG_ENTRY_PRINTER_H
-#define LOG_ENTRY_PRINTER_H
-
-#include "LogReader.h"
-
-#include <log/logprint.h>
-
-#include <stdio.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * Decodes the log entry and prints it to the supplied file descriptor.
- */
-class LogEntryPrinter : public LogListener {
-public:
-    LogEntryPrinter(int out);
-    virtual ~LogEntryPrinter();
-
-    virtual void OnLogEvent(const log_msg& msg);
-
-private:
-    /**
-     * Where to write to.
-     */
-    int m_out;
-
-    /**
-     * Numeric to string tag name mapping.
-     */
-    EventTagMap* m_tags;
-
-    /**
-     * Pretty printing format.
-     */
-    AndroidLogFormat* m_format;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#endif  // LOG_ENTRY_PRINTER_H
diff --git a/cmds/statsd/src/LogReader.cpp b/cmds/statsd/src/LogReader.cpp
deleted file mode 100644
index c4ac337..0000000
--- a/cmds/statsd/src/LogReader.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "LogReader.h"
-
-#include <log/log_read.h>
-
-#include <utils/Errors.h>
-
-#include <time.h>
-#include <unistd.h>
-
-using namespace android;
-using namespace std;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-#define SNOOZE_INITIAL_MS 100
-#define SNOOZE_MAX_MS (10 * 60 * 1000)  // Ten minutes
-
-// ================================================================================
-LogListener::LogListener() {
-}
-
-LogListener::~LogListener() {
-}
-
-// ================================================================================
-LogReader::LogReader() {
-}
-
-LogReader::~LogReader() {
-}
-
-void LogReader::AddListener(const sp<LogListener>& listener) {
-    m_listeners.push_back(listener);
-}
-
-void LogReader::Run() {
-    int nextSnoozeMs = SNOOZE_INITIAL_MS;
-
-    // In an ideal world, this outer loop will only ever run one iteration, but it
-    // exists to handle crashes in logd.  The inner loop inside connect_and_read()
-    // reads from logd forever, but if that read fails, we fall out to the outer
-    // loop, do the backoff (resetting the backoff timeout if we successfully read
-    // something), and then try again.
-    while (true) {
-        // Connect and read
-        int lineCount = connect_and_read();
-
-        // Figure out how long to sleep.
-        if (lineCount > 0) {
-            // If we managed to read at least one line, reset the backoff
-            nextSnoozeMs = SNOOZE_INITIAL_MS;
-        } else {
-            // Otherwise, expontial backoff
-            nextSnoozeMs *= 1.5f;
-            if (nextSnoozeMs > 10 * 60 * 1000) {
-                // Don't wait for toooo long.
-                nextSnoozeMs = SNOOZE_MAX_MS;
-            }
-        }
-
-        // Sleep
-        timespec ts;
-        timespec rem;
-        ts.tv_sec = nextSnoozeMs / 1000;
-        ts.tv_nsec = (nextSnoozeMs % 1000) * 1000000L;
-        while (nanosleep(&ts, &rem) == -1) {
-            if (errno == EINTR) {
-                ts = rem;
-            }
-            // other errors are basically impossible
-        }
-    }
-}
-
-int LogReader::connect_and_read() {
-    int lineCount = 0;
-    status_t err;
-    logger_list* loggers;
-    logger* eventLogger;
-
-    // Prepare the logging context
-    loggers = android_logger_list_alloc(ANDROID_LOG_RDONLY,
-                                        /* don't stop after N lines */ 0,
-                                        /* no pid restriction */ 0);
-
-    // Open the buffer(s)
-    eventLogger = android_logger_open(loggers, LOG_ID_STATS);
-
-    // Read forever
-    if (eventLogger) {
-        while (true) {
-            log_msg msg;
-
-            // Read a message
-            err = android_logger_list_read(loggers, &msg);
-            if (err < 0) {
-                fprintf(stderr, "logcat read failure: %s\n", strerror(err));
-                break;
-            }
-
-            // Record that we read one (used above to know how to snooze).
-            lineCount++;
-
-            // Call the listeners
-            for (vector<sp<LogListener> >::iterator it = m_listeners.begin();
-                 it != m_listeners.end(); it++) {
-                (*it)->OnLogEvent(msg);
-            }
-        }
-    }
-
-    // Free the logger list and close the individual loggers
-    android_logger_list_free(loggers);
-
-    return lineCount;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/LogReader.h b/cmds/statsd/src/LogReader.h
deleted file mode 100644
index fc19585..0000000
--- a/cmds/statsd/src/LogReader.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef LOGREADER_H
-#define LOGREADER_H
-
-#include <log/log_read.h>
-#include <utils/RefBase.h>
-
-#include <vector>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * Callback for LogReader
- */
-class LogListener : public virtual android::RefBase {
-public:
-    LogListener();
-    virtual ~LogListener();
-
-    // TODO: Rather than using log_msg, which doesn't have any real internal structure
-    // here, we should pull this out into our own LogEntry class.
-    virtual void OnLogEvent(const log_msg& msg) = 0;
-};
-
-/**
- * Class to read logs from logd.
- */
-class LogReader : public virtual android::RefBase {
-public:
-    /**
-     * Construct the LogReader with a pointer back to the StatsService
-     */
-    LogReader();
-
-    /**
-     * Destructor.
-     */
-    virtual ~LogReader();
-
-    /**
-     * Add a LogListener class.
-     */
-    void AddListener(const android::sp<LogListener>& listener);
-
-    /**
-     * Run the main LogReader loop
-     */
-    void Run();
-
-private:
-    /**
-     * List of listeners to call back on when we do get an event.
-     */
-    std::vector<android::sp<LogListener> > m_listeners;
-
-    /**
-     * Connect to a single instance of logd, and read until there's a read error.
-     * Logd can crash, exit, be killed etc.
-     *
-     * Returns the number of lines that were read.
-     */
-    int connect_and_read();
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#endif  // LOGREADER_H
diff --git a/cmds/statsd/src/PackageInfoListener.h b/cmds/statsd/src/PackageInfoListener.h
deleted file mode 100644
index 476c1d9..0000000
--- a/cmds/statsd/src/PackageInfoListener.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef STATSD_PACKAGE_INFO_LISTENER_H
-#define STATSD_PACKAGE_INFO_LISTENER_H
-
-#include <utils/RefBase.h>
-#include <string>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class PackageInfoListener : public virtual android::RefBase {
-public:
-    // Uid map will notify this listener that the app with apk name and uid has been upgraded to
-    // the specified version.
-    virtual void notifyAppUpgrade(const std::string& apk, const int uid, const int version) = 0;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#endif //STATSD_PACKAGE_INFO_LISTENER_H
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index f877ef3..e7825cf 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -14,12 +14,14 @@
  * limitations under the License.
  */
 
-#include <StatsLogProcessor.h>
+#include "Log.h"
 
-#include <cutils/log.h>
-#include <frameworks/base/cmds/statsd/src/stats_log.pb.h>
+#include "StatsLogProcessor.h"
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "metrics/CountMetricProducer.h"
+#include "stats_util.h"
+
 #include <log/log_event_list.h>
-#include <metrics/CountMetricProducer.h>
 #include <utils/Errors.h>
 
 using namespace android;
@@ -31,22 +33,20 @@
 namespace os {
 namespace statsd {
 
-StatsLogProcessor::StatsLogProcessor(const sp<UidMap> &uidMap)
-        : m_dropbox_writer("all-logs"), m_UidMap(uidMap)
-{
-    // hardcoded config
-    // this should be called from StatsService when it receives a statsd_config
-    UpdateConfig(0, buildFakeConfig());
+StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap)
+    : m_dropbox_writer("all-logs"), mUidMap(uidMap) {
 }
 
 StatsLogProcessor::~StatsLogProcessor() {
 }
 
 // TODO: what if statsd service restarts? How do we know what logs are already processed before?
-void StatsLogProcessor::OnLogEvent(const log_msg& msg) {
+void StatsLogProcessor::OnLogEvent(const LogEvent& msg) {
     // TODO: Use EventMetric to filter the events we want to log.
+    /* TODO: Convert this when we have the generic protobuf writing library in.
     EventMetricData eventMetricData = parse(msg);
     m_dropbox_writer.addEventMetricData(eventMetricData);
+    */
 
     // pass the event to metrics managers.
     for (auto& pair : mMetricsManagers) {
@@ -54,17 +54,18 @@
     }
 }
 
-void StatsLogProcessor::UpdateConfig(const int config_source, const StatsdConfig& config) {
-    auto it = mMetricsManagers.find(config_source);
+void StatsLogProcessor::OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config) {
+    auto it = mMetricsManagers.find(key);
     if (it != mMetricsManagers.end()) {
         it->second->finish();
     }
 
-    ALOGD("Updated configuration for source %i", config_source);
+    ALOGD("Updated configuration for key %s", key.ToString().c_str());
 
     unique_ptr<MetricsManager> newMetricsManager = std::make_unique<MetricsManager>(config);
     if (newMetricsManager->isConfigValid()) {
-        mMetricsManagers.insert({config_source, std::move(newMetricsManager)});
+        mMetricsManagers[key] = std::move(newMetricsManager);
+        // Why doesn't this work? mMetricsManagers.insert({key, std::move(newMetricsManager)});
         ALOGD("StatsdConfig valid");
     } else {
         // If there is any error in the config, don't use it.
@@ -72,6 +73,24 @@
     }
 }
 
+vector<StatsLogReport> StatsLogProcessor::onDumpReport(const ConfigKey& key) {
+    auto it = mMetricsManagers.find(key);
+    if (it == mMetricsManagers.end()) {
+        ALOGW("Config source %s does not exist", key.ToString().c_str());
+        return vector<StatsLogReport>();
+    }
+
+    return it->second->onDumpReport();
+}
+
+void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) {
+    auto it = mMetricsManagers.find(key);
+    if (it != mMetricsManagers.end()) {
+        it->second->finish();
+        mMetricsManagers.erase(it);
+    }
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 05e441c..3cefd29 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -16,14 +16,14 @@
 #ifndef STATS_LOG_PROCESSOR_H
 #define STATS_LOG_PROCESSOR_H
 
-#include "DropboxWriter.h"
-#include "LogReader.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "config/ConfigListener.h"
+#include "logd/LogReader.h"
 #include "metrics/MetricsManager.h"
-#include "stats_util.h"
-#include "UidMap.h"
+#include "packages/UidMap.h"
+#include "storage/DropboxWriter.h"
 
-#include <log/logprint.h>
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
 #include <stdio.h>
 #include <unordered_map>
 
@@ -31,22 +31,26 @@
 namespace os {
 namespace statsd {
 
-class StatsLogProcessor : public LogListener {
+class StatsLogProcessor : public ConfigListener {
 public:
-    StatsLogProcessor(const sp<UidMap> &uidMap);
+    StatsLogProcessor(const sp<UidMap>& uidMap);
     virtual ~StatsLogProcessor();
 
-    virtual void OnLogEvent(const log_msg& msg);
+    virtual void OnLogEvent(const LogEvent& event);
 
-    void UpdateConfig(const int config_source, const StatsdConfig& config);
+    void OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config);
+    void OnConfigRemoved(const ConfigKey& key);
+
+    // TODO: Once we have the ProtoOutputStream in c++, we can just return byte array.
+    std::vector<StatsLogReport> onDumpReport(const ConfigKey& key);
 
 private:
     // TODO: use EventMetrics to log the events.
     DropboxWriter m_dropbox_writer;
 
-    std::unordered_map<int, std::unique_ptr<MetricsManager>> mMetricsManagers;
+    std::unordered_map<ConfigKey, std::unique_ptr<MetricsManager>> mMetricsManagers;
 
-    sp<UidMap> m_UidMap; // Reference to the UidMap to lookup app name and version for each uid.
+    sp<UidMap> mUidMap;  // Reference to the UidMap to lookup app name and version for each uid.
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/StatsPullerManager.cpp b/cmds/statsd/src/StatsPullerManager.cpp
deleted file mode 100644
index f4cf1ce..0000000
--- a/cmds/statsd/src/StatsPullerManager.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "StatsPullerManager"
-#define DEBUG true
-
-#include "StatsPullerManager.h"
-#include <android/os/IStatsCompanionService.h>
-#include <cutils/log.h>
-#include "StatsService.h"
-#include "KernelWakelockPuller.h"
-
-
-using namespace android;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-const int StatsPullerManager::KERNEL_WAKELOCKS = 1;
-
-StatsPullerManager::StatsPullerManager() {
-    mStatsPullers.insert(
-            {static_cast<int>(KERNEL_WAKELOCKS), std::make_unique<KernelWakelockPuller>()});
-}
-
-String16 StatsPullerManager::pull(int pullCode) {
-    if (DEBUG) ALOGD("Initiating pulling %d", pullCode);
-    if (mStatsPullers.find(pullCode) != mStatsPullers.end()) {
-        return (mStatsPullers.find(pullCode)->second)->pull();
-    } else {
-        ALOGD("Unknown pull code %d", pullCode);
-        return String16();
-    }
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/StatsPullerManager.h b/cmds/statsd/src/StatsPullerManager.h
deleted file mode 100644
index ab36df5..0000000
--- a/cmds/statsd/src/StatsPullerManager.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef STATSD_STATSPULLERMANAGER_H
-#define STATSD_STATSPULLERMANAGER_H
-
-#include <utils/String16.h>
-#include <unordered_map>
-#include "StatsPuller.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-const static int KERNEL_WAKELOCKS = 1;
-
-class StatsPullerManager {
-public:
-    // Enums of pulled data types (pullCodes)
-    // These values must be kept in sync with com/android/server/stats/StatsCompanionService.java.
-    // TODO: pull the constant from stats_events.proto instead
-    const static int KERNEL_WAKELOCKS;
-    StatsPullerManager();
-
-    String16 pull(const int pullCode);
-
-private:
-    std::unordered_map<int, std::unique_ptr<StatsPuller>> mStatsPullers;
-};
-
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#endif  // STATSD_STATSPULLERMANAGER_H
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index b496404..87616d3 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -14,16 +14,15 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "statsd"
 #define DEBUG true
+#include "Log.h"
 
 #include "StatsService.h"
-#include "DropboxReader.h"
+#include "storage/DropboxReader.h"
 
 #include <android-base/file.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
-#include <cutils/log.h>
 #include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
 #include <private/android_filesystem_config.h>
 #include <utils/Looper.h>
@@ -31,6 +30,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/system_properties.h>
 #include <unistd.h>
 
 using namespace android;
@@ -39,24 +39,64 @@
 namespace os {
 namespace statsd {
 
+// ======================================================================
+/**
+ * Watches for the death of the stats companion (system process).
+ */
+class CompanionDeathRecipient : public IBinder::DeathRecipient {
+public:
+    CompanionDeathRecipient(const sp<AnomalyMonitor>& anomalyMonitor);
+    virtual void binderDied(const wp<IBinder>& who);
+
+private:
+    const sp<AnomalyMonitor> mAnomalyMonitor;
+};
+
+CompanionDeathRecipient::CompanionDeathRecipient(const sp<AnomalyMonitor>& anomalyMonitor)
+    : mAnomalyMonitor(anomalyMonitor) {
+}
+
+void CompanionDeathRecipient::binderDied(const wp<IBinder>& who) {
+    ALOGW("statscompanion service died");
+    mAnomalyMonitor->setStatsCompanionService(nullptr);
+}
+
+// ======================================================================
 StatsService::StatsService(const sp<Looper>& handlerLooper)
-    :   mAnomalyMonitor(new AnomalyMonitor(2)),m_UidMap(new UidMap()), mStatsPullerManager()
-    // TODO: Change AnomalyMonitor initialization based on the config
+    : mStatsPullerManager(),
+      mAnomalyMonitor(new AnomalyMonitor(2))  // TODO: Put this comment somewhere better
 {
-    ALOGD("stats service constructed");
+    mUidMap = new UidMap();
+    mConfigManager = new ConfigManager();
+    mProcessor = new StatsLogProcessor(mUidMap);
+
+    mConfigManager->AddListener(mProcessor);
+
+    init_system_properties();
 }
 
 StatsService::~StatsService() {
 }
 
-status_t StatsService::setProcessor(const sp<StatsLogProcessor>& main_processor) {
-    m_processor = main_processor;
-    ALOGD("stats service set to processor %p", m_processor.get());
-    return NO_ERROR;
+void StatsService::init_system_properties() {
+    mEngBuild = false;
+    const prop_info* buildType = __system_property_find("ro.build.type");
+    if (buildType != NULL) {
+        __system_property_read_callback(buildType, init_build_type_callback, this);
+    }
 }
 
-// Implement our own because the default binder implementation isn't
-// properly handling SHELL_COMMAND_TRANSACTION
+void StatsService::init_build_type_callback(void* cookie, const char* /*name*/, const char* value,
+                                            uint32_t serial) {
+    if (0 == strcmp("eng", value) || 0 == strcmp("userdebug", value)) {
+        reinterpret_cast<StatsService*>(cookie)->mEngBuild = true;
+    }
+}
+
+/**
+ * Implement our own because the default binder implementation isn't
+ * properly handling SHELL_COMMAND_TRANSACTION.
+ */
 status_t StatsService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
                                   uint32_t flags) {
     status_t err;
@@ -105,58 +145,214 @@
     }
 }
 
+/**
+ * Write debugging data about statsd.
+ */
 status_t StatsService::dump(int fd, const Vector<String16>& args) {
     FILE* out = fdopen(fd, "w");
     if (out == NULL) {
         return NO_MEMORY;  // the fd is already open
     }
 
-    fprintf(out, "StatsService::dump:");
-    ALOGD("StatsService::dump:");
-    const int N = args.size();
-    for (int i = 0; i < N; i++) {
-        fprintf(out, " %s", String8(args[i]).string());
-        ALOGD("   %s", String8(args[i]).string());
-    }
-    fprintf(out, "\n");
+    // TODO: Proto format for incident reports
+    dump_impl(out);
 
     fclose(out);
     return NO_ERROR;
 }
 
+/**
+ * Write debugging data about statsd in text format.
+ */
+void StatsService::dump_impl(FILE* out) {
+    mConfigManager->Dump(out);
+}
+
+/**
+ * Implementation of the adb shell cmd stats command.
+ */
 status_t StatsService::command(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
-    if (args.size() > 0) {
-        if (!args[0].compare(String8("print-stats-log")) && args.size() > 1) {
-            return doPrintStatsLog(out, args);
-        }
+    // TODO: Permission check
+
+    const int argCount = args.size();
+    if (argCount >= 1) {
+        // adb shell cmd stats config ...
         if (!args[0].compare(String8("config"))) {
-            return doLoadConfig(in);
+            return cmd_config(in, out, err, args);
         }
+
+        // adb shell cmd stats print-stats-log
+        if (!args[0].compare(String8("print-stats-log")) && args.size() > 1) {
+            return cmd_print_stats_log(out, args);
+        }
+
         if (!args[0].compare(String8("print-uid-map"))) {
-            return doPrintUidMap(out);
+            return cmd_print_uid_map(out);
+        }
+
+        if (!args[0].compare(String8("dump-report"))) {
+            return cmd_dump_report(out, err, args);
         }
     }
 
-    printCmdHelp(out);
+    print_cmd_help(out);
     return NO_ERROR;
 }
 
-status_t StatsService::doLoadConfig(FILE* in) {
-    string content;
-    if (!android::base::ReadFdToString(fileno(in), &content)) {
-        return UNKNOWN_ERROR;
+void StatsService::print_cmd_help(FILE* out) {
+    fprintf(out,
+            "usage: adb shell cmd stats print-stats-log [tag_required] "
+            "[timestamp_nsec_optional]\n");
+    fprintf(out, "\n");
+    fprintf(out, "\n");
+    fprintf(out, "usage: adb shell cmd stats print-uid-map \n");
+    fprintf(out, "\n");
+    fprintf(out, "  Prints the UID, app name, version mapping.\n");
+    fprintf(out, "\n");
+    fprintf(out, "\n");
+    fprintf(out, "usage: adb shell cmd stats config remove [UID] NAME\n");
+    fprintf(out, "usage: adb shell cmd stats config update [UID] NAME\n");
+    fprintf(out, "\n");
+    fprintf(out, "  Adds, updates or removes a configuration. The proto should be in\n");
+    fprintf(out, "  wire-encoded protobuf format and passed via stdin.\n");
+    fprintf(out, "\n");
+    fprintf(out, "  UID           The uid to use. It is only possible to pass the UID\n");
+    fprintf(out, "                parameter on eng builds.  If UID is omitted the calling\n");
+    fprintf(out, "                uid is used.\n");
+    fprintf(out, "  NAME          The per-uid name to use\n");
+}
+
+status_t StatsService::cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
+    const int argCount = args.size();
+    if (argCount >= 2) {
+        if (args[1] == "update" || args[1] == "remove") {
+            bool good = false;
+            int uid = -1;
+            string name;
+
+            if (argCount == 3) {
+                // Automatically pick the UID
+                uid = IPCThreadState::self()->getCallingUid();
+                // TODO: What if this isn't a binder call? Should we fail?
+                name.assign(args[2].c_str(), args[2].size());
+                good = true;
+            } else if (argCount == 4) {
+                // If it's a userdebug or eng build, then the shell user can
+                // impersonate other uids.
+                if (mEngBuild) {
+                    const char* s = args[2].c_str();
+                    if (*s != '\0') {
+                        char* end = NULL;
+                        uid = strtol(s, &end, 0);
+                        if (*end == '\0') {
+                            name.assign(args[3].c_str(), args[3].size());
+                            good = true;
+                        }
+                    }
+                } else {
+                    fprintf(err,
+                            "The config can only be set for other UIDs on eng or userdebug "
+                            "builds.\n");
+                }
+            }
+
+            if (!good) {
+                // If arg parsing failed, print the help text and return an error.
+                print_cmd_help(out);
+                return UNKNOWN_ERROR;
+            }
+
+            if (args[1] == "update") {
+                // Read stream into buffer.
+                string buffer;
+                if (!android::base::ReadFdToString(fileno(in), &buffer)) {
+                    fprintf(err, "Error reading stream for StatsConfig.\n");
+                    return UNKNOWN_ERROR;
+                }
+
+                // Parse buffer.
+                StatsdConfig config;
+                if (!config.ParseFromString(buffer)) {
+                    fprintf(err, "Error parsing proto stream for StatsConfig.\n");
+                    return UNKNOWN_ERROR;
+                }
+
+                // Add / update the config.
+                mConfigManager->UpdateConfig(ConfigKey(uid, name), config);
+            } else {
+                // Remove the config.
+                mConfigManager->RemoveConfig(ConfigKey(uid, name));
+            }
+
+            return NO_ERROR;
+        }
     }
-    StatsdConfig config;
-    if (config.ParseFromString(content)) {
-        ALOGD("Config parsed from command line: %s", config.SerializeAsString().c_str());
-        m_processor->UpdateConfig(0, config);
-        return NO_ERROR;
+    print_cmd_help(out);
+    return UNKNOWN_ERROR;
+}
+
+status_t StatsService::cmd_dump_report(FILE* out, FILE* err, const Vector<String8>& args) {
+    if (mProcessor != nullptr) {
+        const int argCount = args.size();
+        bool good = false;
+        int uid;
+        string name;
+        if (argCount == 2) {
+            // Automatically pick the UID
+            uid = IPCThreadState::self()->getCallingUid();
+            // TODO: What if this isn't a binder call? Should we fail?
+            name.assign(args[2].c_str(), args[2].size());
+            good = true;
+        } else if (argCount == 3) {
+            // If it's a userdebug or eng build, then the shell user can
+            // impersonate other uids.
+            if (mEngBuild) {
+                const char* s = args[1].c_str();
+                if (*s != '\0') {
+                    char* end = NULL;
+                    uid = strtol(s, &end, 0);
+                    if (*end == '\0') {
+                        name.assign(args[2].c_str(), args[2].size());
+                        good = true;
+                    }
+                }
+            } else {
+                fprintf(out,
+                        "The metrics can only be dumped for other UIDs on eng or userdebug "
+                        "builds.\n");
+            }
+        }
+        if (good) {
+            mProcessor->onDumpReport(ConfigKey(uid, name));
+            // TODO: print the returned StatsLogReport to file instead of printing to logcat.
+            fprintf(out, "Dump report for Config [%d,%s]\n", uid, name.c_str());
+            fprintf(out, "See the StatsLogReport in logcat...\n");
+            return android::OK;
+        } else {
+            // If arg parsing failed, print the help text and return an error.
+            print_cmd_help(out);
+            return UNKNOWN_ERROR;
+        }
     } else {
-        ALOGD("Config failed to be parsed");
+        fprintf(out, "Log processor does not exist...\n");
         return UNKNOWN_ERROR;
     }
 }
 
+status_t StatsService::cmd_print_stats_log(FILE* out, const Vector<String8>& args) {
+    long msec = 0;
+
+    if (args.size() > 2) {
+        msec = strtol(args[2].string(), NULL, 10);
+    }
+    return DropboxReader::readStatsLogs(out, args[1].string(), msec);
+}
+
+status_t StatsService::cmd_print_uid_map(FILE* out) {
+    mUidMap->printUidMap(out);
+    return NO_ERROR;
+}
+
 Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<int32_t>& version,
                                       const vector<String16>& app) {
     if (DEBUG) ALOGD("StatsService::informAllUidData was called");
@@ -166,7 +362,7 @@
                                          "Only system uid can call informAllUidData");
     }
 
-    m_UidMap->updateMap(uid, version, app);
+    mUidMap->updateMap(uid, version, app);
     if (DEBUG) ALOGD("StatsService::informAllUidData succeeded");
 
     return Status::ok();
@@ -179,7 +375,7 @@
         return Status::fromExceptionCode(Status::EX_SECURITY,
                                          "Only system uid can call informOnePackage");
     }
-    m_UidMap->updateApp(app, uid, version);
+    mUidMap->updateApp(app, uid, version);
     return Status::ok();
 }
 
@@ -190,7 +386,7 @@
         return Status::fromExceptionCode(Status::EX_SECURITY,
                                          "Only system uid can call informOnePackageRemoved");
     }
-    m_UidMap->removeApp(app, uid);
+    mUidMap->removeApp(app, uid);
     return Status::ok();
 }
 
@@ -282,38 +478,18 @@
                 "statscompanion unavailable despite it contacting statsd!");
     }
     if (DEBUG) ALOGD("StatsService::statsCompanionReady linking to statsCompanion.");
-    IInterface::asBinder(statsCompanion)->linkToDeath(new StatsdDeathRecipient(mAnomalyMonitor));
+    IInterface::asBinder(statsCompanion)->linkToDeath(new CompanionDeathRecipient(mAnomalyMonitor));
     mAnomalyMonitor->setStatsCompanionService(statsCompanion);
 
     return Status::ok();
 }
 
-void StatsdDeathRecipient::binderDied(const wp<IBinder>& who) {
-    ALOGW("statscompanion service died");
-    mAnmlyMntr->setStatsCompanionService(nullptr);
+void StatsService::Startup() {
+    mConfigManager->Startup();
 }
 
-status_t StatsService::doPrintStatsLog(FILE* out, const Vector<String8>& args) {
-    long msec = 0;
-
-    if (args.size() > 2) {
-        msec = strtol(args[2].string(), NULL, 10);
-    }
-    return DropboxReader::readStatsLogs(out, args[1].string(), msec);
-}
-
-status_t StatsService::doPrintUidMap(FILE* out) {
-    m_UidMap->printUidMap(out);
-    return NO_ERROR;
-}
-
-void StatsService::printCmdHelp(FILE* out) {
-    fprintf(out, "Usage:\n");
-    fprintf(out, "\t print-stats-log [tag_required] [timestamp_nsec_optional]\n");
-    fprintf(out, "\t print-uid-map Prints the UID, app name, version mapping.\n");
-    fprintf(out,
-            "\t config\t Loads a new config from command-line (must be proto in wire-encoded "
-            "format).\n");
+void StatsService::OnLogEvent(const LogEvent& event) {
+    mProcessor->OnLogEvent(event);
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 541f7e8..294aec8 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -17,11 +17,11 @@
 #ifndef STATS_SERVICE_H
 #define STATS_SERVICE_H
 
-#include "AnomalyMonitor.h"
 #include "StatsLogProcessor.h"
-#include "StatsPullerManager.h"
-#include "StatsPuller.h"
-#include "UidMap.h"
+#include "anomaly/AnomalyMonitor.h"
+#include "config/ConfigManager.h"
+#include "external/StatsPullerManager.h"
+#include "packages/UidMap.h"
 
 #include <android/os/BnStatsManager.h>
 #include <android/os/IStatsCompanionService.h>
@@ -42,75 +42,119 @@
 namespace os {
 namespace statsd {
 
-class StatsService : public BnStatsManager {
+class StatsService : public BnStatsManager, public LogListener {
 public:
     StatsService(const sp<Looper>& handlerLooper);
     virtual ~StatsService();
 
     virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
-
     virtual status_t dump(int fd, const Vector<String16>& args);
-
     virtual status_t command(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
 
     virtual Status systemRunning();
-
-    // Inform statsd that statsCompanion is ready.
     virtual Status statsCompanionReady();
-
     virtual Status informAnomalyAlarmFired();
-
     virtual Status informPollAlarmFired();
-
     virtual Status informAllUidData(const vector<int32_t>& uid, const vector<int32_t>& version,
                                     const vector<String16>& app);
     virtual Status informOnePackage(const String16& app, int32_t uid, int32_t version);
     virtual Status informOnePackageRemoved(const String16& app, int32_t uid);
 
-    virtual status_t setProcessor(const sp<StatsLogProcessor>& main_processor);
+    /**
+     * Called right before we start processing events.
+     */
+    void Startup();
+
+    /**
+     * Called by LogReader when there's a log event to process.
+     */
+    virtual void OnLogEvent(const LogEvent& event);
 
     // TODO: public for testing since statsd doesn't run when system starts. Change to private
     // later.
     /** Inform statsCompanion that statsd is ready. */
     virtual void sayHiToStatsCompanion();
 
-    // TODO: Move this to a more logical file/class
-    // TODO: Should be private. Temporarily public for testing purposes only.
-    const sp<AnomalyMonitor> mAnomalyMonitor;
-
-    sp<UidMap> getUidMap() {
-        return m_UidMap;
-    }
-
     /** Fetches and returns the StatsCompanionService. */
     static sp<IStatsCompanionService> getStatsCompanionService();
 
 private:
-    sp<UidMap> m_UidMap; // Reference to the UID map needed for translating UID to app name/version.
+    /**
+     * Load system properties at init.
+     */
+    void init_system_properties();
 
-    sp<StatsLogProcessor> m_processor;  // Reference to the processor for updating configs.
+    /**
+     * Helper for loading system properties.
+     */
+    static void init_build_type_callback(void* cookie, const char* name, const char* value,
+                                         uint32_t serial);
 
-    status_t doPrintStatsLog(FILE* out, const Vector<String8>& args);
+    /**
+     * Text output of dumpsys.
+     */
+    void dump_impl(FILE* out);
 
-    void printCmdHelp(FILE* out);
+    /**
+     * Print usage information for the commands
+     */
+    void print_cmd_help(FILE* out);
 
-    status_t doLoadConfig(FILE* in);
+    /**
+     * Handle the config sub-command.
+     */
+    status_t cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
 
+    /**
+     * Print the event log.
+     */
+    status_t cmd_print_stats_log(FILE* out, const Vector<String8>& args);
+
+    /**
+     * Print the event log.
+     */
+    status_t cmd_dump_report(FILE* out, FILE* err, const Vector<String8>& args);
+
+    /**
+     * Print the mapping of uids to package names.
+     */
+    status_t cmd_print_uid_map(FILE* out);
+
+    /**
+     * Update a configuration.
+     */
+    void set_config(int uid, const string& name, const StatsdConfig& config);
+
+    /**
+     * Tracks the uid <--> package name mapping.
+     */
+    sp<UidMap> mUidMap;
+
+    /**
+     * Fetches external metrics.
+     * TODO: This should be an sp<>
+     */
     StatsPullerManager mStatsPullerManager;
 
-    status_t doPrintUidMap(FILE* out);
-};
+    /**
+     * Tracks the configurations that have been passed to statsd.
+     */
+    sp<ConfigManager> mConfigManager;
 
-// --- StatsdDeathRecipient ---
-class StatsdDeathRecipient : public IBinder::DeathRecipient {
-public:
-    StatsdDeathRecipient(sp<AnomalyMonitor> anomalyMonitor) : mAnmlyMntr(anomalyMonitor) {
-    }
+    /**
+     * The metrics recorder.
+     */
+    sp<StatsLogProcessor> mProcessor;
 
-    virtual void binderDied(const wp<IBinder>& who);
+    /**
+     * The anomaly detector.
+     */
+    const sp<AnomalyMonitor> mAnomalyMonitor;
 
-private:
-    const sp<AnomalyMonitor> mAnmlyMntr;
+    /**
+     * Whether this is an eng build.
+     */
+    bool mEngBuild;
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/UidMap.cpp b/cmds/statsd/src/UidMap.cpp
deleted file mode 100644
index 76a7f3f..0000000
--- a/cmds/statsd/src/UidMap.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, versionCode 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "UidMap.h"
-#include <cutils/log.h>
-#include <utils/Errors.h>
-
-using namespace android;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-bool UidMap::hasApp(int uid, const string& packageName) const {
-    lock_guard<mutex> lock(mMutex);
-
-    auto range = mMap.equal_range(uid);
-    for (auto it = range.first; it != range.second; ++it) {
-        if (it->second.packageName == packageName) {
-            return true;
-        }
-    }
-    return false;
-}
-
-int UidMap::getAppVersion(int uid, const string& packageName) const {
-    lock_guard<mutex> lock(mMutex);
-
-    auto range = mMap.equal_range(uid);
-    for (auto it = range.first; it != range.second; ++it) {
-        if (it->second.packageName == packageName) {
-            return it->second.versionCode;
-        }
-    }
-    return 0;
-}
-
-void UidMap::updateMap(const vector <int32_t> &uid, const vector <int32_t> &versionCode,
-                       const vector <String16> &packageName) {
-    lock_guard<mutex> lock(mMutex); // Exclusively lock for updates.
-
-    mMap.clear();
-    for (unsigned long j=0; j<uid.size(); j++) {
-        mMap.insert(make_pair(uid[j], AppData(string(String8(packageName[j]).string()),
-                                              versionCode[j])));
-    }
-
-    if (mOutput.initial_size() == 0) { // Provide the initial states in the mOutput proto
-        for (unsigned long j=0; j<uid.size(); j++) {
-            auto t = mOutput.add_initial();
-            t->set_app(string(String8(packageName[j]).string()));
-            t->set_version(int(versionCode[j]));
-            t->set_uid(uid[j]);
-        }
-    }
-}
-
-void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int32_t& versionCode){
-    lock_guard<mutex> lock(mMutex);
-
-    string app = string(String8(app_16).string());
-
-    // Notify any interested producers that this app has updated
-    for (auto it : mSubscribers) {
-        it->notifyAppUpgrade(app, uid, versionCode);
-    }
-
-    auto log = mOutput.add_changes();
-    log->set_deletion(false);
-    //log.timestamp = TODO: choose how timestamps are computed
-    log->set_app(app);
-    log->set_uid(uid);
-    log->set_version(versionCode);
-
-    auto range = mMap.equal_range(int(uid));
-    for (auto it = range.first; it != range.second; ++it) {
-        if (it->second.packageName == app) {
-            it->second.versionCode = int(versionCode);
-            return;
-        }
-        ALOGD("updateApp failed to find the app %s with uid %i to update", app.c_str(), uid);
-        return;
-    }
-
-    // Otherwise, we need to add an app at this uid.
-    mMap.insert(make_pair(uid, AppData(app, int(versionCode))));
-}
-
-
-void UidMap::removeApp(const String16& app_16, const int32_t& uid){
-    lock_guard<mutex> lock(mMutex);
-
-    string app = string(String8(app_16).string());
-
-    auto log = mOutput.add_changes();
-    log->set_deletion(true);
-    //log.timestamp = TODO: choose how timestamps are computed
-    log->set_app(app);
-    log->set_uid(uid);
-
-    auto range = mMap.equal_range(int(uid));
-    for (auto it = range.first; it != range.second; ++it) {
-        if (it->second.packageName == app) {
-            mMap.erase(it);
-            return;
-        }
-    }
-    ALOGD("removeApp failed to find the app %s with uid %i to remove", app.c_str(), uid);
-    return;
-}
-
-void UidMap::addListener(sp<PackageInfoListener> producer) {
-    lock_guard<mutex> lock(mMutex); // Lock for updates
-    mSubscribers.insert(producer);
-}
-
-void UidMap::removeListener(sp<PackageInfoListener> producer) {
-    lock_guard<mutex> lock(mMutex); // Lock for updates
-    mSubscribers.erase(producer);
-}
-
-UidMapping UidMap::getAndClearOutput() {
-    lock_guard<mutex> lock(mMutex); // Lock for updates
-
-    auto ret = UidMapping(mOutput); // Copy that will be returned.
-    mOutput.Clear();
-
-    // Re-initialize the initial state for the outputs. This results in extra data being uploaded
-    // but helps ensure we can't re-construct the UID->app name, versionCode mapping in server.
-    for (auto it : mMap) {
-        auto t = mOutput.add_initial();
-        t->set_app(it.second.packageName);
-        t->set_version(it.second.versionCode);
-        t->set_uid(it.first);
-    }
-
-    return ret;
-}
-
-void UidMap::printUidMap(FILE* out) {
-    lock_guard<mutex> lock(mMutex);
-
-    for (auto it : mMap) {
-        fprintf(out, "%s, v%d (%i)\n", it.second.packageName.c_str(), it.second.versionCode, it.first);
-    }
-}
-
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/UidMap.h b/cmds/statsd/src/UidMap.h
deleted file mode 100644
index 1481010..0000000
--- a/cmds/statsd/src/UidMap.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef STATSD_UIDMAP_H
-#define STATSD_UIDMAP_H
-
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
-#include "PackageInfoListener.h"
-
-#include <binder/IResultReceiver.h>
-#include <binder/IShellCallback.h>
-#include <log/logprint.h>
-#include <mutex>
-#include <string>
-#include <stdio.h>
-#include <set>
-#include <unordered_map>
-#include <utils/RefBase.h>
-
-using namespace std;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-struct AppData {
-    const string packageName;
-    int versionCode;
-
-    AppData(const string& a, const int v) : packageName(a), versionCode(v) {};
-};
-
-// UidMap keeps track of what the corresponding app name (APK name) and version code for every uid
-// at any given moment. This map must be updated by StatsCompanionService.
-class UidMap : public virtual android::RefBase  {
-public:
-    /*
-     * All three inputs must be the same size, and the jth element in each array refers to the same
-     * tuple, ie. uid[j] corresponds to packageName[j] with versionCode[j].
-     */
-    void updateMap(const vector<int32_t>& uid, const vector<int32_t>& versionCode,
-                   const vector<String16>& packageName);
-
-    // Returns true if the given uid contains the specified app (eg. com.google.android.gms).
-    bool hasApp(int uid, const string& packageName) const;
-
-    int getAppVersion(int uid, const string& packageName) const;
-
-    void updateApp(const String16& packageName, const int32_t& uid, const int32_t& versionCode);
-    void removeApp(const String16& packageName, const int32_t& uid);
-
-    // Helper for debugging contents of this uid map. Can be triggered with:
-    // adb shell cmd stats print-uid-map
-    void printUidMap(FILE* out);
-
-    // Commands for indicating to the map that a producer should be notified if an app is updated.
-    // This allows the metric producer to distinguish when the same uid or app represents a
-    // different version of an app.
-    void addListener(sp<PackageInfoListener> producer);
-    // Remove the listener from the set of metric producers that subscribe to updates.
-    void removeListener(sp<PackageInfoListener> producer);
-
-    // Grabs the current output contents and then clears it.
-    UidMapping getAndClearOutput();
-
-private:
-    // TODO: Use shared_mutex for improved read-locking if a library can be found in Android.
-    mutable mutex mMutex;
-
-    std::unordered_multimap<int, AppData> mMap;
-
-    // We prepare the output proto as apps are updated, so that we can grab the current output.
-    UidMapping mOutput;
-
-    // Metric producers that should be notified if there's an upgrade in any app.
-    set<sp<PackageInfoListener>> mSubscribers;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#endif //STATSD_UIDMAP_H
-
diff --git a/cmds/statsd/src/anomaly/AnomalyMonitor.cpp b/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
new file mode 100644
index 0000000..7a46410
--- /dev/null
+++ b/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define DEBUG true
+#include "Log.h"
+
+#include "anomaly/AnomalyMonitor.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+AnomalyMonitor::AnomalyMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec)
+    : mRegisteredAlarmTimeSec(0), mMinUpdateTimeSec(minDiffToUpdateRegisteredAlarmTimeSec) {
+}
+
+AnomalyMonitor::~AnomalyMonitor() {
+}
+
+void AnomalyMonitor::setStatsCompanionService(sp<IStatsCompanionService> statsCompanionService) {
+    std::lock_guard<std::mutex> lock(mLock);
+    sp<IStatsCompanionService> tmpForLock = mStatsCompanionService;
+    mStatsCompanionService = statsCompanionService;
+    if (statsCompanionService == nullptr) {
+        if (DEBUG) ALOGD("Erasing link to statsCompanionService");
+        return;
+    }
+    if (DEBUG) ALOGD("Creating link to statsCompanionService");
+    const sp<const AnomalyAlarm> top = mPq.top();
+    if (top != nullptr) {
+        updateRegisteredAlarmTime_l(top->timestampSec);
+    }
+}
+
+void AnomalyMonitor::add(sp<const AnomalyAlarm> alarm) {
+    std::lock_guard<std::mutex> lock(mLock);
+    if (alarm == nullptr) {
+        ALOGW("Asked to add a null alarm.");
+        return;
+    }
+    if (alarm->timestampSec < 1) {
+        // forbidden since a timestamp 0 is used to indicate no alarm registered
+        ALOGW("Asked to add a 0-time alarm.");
+        return;
+    }
+    // TODO: Ensure that refractory period is respected.
+    if (DEBUG) ALOGD("Adding alarm with time %u", alarm->timestampSec);
+    mPq.push(alarm);
+    if (mRegisteredAlarmTimeSec < 1 ||
+        alarm->timestampSec + mMinUpdateTimeSec < mRegisteredAlarmTimeSec) {
+        updateRegisteredAlarmTime_l(alarm->timestampSec);
+    }
+}
+
+void AnomalyMonitor::remove(sp<const AnomalyAlarm> alarm) {
+    std::lock_guard<std::mutex> lock(mLock);
+    if (alarm == nullptr) {
+        ALOGW("Asked to remove a null alarm.");
+        return;
+    }
+    if (DEBUG) ALOGD("Removing alarm with time %u", alarm->timestampSec);
+    mPq.remove(alarm);
+    if (mPq.empty()) {
+        if (DEBUG) ALOGD("Queue is empty. Cancel any alarm.");
+        mRegisteredAlarmTimeSec = 0;
+        if (mStatsCompanionService != nullptr) {
+            mStatsCompanionService->cancelAnomalyAlarm();
+        }
+        return;
+    }
+    uint32_t soonestAlarmTimeSec = mPq.top()->timestampSec;
+    if (DEBUG) ALOGD("Soonest alarm is %u", soonestAlarmTimeSec);
+    if (soonestAlarmTimeSec > mRegisteredAlarmTimeSec + mMinUpdateTimeSec) {
+        updateRegisteredAlarmTime_l(soonestAlarmTimeSec);
+    }
+}
+
+// More efficient than repeatedly calling remove(mPq.top()) since it batches the
+// updates to the registered alarm.
+unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> AnomalyMonitor::popSoonerThan(
+        uint32_t timestampSec) {
+    if (DEBUG) ALOGD("Removing alarms with time <= %u", timestampSec);
+    unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> oldAlarms;
+    std::lock_guard<std::mutex> lock(mLock);
+
+    for (sp<const AnomalyAlarm> t = mPq.top(); t != nullptr && t->timestampSec <= timestampSec;
+         t = mPq.top()) {
+        oldAlarms.insert(t);
+        mPq.pop();  // remove t
+    }
+    // Always update registered alarm time (if anything has changed).
+    if (!oldAlarms.empty()) {
+        if (mPq.empty()) {
+            if (DEBUG) ALOGD("Queue is empty. Cancel any alarm.");
+            mRegisteredAlarmTimeSec = 0;
+            if (mStatsCompanionService != nullptr) {
+                mStatsCompanionService->cancelAnomalyAlarm();
+            }
+        } else {
+            // Always update the registered alarm in this case (unlike remove()).
+            updateRegisteredAlarmTime_l(mPq.top()->timestampSec);
+        }
+    }
+    return oldAlarms;
+}
+
+void AnomalyMonitor::updateRegisteredAlarmTime_l(uint32_t timestampSec) {
+    if (DEBUG) ALOGD("Updating reg alarm time to %u", timestampSec);
+    mRegisteredAlarmTimeSec = timestampSec;
+    if (mStatsCompanionService != nullptr) {
+        mStatsCompanionService->setAnomalyAlarm(secToMs(mRegisteredAlarmTimeSec));
+    }
+}
+
+int64_t AnomalyMonitor::secToMs(uint32_t timeSec) {
+    return ((int64_t)timeSec) * 1000;
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/anomaly/AnomalyMonitor.h b/cmds/statsd/src/anomaly/AnomalyMonitor.h
new file mode 100644
index 0000000..e2ac623
--- /dev/null
+++ b/cmds/statsd/src/anomaly/AnomalyMonitor.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANOMALY_MONITOR_H
+#define ANOMALY_MONITOR_H
+
+#include "anomaly/indexed_priority_queue.h"
+
+#include <android/os/IStatsCompanionService.h>
+#include <utils/RefBase.h>
+
+#include <queue>
+#include <unordered_set>
+#include <vector>
+
+using namespace android;
+
+using android::os::IStatsCompanionService;
+using std::unordered_set;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * Represents an alarm, associated with some aggregate metric, holding a
+ * projected time at which the metric is expected to exceed its anomaly
+ * threshold.
+ * Timestamps are in seconds since epoch in a uint32, so will fail in year 2106.
+ */
+struct AnomalyAlarm : public RefBase {
+    AnomalyAlarm(uint32_t timestampSec) : timestampSec(timestampSec) {
+    }
+
+    const uint32_t timestampSec;
+
+    /** AnomalyAlarm a is smaller (higher priority) than b if its timestamp is sooner. */
+    struct SmallerTimestamp {
+        bool operator()(sp<const AnomalyAlarm> a, sp<const AnomalyAlarm> b) const {
+            return (a->timestampSec < b->timestampSec);
+        }
+    };
+};
+
+/**
+ * Manages alarms for Anomaly Detection.
+ */
+class AnomalyMonitor : public RefBase {
+public:
+    /**
+     * @param minDiffToUpdateRegisteredAlarmTimeSec If the soonest alarm differs
+     * from the registered alarm by more than this amount, update the registered
+     * alarm.
+     */
+    AnomalyMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec);
+    ~AnomalyMonitor();
+
+    /**
+     * Tells AnomalyMonitor what IStatsCompanionService to use and, if
+     * applicable, immediately registers an existing alarm with it.
+     * If nullptr, AnomalyMonitor will continue to add/remove alarms, but won't
+     * update IStatsCompanionService (until such time as it is set non-null).
+     */
+    void setStatsCompanionService(sp<IStatsCompanionService> statsCompanionService);
+
+    /**
+     * Adds the given alarm (reference) to the queue.
+     */
+    void add(sp<const AnomalyAlarm> alarm);
+
+    /**
+     * Removes the given alarm (reference) from the queue.
+     * Note that alarm comparison is reference-based; if another alarm exists
+     * with the same timestampSec, that alarm will still remain in the queue.
+     */
+    void remove(sp<const AnomalyAlarm> alarm);
+
+    /**
+     * Returns and removes all alarms whose timestamp <= the given timestampSec.
+     * Always updates the registered alarm if return is non-empty.
+     */
+    unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> popSoonerThan(
+            uint32_t timestampSec);
+
+    /**
+     * Returns the projected alarm timestamp that is registered with
+     * StatsCompanionService. This may not be equal to the soonest alarm,
+     * but should be within minDiffToUpdateRegisteredAlarmTimeSec of it.
+     */
+    uint32_t getRegisteredAlarmTimeSec() const {
+        return mRegisteredAlarmTimeSec;
+    }
+
+private:
+    std::mutex mLock;
+
+    /**
+     * Timestamp (seconds since epoch) of the alarm registered with
+     * StatsCompanionService. This, in general, may not be equal to the soonest
+     * alarm stored in mPq, but should be within minUpdateTimeSec of it.
+     * A value of 0 indicates that no alarm is currently registered.
+     */
+    uint32_t mRegisteredAlarmTimeSec;
+
+    /**
+     * Priority queue of alarms, prioritized by soonest alarm.timestampSec.
+     */
+    indexed_priority_queue<AnomalyAlarm, AnomalyAlarm::SmallerTimestamp> mPq;
+
+    /**
+     * Binder interface for communicating with StatsCompanionService.
+     */
+    sp<IStatsCompanionService> mStatsCompanionService = nullptr;
+
+    /**
+     * Amount by which the soonest projected alarm must differ from
+     * mRegisteredAlarmTimeSec before updateRegisteredAlarmTime_l is called.
+     */
+    uint32_t mMinUpdateTimeSec;
+
+    /**
+     * Updates the alarm registered with StatsCompanionService to the given time.
+     * Also correspondingly updates mRegisteredAlarmTimeSec.
+     */
+    void updateRegisteredAlarmTime_l(uint32_t timestampSec);
+
+    /** Converts uint32 timestamp in seconds to a Java long in msec. */
+    int64_t secToMs(uint32_t timeSec);
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+
+#endif  // ANOMALY_MONITOR_H
diff --git a/cmds/statsd/src/anomaly/indexed_priority_queue.h b/cmds/statsd/src/anomaly/indexed_priority_queue.h
new file mode 100644
index 0000000..1a2e9c2
--- /dev/null
+++ b/cmds/statsd/src/anomaly/indexed_priority_queue.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "Log.h"
+
+#include <utils/RefBase.h>
+#include <unordered_map>
+#include <vector>
+
+using namespace android;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/** Defines a hash function for sp<AA>, returning the hash of the underlying pointer. */
+template <class AA>
+struct SpHash {
+    size_t operator()(const sp<const AA>& k) const {
+        return std::hash<const AA*>()(k.get());
+    }
+};
+
+/**
+ * Min priority queue for generic type AA.
+ * Unlike a regular priority queue, this class is also capable of removing interior elements.
+ * @tparam Comparator must implement [bool operator()(sp<const AA> a, sp<const AA> b)], returning
+ *    whether a should be closer to the top of the queue than b.
+ */
+template <class AA, class Comparator>
+class indexed_priority_queue {
+public:
+    indexed_priority_queue();
+    /** Adds a into the priority queue. If already present or a==nullptr, does nothing. */
+    void push(sp<const AA> a);
+    /** Removes a from the priority queue. If not present or a==nullptr, does nothing. */
+    void remove(sp<const AA> a);
+    /** Removes the top element, if there is one. */
+    void pop();
+    /** Removes all elements. */
+    void clear();
+    /** Returns whether priority queue contains a (not just a copy of a, but a itself). */
+    bool contains(sp<const AA> a) const;
+    /** Returns min element. Returns nullptr iff empty(). */
+    sp<const AA> top() const;
+    /** Returns number of elements in priority queue. */
+    size_t size() const {
+        return pq.size() - 1;
+    }  // pq is 1-indexed
+    /** Returns true iff priority queue is empty. */
+    bool empty() const {
+        return size() < 1;
+    }
+
+private:
+    /** Vector representing a min-heap (1-indexed, with nullptr at 0). */
+    std::vector<sp<const AA>> pq;
+    /** Mapping of each element in pq to its index in pq (i.e. the inverse of a=pq[i]). */
+    std::unordered_map<sp<const AA>, size_t, SpHash<AA>> indices;
+
+    void init();
+    void sift_up(size_t idx);
+    void sift_down(size_t idx);
+    /** Returns whether pq[idx1] is considered higher than pq[idx2], according to Comparator. */
+    bool higher(size_t idx1, size_t idx2) const;
+    void swap_indices(size_t i, size_t j);
+};
+
+// Implementation must be done in this file due to use of template.
+
+template <class AA, class Comparator>
+indexed_priority_queue<AA, Comparator>::indexed_priority_queue() {
+    init();
+}
+
+template <class AA, class Comparator>
+void indexed_priority_queue<AA, Comparator>::push(sp<const AA> a) {
+    if (a == nullptr) return;
+    if (contains(a)) return;
+    pq.push_back(a);
+    size_t idx = size();  // index of last element since 1-indexed
+    indices.insert({a, idx});
+    sift_up(idx);  // get the pq back in order
+}
+
+template <class AA, class Comparator>
+void indexed_priority_queue<AA, Comparator>::remove(sp<const AA> a) {
+    if (a == nullptr) return;
+    if (!contains(a)) return;
+    size_t idx = indices[a];
+    if (idx >= pq.size()) {
+        ALOGE("indexed_priority_queue: Invalid index in map of indices.");
+        return;
+    }
+    if (idx == size()) {  // if a is the last element, i.e. at index idx == size() == (pq.size()-1)
+        pq.pop_back();
+        indices.erase(a);
+        return;
+    }
+    // move last element (guaranteed not to be at idx) to idx, then delete a
+    sp<const AA> last_a = pq.back();
+    pq[idx] = last_a;
+    pq.pop_back();
+    indices[last_a] = idx;
+    indices.erase(a);
+
+    // get the heap back in order (since the element at idx is not in order)
+    sift_up(idx);
+    sift_down(idx);
+}
+
+// The same as, but slightly more efficient than, remove(top()).
+template <class AA, class Comparator>
+void indexed_priority_queue<AA, Comparator>::pop() {
+    sp<const AA> a = top();
+    if (a == nullptr) return;
+    const size_t idx = 1;
+    if (idx == size()) {  // if a is the last element
+        pq.pop_back();
+        indices.erase(a);
+        return;
+    }
+    // move last element (guaranteed not to be at idx) to idx, then delete a
+    sp<const AA> last_a = pq.back();
+    pq[idx] = last_a;
+    pq.pop_back();
+    indices[last_a] = idx;
+    indices.erase(a);
+
+    // get the heap back in order (since the element at idx is not in order)
+    sift_down(idx);
+}
+
+template <class AA, class Comparator>
+void indexed_priority_queue<AA, Comparator>::clear() {
+    pq.clear();
+    indices.clear();
+    init();
+}
+
+template <class AA, class Comparator>
+sp<const AA> indexed_priority_queue<AA, Comparator>::top() const {
+    if (empty()) return nullptr;
+    return pq[1];
+}
+
+template <class AA, class Comparator>
+void indexed_priority_queue<AA, Comparator>::init() {
+    pq.push_back(nullptr);         // so that pq is 1-indexed.
+    indices.insert({nullptr, 0});  // just to be consistent with pq.
+}
+
+template <class AA, class Comparator>
+void indexed_priority_queue<AA, Comparator>::sift_up(size_t idx) {
+    while (idx > 1) {
+        size_t parent = idx / 2;
+        if (higher(idx, parent))
+            swap_indices(idx, parent);
+        else
+            break;
+        idx = parent;
+    }
+}
+
+template <class AA, class Comparator>
+void indexed_priority_queue<AA, Comparator>::sift_down(size_t idx) {
+    while (2 * idx <= size()) {
+        size_t child = 2 * idx;
+        if (child < size() && higher(child + 1, child)) child++;
+        if (higher(child, idx))
+            swap_indices(child, idx);
+        else
+            break;
+        idx = child;
+    }
+}
+
+template <class AA, class Comparator>
+bool indexed_priority_queue<AA, Comparator>::higher(size_t idx1, size_t idx2) const {
+    if (!(0u < idx1 && idx1 < pq.size() && 0u < idx2 && idx2 < pq.size())) {
+        ALOGE("indexed_priority_queue: Attempting to access invalid index");
+        return false;  // got to do something.
+    }
+    return Comparator()(pq[idx1], pq[idx2]);
+}
+
+template <class AA, class Comparator>
+bool indexed_priority_queue<AA, Comparator>::contains(sp<const AA> a) const {
+    if (a == nullptr) return false;  // publicly, we pretend that nullptr is not actually in pq.
+    return indices.count(a) > 0;
+}
+
+template <class AA, class Comparator>
+void indexed_priority_queue<AA, Comparator>::swap_indices(size_t i, size_t j) {
+    if (!(0u < i && i < pq.size() && 0u < j && j < pq.size())) {
+        ALOGE("indexed_priority_queue: Attempting to swap invalid index");
+        return;
+    }
+    sp<const AA> val_i = pq[i];
+    sp<const AA> val_j = pq[j];
+    pq[i] = val_j;
+    pq[j] = val_i;
+    indices[val_i] = j;
+    indices[val_j] = i;
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
index 6188383..f56c15a 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
@@ -13,23 +13,24 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_TAG "CombinationConditionTracker"
+
 #define DEBUG true  // STOPSHIP if true
-#define VLOG(...) \
-    if (DEBUG) ALOGD(__VA_ARGS__);
+#include "Log.h"
 
 #include "CombinationConditionTracker.h"
-#include <cutils/log.h>
+
 #include <log/logprint.h>
-using std::string;
-using std::unique_ptr;
-using std::unordered_map;
-using std::vector;
 
 namespace android {
 namespace os {
 namespace statsd {
 
+using std::map;
+using std::string;
+using std::unique_ptr;
+using std::unordered_map;
+using std::vector;
+
 CombinationConditionTracker::CombinationConditionTracker(const string& name, const int index)
     : ConditionTracker(name, index) {
     VLOG("creating CombinationConditionTracker %s", mName.c_str());
@@ -102,33 +103,62 @@
     return true;
 }
 
+void CombinationConditionTracker::isConditionMet(
+        const map<string, HashableDimensionKey>& conditionParameters,
+        const vector<sp<ConditionTracker>>& allConditions, vector<ConditionState>& conditionCache) {
+    for (const int childIndex : mChildren) {
+        if (conditionCache[childIndex] == ConditionState::kNotEvaluated) {
+            allConditions[childIndex]->isConditionMet(conditionParameters, allConditions,
+                                                      conditionCache);
+        }
+    }
+    conditionCache[mIndex] =
+            evaluateCombinationCondition(mChildren, mLogicalOperation, conditionCache);
+}
+
 bool CombinationConditionTracker::evaluateCondition(
-        const LogEventWrapper& event, const std::vector<MatchingState>& eventMatcherValues,
+        const LogEvent& event, const std::vector<MatchingState>& eventMatcherValues,
         const std::vector<sp<ConditionTracker>>& mAllConditions,
-        std::vector<ConditionState>& conditionCache, std::vector<bool>& changedCache) {
+        std::vector<ConditionState>& nonSlicedConditionCache,
+        std::vector<bool>& nonSlicedChangedCache, vector<bool>& slicedConditionChanged) {
     // value is up to date.
-    if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
+    if (nonSlicedConditionCache[mIndex] != ConditionState::kNotEvaluated) {
         return false;
     }
 
     for (const int childIndex : mChildren) {
-        if (conditionCache[childIndex] == ConditionState::kNotEvaluated) {
+        if (nonSlicedConditionCache[childIndex] == ConditionState::kNotEvaluated) {
             const sp<ConditionTracker>& child = mAllConditions[childIndex];
-            child->evaluateCondition(event, eventMatcherValues, mAllConditions, conditionCache,
-                                     changedCache);
+            child->evaluateCondition(event, eventMatcherValues, mAllConditions,
+                                     nonSlicedConditionCache, nonSlicedChangedCache,
+                                     slicedConditionChanged);
         }
     }
 
     ConditionState newCondition =
-            evaluateCombinationCondition(mChildren, mLogicalOperation, conditionCache);
+            evaluateCombinationCondition(mChildren, mLogicalOperation, nonSlicedConditionCache);
 
-    bool changed = (mConditionState != newCondition);
-    mConditionState = newCondition;
+    bool nonSlicedChanged = (mNonSlicedConditionState != newCondition);
+    mNonSlicedConditionState = newCondition;
 
-    conditionCache[mIndex] = mConditionState;
+    nonSlicedConditionCache[mIndex] = mNonSlicedConditionState;
 
-    changedCache[mIndex] = changed;
-    return changed;
+    nonSlicedChangedCache[mIndex] = nonSlicedChanged;
+
+    if (mSliced) {
+        for (const int childIndex : mChildren) {
+            // If any of the sliced condition in children condition changes, the combination
+            // condition may be changed too.
+            if (slicedConditionChanged[childIndex]) {
+                slicedConditionChanged[mIndex] = true;
+                break;
+            }
+        }
+        ALOGD("CombinationCondition %s sliced may changed? %d", mName.c_str(),
+              slicedConditionChanged[mIndex] == true);
+    }
+
+    return nonSlicedChanged;
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h
index 38780e7..fc88a88 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.h
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.h
@@ -35,11 +35,18 @@
               const std::unordered_map<std::string, int>& conditionNameIndexMap,
               std::vector<bool>& stack) override;
 
-    bool evaluateCondition(const LogEventWrapper& event,
+    bool evaluateCondition(const LogEvent& event,
                            const std::vector<MatchingState>& eventMatcherValues,
                            const std::vector<sp<ConditionTracker>>& mAllConditions,
                            std::vector<ConditionState>& conditionCache,
-                           std::vector<bool>& changedCache) override;
+                           std::vector<bool>& changedCache,
+                           std::vector<bool>& slicedConditionMayChanged) override;
+
+    void isConditionMet(const std::map<std::string, HashableDimensionKey>& conditionParameters,
+                        const std::vector<sp<ConditionTracker>>& allConditions,
+                        std::vector<ConditionState>& conditionCache) override;
+
+    void addDimensions(const std::vector<KeyMatcher>& keyMatchers) override{};
 
 private:
     LogicalOperation mLogicalOperation;
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
index 2da8fa0..055b478 100644
--- a/cmds/statsd/src/condition/ConditionTracker.h
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -14,17 +14,19 @@
  * limitations under the License.
  */
 
-#ifndef CONDITION_TRACKER_H
-#define CONDITION_TRACKER_H
+#pragma once
 
-#include <cutils/log.h>
+#include "Log.h"
+
+#include "condition/condition_util.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "matchers/LogMatchingTracker.h"
+#include "matchers/matcher_util.h"
+
 #include <log/logprint.h>
 #include <utils/RefBase.h>
+
 #include <unordered_map>
-#include "../matchers/LogMatchingTracker.h"
-#include "../matchers/matcher_util.h"
-#include "condition_util.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
 namespace android {
 namespace os {
@@ -36,8 +38,9 @@
         : mName(name),
           mIndex(index),
           mInitialized(false),
-          mConditionState(ConditionState::kUnknown),
-          mTrackerIndex(){};
+          mTrackerIndex(),
+          mNonSlicedConditionState(ConditionState::kUnknown),
+          mSliced(false){};
 
     virtual ~ConditionTracker(){};
 
@@ -61,25 +64,47 @@
     //                     event before ConditionTrackers, because ConditionTracker depends on
     //                     LogMatchingTrackers.
     // mAllConditions: the list of all ConditionTracker
-    // conditionCache: the cached results of the ConditionTrackers for this new event.
-    // changedCache: the bit map to record whether the condition has changed.
-    virtual bool evaluateCondition(const LogEventWrapper& event,
+    // conditionCache: the cached non-sliced condition of the ConditionTrackers for this new event.
+    // nonSlicedConditionChanged: the bit map to record whether non-sliced condition has changed.
+    // slicedConditionMayChanged: the bit map to record whether sliced condition may have changed.
+    //      Because sliced condition needs parameters to determine the value. So the sliced
+    //      condition is not pushed to metrics. We only inform the relevant metrics that the sliced
+    //      condition may have changed, and metrics should pull the conditions that they are
+    //      interested in.
+    virtual bool evaluateCondition(const LogEvent& event,
                                    const std::vector<MatchingState>& eventMatcherValues,
                                    const std::vector<sp<ConditionTracker>>& mAllConditions,
                                    std::vector<ConditionState>& conditionCache,
-                                   std::vector<bool>& changedCache) = 0;
+                                   std::vector<bool>& nonSlicedConditionChanged,
+                                   std::vector<bool>& slicedConditionMayChanged) = 0;
 
     // Return the current condition state.
     virtual ConditionState isConditionMet() {
-        ALOGW("Condition %s value %d", mName.c_str(), mConditionState);
-        return mConditionState;
+        return mNonSlicedConditionState;
     };
 
+    // Query the condition with parameters.
+    // [conditionParameters]: a map from condition name to the HashableDimensionKey to query the
+    //                       condition.
+    // [allConditions]: all condition trackers. This is needed because the condition evaluation is
+    //                  done recursively
+    // [conditionCache]: the cache holding the condition evaluation values.
+    virtual void isConditionMet(
+            const std::map<std::string, HashableDimensionKey>& conditionParameters,
+            const std::vector<sp<ConditionTracker>>& allConditions,
+            std::vector<ConditionState>& conditionCache) = 0;
+
     // return the list of LogMatchingTracker index that this ConditionTracker uses.
     virtual const std::set<int>& getLogTrackerIndex() const {
         return mTrackerIndex;
     }
 
+    virtual void setSliced(bool sliced) {
+        mSliced = mSliced | sliced;
+    }
+
+    virtual void addDimensions(const std::vector<KeyMatcher>& keyMatchers) = 0;
+
 protected:
     // We don't really need the string name, but having a name here makes log messages
     // easy to debug.
@@ -91,15 +116,15 @@
     // if it's properly initialized.
     bool mInitialized;
 
-    // current condition state.
-    ConditionState mConditionState;
-
     // the list of LogMatchingTracker index that this ConditionTracker uses.
     std::set<int> mTrackerIndex;
+
+    ConditionState mNonSlicedConditionState;
+
+    bool mSliced;
 };
 
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
 
-#endif  // CONDITION_TRACKER_H
diff --git a/cmds/statsd/src/condition/ConditionWizard.cpp b/cmds/statsd/src/condition/ConditionWizard.cpp
new file mode 100644
index 0000000..411f7e5
--- /dev/null
+++ b/cmds/statsd/src/condition/ConditionWizard.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "ConditionWizard.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::map;
+using std::string;
+using std::vector;
+
+ConditionState ConditionWizard::query(const int index,
+                                      const map<string, HashableDimensionKey>& parameters) {
+    vector<ConditionState> cache(mAllConditions.size(), ConditionState::kNotEvaluated);
+
+    mAllConditions[index]->isConditionMet(parameters, mAllConditions, cache);
+    return cache[index];
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/condition/ConditionWizard.h b/cmds/statsd/src/condition/ConditionWizard.h
new file mode 100644
index 0000000..4889b64
--- /dev/null
+++ b/cmds/statsd/src/condition/ConditionWizard.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CONDITION_WIZARD_H
+#define CONDITION_WIZARD_H
+
+#include "ConditionTracker.h"
+#include "condition_util.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// Held by MetricProducer, to query a condition state with input defined in EventConditionLink.
+class ConditionWizard : public virtual android::RefBase {
+public:
+    ConditionWizard(std::vector<sp<ConditionTracker>>& conditionTrackers)
+        : mAllConditions(conditionTrackers){};
+
+    // Query condition state, for a ConditionTracker at [conditionIndex], with [conditionParameters]
+    // [conditionParameters] mapping from condition name to the HashableDimensionKey to query the
+    //                       condition.
+    // The ConditionTracker at [conditionIndex] can be a CombinationConditionTracker. In this case,
+    // the conditionParameters contains the parameters for it's children SimpleConditionTrackers.
+    ConditionState query(const int conditionIndex,
+                         const std::map<std::string, HashableDimensionKey>& conditionParameters);
+
+private:
+    std::vector<sp<ConditionTracker>>& mAllConditions;
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+#endif  // CONDITION_WIZARD_H
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index e78c0de..bde3846 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -14,24 +14,23 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "Stats_SimpleConditionTracker"
 #define DEBUG true  // STOPSHIP if true
-#define VLOG(...) \
-    if (DEBUG) ALOGD(__VA_ARGS__);
+#include "Log.h"
 
 #include "SimpleConditionTracker.h"
-#include <cutils/log.h>
-#include <log/logprint.h>
 
-using std::string;
-using std::unique_ptr;
-using std::unordered_map;
-using std::vector;
+#include <log/logprint.h>
 
 namespace android {
 namespace os {
 namespace statsd {
 
+using std::map;
+using std::string;
+using std::unique_ptr;
+using std::unordered_map;
+using std::vector;
+
 SimpleConditionTracker::SimpleConditionTracker(
         const string& name, const int index, const SimpleCondition& simpleCondition,
         const unordered_map<string, int>& trackerNameIndexMap)
@@ -66,7 +65,7 @@
     if (simpleCondition.has_stop_all()) {
         auto pair = trackerNameIndexMap.find(simpleCondition.stop_all());
         if (pair == trackerNameIndexMap.end()) {
-            ALOGW("Stop matcher %s not found in the config", simpleCondition.stop().c_str());
+            ALOGW("Stop all matcher %s not found in the config", simpleCondition.stop().c_str());
             return;
         }
         mStopAllLogMatcherIndex = pair->second;
@@ -91,41 +90,136 @@
     return mInitialized;
 }
 
-bool SimpleConditionTracker::evaluateCondition(const LogEventWrapper& event,
+void print(unordered_map<HashableDimensionKey, ConditionState>& conditions, const string& name) {
+    VLOG("%s DUMP:", name.c_str());
+
+    for (const auto& pair : conditions) {
+        VLOG("\t%s %d", pair.first.c_str(), pair.second);
+    }
+}
+
+void SimpleConditionTracker::addDimensions(const std::vector<KeyMatcher>& keyMatchers) {
+    VLOG("Added dimensions size %lu", (unsigned long)keyMatchers.size());
+    mDimensionsList.push_back(keyMatchers);
+    mSliced = true;
+}
+
+bool SimpleConditionTracker::evaluateCondition(const LogEvent& event,
                                                const vector<MatchingState>& eventMatcherValues,
                                                const vector<sp<ConditionTracker>>& mAllConditions,
                                                vector<ConditionState>& conditionCache,
-                                               vector<bool>& changedCache) {
+                                               vector<bool>& nonSlicedConditionChanged,
+                                               std::vector<bool>& slicedConditionChanged) {
     if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
         // it has been evaluated.
-        VLOG("Yes, already evaluated, %s %d", mName.c_str(), mConditionState);
+        VLOG("Yes, already evaluated, %s %d", mName.c_str(), mNonSlicedConditionState);
         return false;
     }
 
     // Ignore nesting, because we know we cannot trust ourselves on tracking nesting conditions.
-    ConditionState newCondition = mConditionState;
+
+    ConditionState newCondition = mNonSlicedConditionState;
+    bool matched = false;
     // Note: The order to evaluate the following start, stop, stop_all matters.
     // The priority of overwrite is stop_all > stop > start.
     if (mStartLogMatcherIndex >= 0 &&
         eventMatcherValues[mStartLogMatcherIndex] == MatchingState::kMatched) {
+        matched = true;
         newCondition = ConditionState::kTrue;
     }
 
     if (mStopLogMatcherIndex >= 0 &&
         eventMatcherValues[mStopLogMatcherIndex] == MatchingState::kMatched) {
+        matched = true;
         newCondition = ConditionState::kFalse;
     }
 
+    bool stopAll = false;
     if (mStopAllLogMatcherIndex >= 0 &&
         eventMatcherValues[mStopAllLogMatcherIndex] == MatchingState::kMatched) {
+        matched = true;
         newCondition = ConditionState::kFalse;
+        stopAll = true;
     }
 
-    bool changed = (mConditionState != newCondition);
-    mConditionState = newCondition;
-    conditionCache[mIndex] = mConditionState;
-    changedCache[mIndex] = changed;
-    return changed;
+    if (matched == false) {
+        slicedConditionChanged[mIndex] = false;
+        nonSlicedConditionChanged[mIndex] = false;
+        conditionCache[mIndex] = mNonSlicedConditionState;
+        return false;
+    }
+
+    bool nonSlicedChanged = mNonSlicedConditionState != newCondition;
+
+    bool slicedChanged = false;
+
+    if (stopAll) {
+        // TODO: handle stop all; all dimension should be cleared.
+    }
+
+    if (mDimensionsList.size() > 0) {
+        for (size_t i = 0; i < mDimensionsList.size(); i++) {
+            const auto& dim = mDimensionsList[i];
+            vector<KeyValuePair> key = getDimensionKey(event, dim);
+            HashableDimensionKey hashableKey = getHashableKey(key);
+            if (mSlicedConditionState.find(hashableKey) == mSlicedConditionState.end() ||
+                mSlicedConditionState[hashableKey] != newCondition) {
+                slicedChanged = true;
+                mSlicedConditionState[hashableKey] = newCondition;
+            }
+            VLOG("key: %s %d", hashableKey.c_str(), newCondition);
+        }
+        // dump all dimensions for debugging
+        if (DEBUG) {
+            print(mSlicedConditionState, mName);
+        }
+    }
+
+    // even if this SimpleCondition is not sliced, it may be part of a sliced CombinationCondition
+    // if the nonSliced condition changed, it may affect the sliced condition in the parent node.
+    // so mark the slicedConditionChanged to be true.
+    // For example: APP_IN_BACKGROUND_OR_SCREEN_OFF
+    //     APP_IN_BACKGROUND is sliced [App_A->True, App_B->False].
+    //     SCREEN_OFF is not sliced, and it changes from False -> True;
+    //     We need to populate this change to parent condition. Because for App_B,
+    //     the APP_IN_BACKGROUND_OR_SCREEN_OFF condition would change from False->True.
+    slicedConditionChanged[mIndex] = mSliced ? slicedChanged : nonSlicedChanged;
+    nonSlicedConditionChanged[mIndex] = nonSlicedChanged;
+
+    VLOG("SimpleCondition %s nonSlicedChange? %d  SlicedChanged? %d", mName.c_str(),
+         nonSlicedConditionChanged[mIndex] == true, slicedConditionChanged[mIndex] == true);
+    mNonSlicedConditionState = newCondition;
+    conditionCache[mIndex] = mNonSlicedConditionState;
+
+    return nonSlicedConditionChanged[mIndex];
+}
+
+void SimpleConditionTracker::isConditionMet(
+        const map<string, HashableDimensionKey>& conditionParameters,
+        const vector<sp<ConditionTracker>>& allConditions, vector<ConditionState>& conditionCache) {
+    const auto pair = conditionParameters.find(mName);
+    if (pair == conditionParameters.end()) {
+        // the query does not need my sliced condition. just return the non sliced condition.
+        conditionCache[mIndex] = mNonSlicedConditionState;
+        VLOG("Condition %s return %d", mName.c_str(), mNonSlicedConditionState);
+        return;
+    }
+
+    const HashableDimensionKey& key = pair->second;
+    VLOG("simpleCondition %s query key: %s", mName.c_str(), key.c_str());
+
+    if (mSlicedConditionState.find(key) == mSlicedConditionState.end()) {
+        // never seen this key before. the condition is unknown to us.
+        conditionCache[mIndex] = ConditionState::kUnknown;
+    } else {
+        conditionCache[mIndex] = mSlicedConditionState[key];
+    }
+
+    VLOG("Condition %s return %d", mName.c_str(), conditionCache[mIndex]);
+
+    if (DEBUG) {
+        print(mSlicedConditionState, mName);
+    }
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h
index 41e1707..1f357f0 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.h
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.h
@@ -19,6 +19,7 @@
 
 #include "ConditionTracker.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "stats_util.h"
 
 namespace android {
 namespace os {
@@ -26,6 +27,8 @@
 
 class SimpleConditionTracker : public virtual ConditionTracker {
 public:
+    // dimensions is a vector of vector because for one single condition, different metrics may be
+    // interested in slicing in different ways. one vector<KeyMatcher> defines one type of slicing.
     SimpleConditionTracker(const std::string& name, const int index,
                            const SimpleCondition& simpleCondition,
                            const std::unordered_map<std::string, int>& trackerNameIndexMap);
@@ -37,11 +40,18 @@
               const std::unordered_map<std::string, int>& conditionNameIndexMap,
               std::vector<bool>& stack) override;
 
-    bool evaluateCondition(const LogEventWrapper& event,
+    bool evaluateCondition(const LogEvent& event,
                            const std::vector<MatchingState>& eventMatcherValues,
                            const std::vector<sp<ConditionTracker>>& mAllConditions,
                            std::vector<ConditionState>& conditionCache,
-                           std::vector<bool>& changedCache) override;
+                           std::vector<bool>& changedCache,
+                           std::vector<bool>& slicedChangedCache) override;
+
+    void isConditionMet(const std::map<std::string, HashableDimensionKey>& conditionParameters,
+                        const std::vector<sp<ConditionTracker>>& allConditions,
+                        std::vector<ConditionState>& conditionCache) override;
+
+    void addDimensions(const std::vector<KeyMatcher>& keyMatchers) override;
 
 private:
     // The index of the LogEventMatcher which defines the start.
@@ -55,6 +65,13 @@
 
     // The index of the LogEventMatcher which defines the stop all.
     int mStopAllLogMatcherIndex;
+
+    // Different metrics may subscribe to different types of slicings. So it's a vector of vector.
+    std::vector<std::vector<KeyMatcher>> mDimensionsList;
+
+    // Keep the map from the internal HashableDimensionKey to std::vector<KeyValuePair>
+    // that StatsLogReport wants.
+    std::unordered_map<HashableDimensionKey, ConditionState> mSlicedConditionState;
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/condition/condition_util.cpp b/cmds/statsd/src/condition/condition_util.cpp
index cb07d15..40d41be 100644
--- a/cmds/statsd/src/condition/condition_util.cpp
+++ b/cmds/statsd/src/condition/condition_util.cpp
@@ -14,27 +14,30 @@
  * limitations under the License.
  */
 
+#include "Log.h"
+
 #include "condition_util.h"
 
-#include <cutils/log.h>
 #include <log/event_tag_map.h>
 #include <log/log_event_list.h>
 #include <log/logprint.h>
 #include <utils/Errors.h>
 #include <unordered_map>
+#include "../matchers/matcher_util.h"
 #include "ConditionTracker.h"
 #include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 #include "stats_util.h"
 
+namespace android {
+namespace os {
+namespace statsd {
+
 using std::set;
 using std::string;
 using std::unordered_map;
 using std::vector;
 
-namespace android {
-namespace os {
-namespace statsd {
 
 ConditionState evaluateCombinationCondition(const std::vector<int>& children,
                                             const LogicalOperation& operation,
@@ -88,6 +91,25 @@
     return newCondition;
 }
 
+HashableDimensionKey getDimensionKeyForCondition(const LogEvent& event,
+                                                 const EventConditionLink& link) {
+    vector<KeyMatcher> eventKey;
+    eventKey.reserve(link.key_in_main().size());
+
+    for (const auto& key : link.key_in_main()) {
+        eventKey.push_back(key);
+    }
+
+    vector<KeyValuePair> dimensionKey = getDimensionKey(event, eventKey);
+
+    for (int i = 0; i < link.key_in_main_size(); i++) {
+        auto& kv = dimensionKey[i];
+        kv.set_key(link.key_in_condition(i).key());
+    }
+
+    return getHashableKey(dimensionKey);
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/condition/condition_util.h b/cmds/statsd/src/condition/condition_util.h
index a4fcea3..47e245e 100644
--- a/cmds/statsd/src/condition/condition_util.h
+++ b/cmds/statsd/src/condition/condition_util.h
@@ -18,6 +18,7 @@
 #define CONDITION_UTIL_H
 
 #include <vector>
+#include "../matchers/matcher_util.h"
 #include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
@@ -35,6 +36,9 @@
 ConditionState evaluateCombinationCondition(const std::vector<int>& children,
                                             const LogicalOperation& operation,
                                             const std::vector<ConditionState>& conditionCache);
+
+HashableDimensionKey getDimensionKeyForCondition(const LogEvent& event,
+                                                 const EventConditionLink& link);
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/config/ConfigKey.cpp b/cmds/statsd/src/config/ConfigKey.cpp
new file mode 100644
index 0000000..a365dc0
--- /dev/null
+++ b/cmds/statsd/src/config/ConfigKey.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "config/ConfigKey.h"
+
+#include <sstream>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::ostringstream;
+
+ConfigKey::ConfigKey() {
+}
+
+ConfigKey::ConfigKey(const ConfigKey& that) : mName(that.mName), mUid(that.mUid) {
+}
+
+ConfigKey::ConfigKey(int uid, const string& name) : mName(name), mUid(uid) {
+}
+
+ConfigKey::~ConfigKey() {
+}
+
+string ConfigKey::ToString() const {
+    ostringstream out;
+    out << '(' << mUid << ',' << mName << ')';
+    return out.str();
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/config/ConfigKey.h b/cmds/statsd/src/config/ConfigKey.h
new file mode 100644
index 0000000..bbf20fd
--- /dev/null
+++ b/cmds/statsd/src/config/ConfigKey.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+#include <functional>
+#include <iostream>
+#include <string>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::hash;
+using std::ostream;
+using std::string;
+
+/**
+ * Uniquely identifies a configuration.
+ */
+class ConfigKey {
+public:
+    ConfigKey();
+    explicit ConfigKey(const ConfigKey& that);
+    ConfigKey(int uid, const string& name);
+    ~ConfigKey();
+
+    inline int GetUid() const {
+        return mUid;
+    }
+    inline const string& GetName() const {
+        return mName;
+    }
+
+    inline bool operator<(const ConfigKey& that) const {
+        if (mUid < that.mUid) {
+            return true;
+        }
+        if (mUid > that.mUid) {
+            return false;
+        }
+        return mName < that.mName;
+    };
+
+    inline bool operator==(const ConfigKey& that) const {
+        return mUid == that.mUid && mName == that.mName;
+    };
+
+    string ToString() const;
+
+private:
+    string mName;
+    int mUid;
+};
+
+inline ostream& operator<<(ostream& os, const ConfigKey& config) {
+    return os << config.ToString();
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+
+/**
+ * A hash function for ConfigKey so it can be used for unordered_map/set.
+ * Unfortunately this hast to go in std namespace because C++ is fun!
+ */
+namespace std {
+
+using android::os::statsd::ConfigKey;
+
+template <>
+struct hash<ConfigKey> {
+    std::size_t operator()(const ConfigKey& key) const {
+        return (7 * key.GetUid()) ^ ((hash<string>()(key.GetName())));
+    }
+};
+
+}  // namespace std
diff --git a/cmds/statsd/src/config/ConfigListener.cpp b/cmds/statsd/src/config/ConfigListener.cpp
new file mode 100644
index 0000000..21a3f16
--- /dev/null
+++ b/cmds/statsd/src/config/ConfigListener.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "config/ConfigListener.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+ConfigListener::ConfigListener() {
+}
+
+ConfigListener::~ConfigListener() {
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/config/ConfigListener.h b/cmds/statsd/src/config/ConfigListener.h
new file mode 100644
index 0000000..a58766d
--- /dev/null
+++ b/cmds/statsd/src/config/ConfigListener.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <frameworks/base/cmds/statsd/src/stats_log.pb.h>
+#include "config/ConfigKey.h"
+
+#include <utils/RefBase.h>
+#include <string>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using android::RefBase;
+using std::string;
+
+/**
+ * Callback for different subsystems inside statsd to implement to find out
+ * when a configuration has been added, updated or removed.
+ */
+class ConfigListener : public virtual RefBase {
+public:
+    ConfigListener();
+    virtual ~ConfigListener();
+
+    /**
+     * A configuration was added or updated.
+     */
+    virtual void OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config) = 0;
+
+    /**
+     * A configuration was removed.
+     */
+    virtual void OnConfigRemoved(const ConfigKey& key) = 0;
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
new file mode 100644
index 0000000..038edd3
--- /dev/null
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "config/ConfigManager.h"
+
+#include "stats_util.h"
+
+#include <vector>
+
+#include <stdio.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+static StatsdConfig build_fake_config();
+
+ConfigManager::ConfigManager() {
+}
+
+ConfigManager::~ConfigManager() {
+}
+
+void ConfigManager::Startup() {
+    // TODO: Implement me -- read from storage and call onto all of the listeners.
+    // Instead, we'll just make a fake one.
+
+    // this should be called from StatsService when it receives a statsd_config
+    UpdateConfig(ConfigKey(0, "fake"), build_fake_config());
+}
+
+void ConfigManager::AddListener(const sp<ConfigListener>& listener) {
+    mListeners.push_back(listener);
+}
+
+void ConfigManager::UpdateConfig(const ConfigKey& key, const StatsdConfig& config) {
+    // Add to map
+    mConfigs[key] = config;
+    // Why doesn't this work? mConfigs.insert({key, config});
+
+    // Save to disk
+    update_saved_configs();
+
+    // Tell everyone
+    for (auto& listener : mListeners) {
+        listener->OnConfigUpdated(key, config);
+    }
+}
+
+void ConfigManager::RemoveConfig(const ConfigKey& key) {
+    unordered_map<ConfigKey, StatsdConfig>::iterator it = mConfigs.find(key);
+    if (it != mConfigs.end()) {
+        // Remove from map
+        mConfigs.erase(it);
+
+        // Save to disk
+        update_saved_configs();
+
+        // Tell everyone
+        for (auto& listener : mListeners) {
+            listener->OnConfigRemoved(key);
+        }
+    }
+    // If we didn't find it, just quietly ignore it.
+}
+
+void ConfigManager::RemoveConfigs(int uid) {
+    vector<ConfigKey> removed;
+
+    for (auto it = mConfigs.begin(); it != mConfigs.end();) {
+        // Remove from map
+        if (it->first.GetUid() == uid) {
+            removed.push_back(it->first);
+            it = mConfigs.erase(it);
+        } else {
+            it++;
+        }
+    }
+
+    // Remove separately so if they do anything in the callback they can't mess up our iteration.
+    for (auto& key : removed) {
+        // Tell everyone
+        for (auto& listener : mListeners) {
+            listener->OnConfigRemoved(key);
+        }
+    }
+}
+
+void ConfigManager::Dump(FILE* out) {
+    fprintf(out, "CONFIGURATIONS (%d)\n", (int)mConfigs.size());
+    fprintf(out, "     uid name\n");
+    for (unordered_map<ConfigKey, StatsdConfig>::const_iterator it = mConfigs.begin();
+         it != mConfigs.end(); it++) {
+        fprintf(out, "  %6d %s\n", it->first.GetUid(), it->first.GetName().c_str());
+        // TODO: Print the contents of the config too.
+    }
+}
+
+void ConfigManager::update_saved_configs() {
+    // TODO: Implement me -- write to disk.
+}
+
+static StatsdConfig build_fake_config() {
+    // HACK: Hard code a test metric for counting screen on events...
+    StatsdConfig config;
+    config.set_config_id(12345L);
+
+    int WAKE_LOCK_TAG_ID = 11;
+    int WAKE_LOCK_UID_KEY_ID = 1;
+    int WAKE_LOCK_STATE_KEY = 2;
+    int WAKE_LOCK_ACQUIRE_VALUE = 1;
+    int WAKE_LOCK_RELEASE_VALUE = 0;
+
+    int APP_USAGE_ID = 12345;
+    int APP_USAGE_UID_KEY_ID = 1;
+    int APP_USAGE_STATE_KEY = 2;
+    int APP_USAGE_FOREGROUND = 1;
+    int APP_USAGE_BACKGROUND = 0;
+
+    int SCREEN_EVENT_TAG_ID = 2;
+    int SCREEN_EVENT_STATE_KEY = 1;
+    int SCREEN_EVENT_ON_VALUE = 2;
+    int SCREEN_EVENT_OFF_VALUE = 1;
+
+    int UID_PROCESS_STATE_TAG_ID = 3;
+    int UID_PROCESS_STATE_UID_KEY = 1;
+
+    // Count Screen ON events.
+    CountMetric* metric = config.add_count_metric();
+    metric->set_metric_id(1);
+    metric->set_what("SCREEN_TURNED_ON");
+    metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
+
+    // Count process state changes, slice by uid.
+    metric = config.add_count_metric();
+    metric->set_metric_id(2);
+    metric->set_what("PROCESS_STATE_CHANGE");
+    metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
+    KeyMatcher* keyMatcher = metric->add_dimension();
+    keyMatcher->set_key(UID_PROCESS_STATE_UID_KEY);
+
+    // Count process state changes, slice by uid, while SCREEN_IS_OFF
+    metric = config.add_count_metric();
+    metric->set_metric_id(3);
+    metric->set_what("PROCESS_STATE_CHANGE");
+    metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
+    keyMatcher = metric->add_dimension();
+    keyMatcher->set_key(UID_PROCESS_STATE_UID_KEY);
+    metric->set_condition("SCREEN_IS_OFF");
+
+    // Count wake lock, slice by uid, while SCREEN_IS_OFF and app in background
+    metric = config.add_count_metric();
+    metric->set_metric_id(4);
+    metric->set_what("APP_GET_WL");
+    metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
+    keyMatcher = metric->add_dimension();
+    keyMatcher->set_key(WAKE_LOCK_UID_KEY_ID);
+    metric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON");
+    EventConditionLink* link = metric->add_links();
+    link->set_condition("APP_IS_BACKGROUND");
+    link->add_key_in_main()->set_key(WAKE_LOCK_UID_KEY_ID);
+    link->add_key_in_condition()->set_key(APP_USAGE_UID_KEY_ID);
+
+    // Duration of an app holding wl, while screen on and app in background
+    DurationMetric* durationMetric = config.add_duration_metric();
+    durationMetric->set_metric_id(5);
+    durationMetric->set_start("APP_GET_WL");
+    durationMetric->set_stop("APP_RELEASE_WL");
+    durationMetric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
+    durationMetric->set_type(DurationMetric_AggregationType_DURATION_SUM);
+    keyMatcher = durationMetric->add_dimension();
+    keyMatcher->set_key(WAKE_LOCK_UID_KEY_ID);
+    durationMetric->set_predicate("APP_IS_BACKGROUND_AND_SCREEN_ON");
+    link = durationMetric->add_links();
+    link->set_condition("APP_IS_BACKGROUND");
+    link->add_key_in_main()->set_key(WAKE_LOCK_UID_KEY_ID);
+    link->add_key_in_condition()->set_key(APP_USAGE_UID_KEY_ID);
+
+    // Event matchers............
+    LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
+    eventMatcher->set_name("SCREEN_TURNED_ON");
+    SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+    simpleLogEntryMatcher->set_tag(SCREEN_EVENT_TAG_ID);
+    KeyValueMatcher* keyValueMatcher = simpleLogEntryMatcher->add_key_value_matcher();
+    keyValueMatcher->mutable_key_matcher()->set_key(SCREEN_EVENT_STATE_KEY);
+    keyValueMatcher->set_eq_int(SCREEN_EVENT_ON_VALUE);
+
+    eventMatcher = config.add_log_entry_matcher();
+    eventMatcher->set_name("SCREEN_TURNED_OFF");
+    simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+    simpleLogEntryMatcher->set_tag(SCREEN_EVENT_TAG_ID);
+    keyValueMatcher = simpleLogEntryMatcher->add_key_value_matcher();
+    keyValueMatcher->mutable_key_matcher()->set_key(SCREEN_EVENT_STATE_KEY);
+    keyValueMatcher->set_eq_int(SCREEN_EVENT_OFF_VALUE);
+
+    eventMatcher = config.add_log_entry_matcher();
+    eventMatcher->set_name("PROCESS_STATE_CHANGE");
+    simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+    simpleLogEntryMatcher->set_tag(UID_PROCESS_STATE_TAG_ID);
+
+    eventMatcher = config.add_log_entry_matcher();
+    eventMatcher->set_name("APP_GOES_BACKGROUND");
+    simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+    simpleLogEntryMatcher->set_tag(APP_USAGE_ID);
+    keyValueMatcher = simpleLogEntryMatcher->add_key_value_matcher();
+    keyValueMatcher->mutable_key_matcher()->set_key(APP_USAGE_STATE_KEY);
+    keyValueMatcher->set_eq_int(APP_USAGE_BACKGROUND);
+
+    eventMatcher = config.add_log_entry_matcher();
+    eventMatcher->set_name("APP_GOES_FOREGROUND");
+    simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+    simpleLogEntryMatcher->set_tag(APP_USAGE_ID);
+    keyValueMatcher = simpleLogEntryMatcher->add_key_value_matcher();
+    keyValueMatcher->mutable_key_matcher()->set_key(APP_USAGE_STATE_KEY);
+    keyValueMatcher->set_eq_int(APP_USAGE_FOREGROUND);
+
+    eventMatcher = config.add_log_entry_matcher();
+    eventMatcher->set_name("APP_GET_WL");
+    simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+    simpleLogEntryMatcher->set_tag(WAKE_LOCK_TAG_ID);
+    keyValueMatcher = simpleLogEntryMatcher->add_key_value_matcher();
+    keyValueMatcher->mutable_key_matcher()->set_key(WAKE_LOCK_STATE_KEY);
+    keyValueMatcher->set_eq_int(WAKE_LOCK_ACQUIRE_VALUE);
+
+    eventMatcher = config.add_log_entry_matcher();
+    eventMatcher->set_name("APP_RELEASE_WL");
+    simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+    simpleLogEntryMatcher->set_tag(WAKE_LOCK_TAG_ID);
+    keyValueMatcher = simpleLogEntryMatcher->add_key_value_matcher();
+    keyValueMatcher->mutable_key_matcher()->set_key(WAKE_LOCK_STATE_KEY);
+    keyValueMatcher->set_eq_int(WAKE_LOCK_RELEASE_VALUE);
+
+    // Conditions.............
+    Condition* condition = config.add_condition();
+    condition->set_name("SCREEN_IS_ON");
+    SimpleCondition* simpleCondition = condition->mutable_simple_condition();
+    simpleCondition->set_start("SCREEN_TURNED_ON");
+    simpleCondition->set_stop("SCREEN_TURNED_OFF");
+
+    condition = config.add_condition();
+    condition->set_name("SCREEN_IS_OFF");
+    simpleCondition = condition->mutable_simple_condition();
+    simpleCondition->set_start("SCREEN_TURNED_OFF");
+    simpleCondition->set_stop("SCREEN_TURNED_ON");
+
+    condition = config.add_condition();
+    condition->set_name("APP_IS_BACKGROUND");
+    simpleCondition = condition->mutable_simple_condition();
+    simpleCondition->set_start("APP_GOES_BACKGROUND");
+    simpleCondition->set_stop("APP_GOES_FOREGROUND");
+
+    condition = config.add_condition();
+    condition->set_name("APP_IS_BACKGROUND_AND_SCREEN_ON");
+    Condition_Combination* combination_condition = condition->mutable_combination();
+    combination_condition->set_operation(LogicalOperation::AND);
+    combination_condition->add_condition("APP_IS_BACKGROUND");
+    combination_condition->add_condition("SCREEN_IS_ON");
+
+    return config;
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
new file mode 100644
index 0000000..5d73eaf
--- /dev/null
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "config/ConfigKey.h"
+#include "config/ConfigListener.h"
+
+#include <string>
+#include <unordered_map>
+
+#include <stdio.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using android::RefBase;
+using std::string;
+using std::unordered_map;
+using std::vector;
+
+/**
+ * Keeps track of which configurations have been set from various sources.
+ *
+ * TODO: Store the configs persistently too.
+ * TODO: Dump method for debugging.
+ */
+class ConfigManager : public virtual RefBase {
+public:
+    ConfigManager();
+    virtual ~ConfigManager();
+
+    /**
+     * Call to load the saved configs from disk.
+     *
+     * TODO: Implement me
+     */
+    void Startup();
+
+    /**
+     * Someone else wants to know about the configs.
+     */
+    void AddListener(const sp<ConfigListener>& listener);
+
+    /**
+     * A configuration was added or updated.
+     *
+     * Reports this to listeners.
+     */
+    void UpdateConfig(const ConfigKey& key, const StatsdConfig& data);
+
+    /**
+     * A configuration was removed.
+     *
+     * Reports this to listeners.
+     */
+    void RemoveConfig(const ConfigKey& key);
+
+    /**
+     * Remove all of the configs for the given uid.
+     */
+    void RemoveConfigs(int uid);
+
+    /**
+     * Text dump of our state for debugging.
+     */
+    void Dump(FILE* out);
+
+private:
+    /**
+     * Save the configs to disk.
+     */
+    void update_saved_configs();
+
+    /**
+     * The Configs that have been set
+     */
+    unordered_map<ConfigKey, StatsdConfig> mConfigs;
+
+    /**
+     * The ConfigListeners that will be told about changes.
+     */
+    vector<sp<ConfigListener>> mListeners;
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/external/KernelWakelockPuller.cpp b/cmds/statsd/src/external/KernelWakelockPuller.cpp
new file mode 100644
index 0000000..b9abee0
--- /dev/null
+++ b/cmds/statsd/src/external/KernelWakelockPuller.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Log.h"
+
+#include <android/os/IStatsCompanionService.h>
+#include <binder/IPCThreadState.h>
+#include <private/android_filesystem_config.h>
+#include "StatsService.h"
+#include "external/KernelWakelockPuller.h"
+#include "external/StatsPuller.h"
+
+using namespace android;
+using namespace android::base;
+using namespace android::binder;
+using namespace android::os;
+using namespace std;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+const int KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS = 20;
+
+// The reading and parsing are implemented in Java. It is not difficult to port over. But for now
+// let StatsCompanionService handle that and send the data back.
+String16 KernelWakelockPuller::pull() {
+    sp<IStatsCompanionService> statsCompanion = StatsService::getStatsCompanionService();
+    String16 returned_value("");
+    if (statsCompanion != NULL) {
+        Status status = statsCompanion->pullData(KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS,
+                                                 &returned_value);
+        if (!status.isOk()) {
+            ALOGW("error pulling kernel wakelock");
+        }
+        ALOGD("KernelWakelockPuller::pull succeeded!");
+        // TODO: remove this when we integrate into aggregation chain.
+        ALOGD("%s", String8(returned_value).string());
+        return returned_value;
+    } else {
+        ALOGW("statsCompanion not found!");
+        return String16();
+    }
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/external/KernelWakelockPuller.h b/cmds/statsd/src/external/KernelWakelockPuller.h
new file mode 100644
index 0000000..1ec3376
--- /dev/null
+++ b/cmds/statsd/src/external/KernelWakelockPuller.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STATSD_KERNELWAKELOCKPULLER_H
+#define STATSD_KERNELWAKELOCKPULLER_H
+
+#include <utils/String16.h>
+#include "external/StatsPuller.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class KernelWakelockPuller : public StatsPuller {
+public:
+    // a number of stats need to be pulled from StatsCompanionService
+    //
+    const static int PULL_CODE_KERNEL_WAKELOCKS;
+    String16 pull() override;
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+
+#endif  // STATSD_KERNELWAKELOCKPULLER_H
diff --git a/cmds/statsd/src/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h
similarity index 100%
rename from cmds/statsd/src/StatsPuller.h
rename to cmds/statsd/src/external/StatsPuller.h
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
new file mode 100644
index 0000000..6e8d58bc
--- /dev/null
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define DEBUG true
+#include "Log.h"
+
+#include <android/os/IStatsCompanionService.h>
+#include "KernelWakelockPuller.h"
+#include "StatsService.h"
+#include "external/StatsPullerManager.h"
+
+using namespace android;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+const int StatsPullerManager::KERNEL_WAKELOCKS = 1;
+
+StatsPullerManager::StatsPullerManager() {
+    mStatsPullers.insert(
+            {static_cast<int>(KERNEL_WAKELOCKS), std::make_unique<KernelWakelockPuller>()});
+}
+
+String16 StatsPullerManager::pull(int pullCode) {
+    if (DEBUG) ALOGD("Initiating pulling %d", pullCode);
+    if (mStatsPullers.find(pullCode) != mStatsPullers.end()) {
+        return (mStatsPullers.find(pullCode)->second)->pull();
+    } else {
+        ALOGD("Unknown pull code %d", pullCode);
+        return String16();
+    }
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h
new file mode 100644
index 0000000..f143424
--- /dev/null
+++ b/cmds/statsd/src/external/StatsPullerManager.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STATSD_STATSPULLERMANAGER_H
+#define STATSD_STATSPULLERMANAGER_H
+
+#include <utils/String16.h>
+#include <unordered_map>
+#include "external/StatsPuller.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+const static int KERNEL_WAKELOCKS = 1;
+
+class StatsPullerManager {
+public:
+    // Enums of pulled data types (pullCodes)
+    // These values must be kept in sync with com/android/server/stats/StatsCompanionService.java.
+    // TODO: pull the constant from stats_events.proto instead
+    const static int KERNEL_WAKELOCKS;
+    StatsPullerManager();
+
+    String16 pull(const int pullCode);
+
+private:
+    std::unordered_map<int, std::unique_ptr<StatsPuller>> mStatsPullers;
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+
+#endif  // STATSD_STATSPULLERMANAGER_H
diff --git a/cmds/statsd/src/indexed_priority_queue.h b/cmds/statsd/src/indexed_priority_queue.h
deleted file mode 100644
index 81e8b3d..0000000
--- a/cmds/statsd/src/indexed_priority_queue.h
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef STATSD_INDEXED_PRIORITY_QUEUE_H
-#define STATSD_INDEXED_PRIORITY_QUEUE_H
-
-// ALOGE can be called from this file. If header loaded by another class, use their LOG_TAG instead.
-#ifndef LOG_TAG
-#define LOG_TAG "statsd(indexed_priority_queue)"
-#endif  // LOG_TAG
-
-#include <cutils/log.h>
-#include <utils/RefBase.h>
-#include <unordered_map>
-#include <vector>
-
-using namespace android;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/** Defines a hash function for sp<AA>, returning the hash of the underlying pointer. */
-template <class AA>
-struct SpHash {
-    size_t operator()(const sp<const AA>& k) const {
-        return std::hash<const AA*>()(k.get());
-    }
-};
-
-/**
- * Min priority queue for generic type AA.
- * Unlike a regular priority queue, this class is also capable of removing interior elements.
- * @tparam Comparator must implement [bool operator()(sp<const AA> a, sp<const AA> b)], returning
- *    whether a should be closer to the top of the queue than b.
- */
-template <class AA, class Comparator>
-class indexed_priority_queue {
-public:
-    indexed_priority_queue();
-    /** Adds a into the priority queue. If already present or a==nullptr, does nothing. */
-    void push(sp<const AA> a);
-    /** Removes a from the priority queue. If not present or a==nullptr, does nothing. */
-    void remove(sp<const AA> a);
-    /** Removes the top element, if there is one. */
-    void pop();
-    /** Removes all elements. */
-    void clear();
-    /** Returns whether priority queue contains a (not just a copy of a, but a itself). */
-    bool contains(sp<const AA> a) const;
-    /** Returns min element. Returns nullptr iff empty(). */
-    sp<const AA> top() const;
-    /** Returns number of elements in priority queue. */
-    size_t size() const {
-        return pq.size() - 1;
-    }  // pq is 1-indexed
-    /** Returns true iff priority queue is empty. */
-    bool empty() const {
-        return size() < 1;
-    }
-
-private:
-    /** Vector representing a min-heap (1-indexed, with nullptr at 0). */
-    std::vector<sp<const AA>> pq;
-    /** Mapping of each element in pq to its index in pq (i.e. the inverse of a=pq[i]). */
-    std::unordered_map<sp<const AA>, size_t, SpHash<AA>> indices;
-
-    void init();
-    void sift_up(size_t idx);
-    void sift_down(size_t idx);
-    /** Returns whether pq[idx1] is considered higher than pq[idx2], according to Comparator. */
-    bool higher(size_t idx1, size_t idx2) const;
-    void swap_indices(size_t i, size_t j);
-};
-
-// Implementation must be done in this file due to use of template.
-
-template <class AA, class Comparator>
-indexed_priority_queue<AA, Comparator>::indexed_priority_queue() {
-    init();
-}
-
-template <class AA, class Comparator>
-void indexed_priority_queue<AA, Comparator>::push(sp<const AA> a) {
-    if (a == nullptr) return;
-    if (contains(a)) return;
-    pq.push_back(a);
-    size_t idx = size();  // index of last element since 1-indexed
-    indices.insert({a, idx});
-    sift_up(idx);  // get the pq back in order
-}
-
-template <class AA, class Comparator>
-void indexed_priority_queue<AA, Comparator>::remove(sp<const AA> a) {
-    if (a == nullptr) return;
-    if (!contains(a)) return;
-    size_t idx = indices[a];
-    if (idx >= pq.size()) {
-        ALOGE("indexed_priority_queue: Invalid index in map of indices.");
-        return;
-    }
-    if (idx == size()) {  // if a is the last element, i.e. at index idx == size() == (pq.size()-1)
-        pq.pop_back();
-        indices.erase(a);
-        return;
-    }
-    // move last element (guaranteed not to be at idx) to idx, then delete a
-    sp<const AA> last_a = pq.back();
-    pq[idx] = last_a;
-    pq.pop_back();
-    indices[last_a] = idx;
-    indices.erase(a);
-
-    // get the heap back in order (since the element at idx is not in order)
-    sift_up(idx);
-    sift_down(idx);
-}
-
-// The same as, but slightly more efficient than, remove(top()).
-template <class AA, class Comparator>
-void indexed_priority_queue<AA, Comparator>::pop() {
-  sp<const AA> a = top();
-  if (a == nullptr) return;
-  const size_t idx = 1;
-  if (idx == size()) {  // if a is the last element
-    pq.pop_back();
-    indices.erase(a);
-    return;
-  }
-  // move last element (guaranteed not to be at idx) to idx, then delete a
-  sp<const AA> last_a = pq.back();
-  pq[idx] = last_a;
-  pq.pop_back();
-  indices[last_a] = idx;
-  indices.erase(a);
-
-  // get the heap back in order (since the element at idx is not in order)
-  sift_down(idx);
-}
-
-template <class AA, class Comparator>
-void indexed_priority_queue<AA, Comparator>::clear() {
-    pq.clear();
-    indices.clear();
-    init();
-}
-
-template <class AA, class Comparator>
-sp<const AA> indexed_priority_queue<AA, Comparator>::top() const {
-    if (empty()) return nullptr;
-    return pq[1];
-}
-
-template <class AA, class Comparator>
-void indexed_priority_queue<AA, Comparator>::init() {
-    pq.push_back(nullptr);         // so that pq is 1-indexed.
-    indices.insert({nullptr, 0});  // just to be consistent with pq.
-}
-
-template <class AA, class Comparator>
-void indexed_priority_queue<AA, Comparator>::sift_up(size_t idx) {
-    while (idx > 1) {
-        size_t parent = idx / 2;
-        if (higher(idx, parent))
-            swap_indices(idx, parent);
-        else
-            break;
-        idx = parent;
-    }
-}
-
-template <class AA, class Comparator>
-void indexed_priority_queue<AA, Comparator>::sift_down(size_t idx) {
-    while (2 * idx <= size()) {
-        size_t child = 2 * idx;
-        if (child < size() && higher(child + 1, child)) child++;
-        if (higher(child, idx))
-            swap_indices(child, idx);
-        else
-            break;
-        idx = child;
-    }
-}
-
-template <class AA, class Comparator>
-bool indexed_priority_queue<AA, Comparator>::higher(size_t idx1, size_t idx2) const {
-    if (!(0u < idx1 && idx1 < pq.size() && 0u < idx2 && idx2 < pq.size())) {
-        ALOGE("indexed_priority_queue: Attempting to access invalid index");
-        return false;  // got to do something.
-    }
-    return Comparator()(pq[idx1], pq[idx2]);
-}
-
-template <class AA, class Comparator>
-bool indexed_priority_queue<AA, Comparator>::contains(sp<const AA> a) const {
-    if (a == nullptr) return false;  // publicly, we pretend that nullptr is not actually in pq.
-    return indices.count(a) > 0;
-}
-
-template <class AA, class Comparator>
-void indexed_priority_queue<AA, Comparator>::swap_indices(size_t i, size_t j) {
-    if (!(0u < i && i < pq.size() && 0u < j && j < pq.size())) {
-        ALOGE("indexed_priority_queue: Attempting to swap invalid index");
-        return;
-    }
-    sp<const AA> val_i = pq[i];
-    sp<const AA> val_j = pq[j];
-    pq[i] = val_j;
-    pq[j] = val_i;
-    indices[val_i] = j;
-    indices[val_j] = i;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#endif  // STATSD_INDEXED_PRIORITY_QUEUE_H
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
new file mode 100644
index 0000000..032b4b8
--- /dev/null
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "logd/LogEvent.h"
+
+#include <sstream>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::ostringstream;
+
+LogEvent::LogEvent(const log_msg& msg) {
+    init(msg);
+}
+
+LogEvent::LogEvent(int64_t timestampNs, android_log_event_list* reader) {
+    init(timestampNs, reader);
+}
+
+LogEvent::~LogEvent() {
+}
+
+/**
+ * The elements of each log event are stored as a vector of android_log_list_elements.
+ * The goal is to do as little preprocessing as possible, because we read a tiny fraction
+ * of the elements that are written to the log.
+ */
+void LogEvent::init(const log_msg& msg) {
+
+    android_log_event_list list(const_cast<log_msg&>(msg));
+    init(msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec, &list);
+}
+
+void LogEvent::init(int64_t timestampNs, android_log_event_list* reader) {
+    mTimestampNs = timestampNs;
+    mTagId = reader->tag();
+
+    mElements.clear();
+    android_log_list_element elem;
+
+    // TODO: The log is actually structured inside one list.  This is convenient
+    // because we'll be able to use it to put the attribution (WorkSource) block first
+    // without doing our own tagging scheme.  Until that change is in, just drop the
+    // list-related log elements and the order we get there is our index-keyed data
+    // structure.
+    do {
+        elem = android_log_read_next(reader->context());
+        switch ((int)elem.type) {
+            case EVENT_TYPE_INT:
+            case EVENT_TYPE_FLOAT:
+            case EVENT_TYPE_STRING:
+            case EVENT_TYPE_LONG:
+                mElements.push_back(elem);
+                break;
+            case EVENT_TYPE_LIST:
+                break;
+            case EVENT_TYPE_LIST_STOP:
+                break;
+            case EVENT_TYPE_UNKNOWN:
+                break;
+            default:
+                break;
+        }
+    } while ((elem.type != EVENT_TYPE_UNKNOWN) && !elem.complete);
+}
+
+int64_t LogEvent::GetLong(size_t key, status_t* err) const {
+    if (key < 1 || (key - 1)  >= mElements.size()) {
+        *err = BAD_INDEX;
+        return 0;
+    }
+    key--;
+    const android_log_list_element& elem = mElements[key];
+    if (elem.type == EVENT_TYPE_INT) {
+        return elem.data.int32;
+    } else if (elem.type == EVENT_TYPE_LONG) {
+        return elem.data.int64;
+    } else if (elem.type == EVENT_TYPE_FLOAT) {
+        return (int64_t)elem.data.float32;
+    } else {
+        *err = BAD_TYPE;
+        return 0;
+    }
+}
+
+const char* LogEvent::GetString(size_t key, status_t* err) const {
+    if (key < 1 || (key - 1)  >= mElements.size()) {
+        *err = BAD_INDEX;
+        return NULL;
+    }
+    key--;
+    const android_log_list_element& elem = mElements[key];
+    if (elem.type != EVENT_TYPE_STRING) {
+        *err = BAD_TYPE;
+        return NULL;
+    }
+    return elem.data.string;
+}
+
+bool LogEvent::GetBool(size_t key, status_t* err) const {
+    if (key < 1 || (key - 1)  >= mElements.size()) {
+        *err = BAD_INDEX;
+        return 0;
+    }
+    key--;
+    const android_log_list_element& elem = mElements[key];
+    if (elem.type == EVENT_TYPE_INT) {
+        return elem.data.int32 != 0;
+    } else if (elem.type == EVENT_TYPE_LONG) {
+        return elem.data.int64 != 0;
+    } else if (elem.type == EVENT_TYPE_FLOAT) {
+        return elem.data.float32 != 0;
+    } else {
+        *err = BAD_TYPE;
+        return 0;
+    }
+}
+
+float LogEvent::GetFloat(size_t key, status_t* err) const {
+    if (key < 1 || (key - 1)  >= mElements.size()) {
+        *err = BAD_INDEX;
+        return 0;
+    }
+    key--;
+    const android_log_list_element& elem = mElements[key];
+    if (elem.type == EVENT_TYPE_INT) {
+        return (float)elem.data.int32;
+    } else if (elem.type == EVENT_TYPE_LONG) {
+        return (float)elem.data.int64;
+    } else if (elem.type == EVENT_TYPE_FLOAT) {
+        return elem.data.float32;
+    } else {
+        *err = BAD_TYPE;
+        return 0;
+    }
+}
+
+KeyValuePair LogEvent::GetKeyValueProto(size_t key) const {
+    KeyValuePair pair;
+    pair.set_key(key);
+    // If the value is not valid, return the KeyValuePair without assigning the value.
+    // Caller can detect the error by checking the enum for "one of" proto type.
+    if (key < 1 || (key - 1) >= mElements.size()) {
+        return pair;
+    }
+    key--;
+
+    const android_log_list_element& elem = mElements[key];
+    if (elem.type == EVENT_TYPE_INT) {
+        pair.set_value_int(elem.data.int32);
+    } else if (elem.type == EVENT_TYPE_LONG) {
+        pair.set_value_int(elem.data.int64);
+    } else if (elem.type == EVENT_TYPE_STRING) {
+        pair.set_value_str(elem.data.string);
+    } else if (elem.type == EVENT_TYPE_FLOAT) {
+        pair.set_value_float(elem.data.float32);
+    }
+    return pair;
+}
+
+string LogEvent::ToString() const {
+    ostringstream result;
+    result << "{ " << mTimestampNs << " (" << mTagId << ")";
+    const size_t N = mElements.size();
+    for (size_t i=0; i<N; i++) {
+        result << " ";
+        result << (i + 1);
+        result << "->";
+        const android_log_list_element& elem = mElements[i];
+        if (elem.type == EVENT_TYPE_INT) {
+            result << elem.data.int32;
+        } else if (elem.type == EVENT_TYPE_LONG) {
+            result << elem.data.int64;
+        } else if (elem.type == EVENT_TYPE_FLOAT) {
+            result << elem.data.float32;
+        } else if (elem.type == EVENT_TYPE_STRING) {
+            result << elem.data.string;
+        }
+    }
+    result << " }";
+    return result.str();
+}
+
+void LogEvent::ToProto(EventMetricData* out) const {
+    // TODO: Implement this when we have the ProtoOutputStream version.
+
+    // set timestamp of the event.
+    out->set_timestamp_nanos(mTimestampNs);
+
+    // uint64_t token = proto->StartObject(EventMetricData.FIELD);
+    const size_t N = mElements.size();
+    for (size_t i=0; i<N; i++) {
+        const int key = i + 1;
+
+        const android_log_list_element& elem = mElements[i];
+        if (elem.type == EVENT_TYPE_INT) {
+            // proto->Write(key, elem.data.int32);
+        } else if (elem.type == EVENT_TYPE_LONG) {
+            // proto->Write(key, elem.data.int64);
+        } else if (elem.type == EVENT_TYPE_FLOAT) {
+            // proto->Write(key, elem.data.float32);
+        } else if (elem.type == EVENT_TYPE_STRING) {
+            // proto->Write(key, elem.data.string);
+        }
+    }
+
+    //proto->EndObject(token);
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
new file mode 100644
index 0000000..464afca
--- /dev/null
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+
+#include <utils/Errors.h>
+#include <log/log_event_list.h>
+#include <log/log_read.h>
+
+#include <string>
+#include <vector>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::string;
+using std::vector;
+
+/**
+ * Wrapper for the log_msg structure.
+ */
+class LogEvent {
+public:
+    /**
+     * Read a LogEvent from a log_msg.
+     */
+    explicit LogEvent(const log_msg& msg);
+
+    /**
+     * Read a LogEvent from an android_log_context.
+     */
+    explicit LogEvent(int64_t timestampNs, android_log_event_list* reader);
+    ~LogEvent();
+
+    /**
+     * Get the timestamp associated with this event.
+     */
+    uint64_t GetTimestampNs() const { return mTimestampNs; }
+
+    /**
+     * Get the tag for this event.
+     */
+    int GetTagId() const { return mTagId; }
+
+    /**
+     * Get the nth value, starting at 1.
+     *
+     * Returns BAD_INDEX if the index is larger than the number of elements.
+     * Returns BAD_TYPE if the index is available but the data is the wrong type.
+     */
+    int64_t GetLong(size_t key, status_t* err) const;
+    const char* GetString(size_t key, status_t* err) const;
+    bool GetBool(size_t key, status_t* err) const;
+    float GetFloat(size_t key, status_t* err) const;
+
+    /**
+     * Return a string representation of this event.
+     */
+    string ToString() const;
+
+    /**
+     * Write this object as an EventMetricData proto object.
+     * TODO: Use the streaming output generator to do this instead of this proto lite object?
+     */
+    void ToProto(EventMetricData* out) const;
+
+    /*
+     * Get a KeyValuePair proto object.
+     */
+    KeyValuePair GetKeyValueProto(size_t key) const;
+
+private:
+    /**
+     * Don't copy, it's slower. If we really need this we can add it but let's try to
+     * avoid it.
+     */
+    explicit LogEvent(const LogEvent&);
+
+    /**
+     * Parses a log_msg into a LogEvent object.
+     */
+    void init(const log_msg& msg);
+
+    /**
+     * Parses a log_msg into a LogEvent object.
+     */
+    void init(int64_t timestampNs, android_log_event_list* reader);
+
+    vector<android_log_list_element> mElements;
+    long mTimestampNs;
+    int mTagId;
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+
diff --git a/cmds/statsd/src/logd/LogListener.cpp b/cmds/statsd/src/logd/LogListener.cpp
new file mode 100644
index 0000000..6ac7978
--- /dev/null
+++ b/cmds/statsd/src/logd/LogListener.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "logd/LogReader.h"
+
+#include <log/log_read.h>
+
+#include <utils/Errors.h>
+
+#include <time.h>
+#include <unistd.h>
+
+using namespace android;
+using namespace std;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+LogListener::LogListener() {
+}
+
+LogListener::~LogListener() {
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/logd/LogListener.h b/cmds/statsd/src/logd/LogListener.h
new file mode 100644
index 0000000..9641226
--- /dev/null
+++ b/cmds/statsd/src/logd/LogListener.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "logd/LogEvent.h"
+
+#include <utils/RefBase.h>
+#include <vector>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * Callback for LogReader
+ */
+class LogListener : public virtual android::RefBase {
+public:
+    LogListener();
+    virtual ~LogListener();
+
+    virtual void OnLogEvent(const LogEvent& msg) = 0;
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/logd/LogReader.cpp b/cmds/statsd/src/logd/LogReader.cpp
new file mode 100644
index 0000000..c441a5e
--- /dev/null
+++ b/cmds/statsd/src/logd/LogReader.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "logd/LogReader.h"
+
+#include <utils/Errors.h>
+
+#include <time.h>
+#include <unistd.h>
+
+using namespace android;
+using namespace std;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+#define SNOOZE_INITIAL_MS 100
+#define SNOOZE_MAX_MS (10 * 60 * 1000)  // Ten minutes
+
+LogReader::LogReader(const sp<LogListener>& listener) : mListener(listener) {
+}
+
+LogReader::~LogReader() {
+}
+
+void LogReader::Run() {
+    int nextSnoozeMs = SNOOZE_INITIAL_MS;
+
+    // In an ideal world, this outer loop will only ever run one iteration, but it
+    // exists to handle crashes in logd.  The inner loop inside connect_and_read()
+    // reads from logd forever, but if that read fails, we fall out to the outer
+    // loop, do the backoff (resetting the backoff timeout if we successfully read
+    // something), and then try again.
+    while (true) {
+        // Connect and read
+        int lineCount = connect_and_read();
+
+        // Figure out how long to sleep.
+        if (lineCount > 0) {
+            // If we managed to read at least one line, reset the backoff
+            nextSnoozeMs = SNOOZE_INITIAL_MS;
+        } else {
+            // Otherwise, expontial backoff
+            nextSnoozeMs *= 1.5f;
+            if (nextSnoozeMs > 10 * 60 * 1000) {
+                // Don't wait for toooo long.
+                nextSnoozeMs = SNOOZE_MAX_MS;
+            }
+        }
+
+        // Sleep
+        timespec ts;
+        timespec rem;
+        ts.tv_sec = nextSnoozeMs / 1000;
+        ts.tv_nsec = (nextSnoozeMs % 1000) * 1000000L;
+        while (nanosleep(&ts, &rem) == -1) {
+            if (errno == EINTR) {
+                ts = rem;
+            }
+            // other errors are basically impossible
+        }
+    }
+}
+
+int LogReader::connect_and_read() {
+    int lineCount = 0;
+    status_t err;
+    logger_list* loggers;
+    logger* eventLogger;
+
+    // Prepare the logging context
+    loggers = android_logger_list_alloc(ANDROID_LOG_RDONLY,
+                                        /* don't stop after N lines */ 0,
+                                        /* no pid restriction */ 0);
+
+    // Open the buffer(s)
+    eventLogger = android_logger_open(loggers, LOG_ID_STATS);
+
+    // Read forever
+    if (eventLogger) {
+
+        while (true) {
+            log_msg msg;
+
+            // Read a message
+            err = android_logger_list_read(loggers, &msg);
+            if (err < 0) {
+                fprintf(stderr, "logcat read failure: %s\n", strerror(err));
+                break;
+            }
+
+            // Record that we read one (used above to know how to snooze).
+            lineCount++;
+
+            // Wrap it in a LogEvent object
+            LogEvent event(msg);
+
+            // Call the listener
+            mListener->OnLogEvent(event);
+        }
+    }
+
+    // Free the logger list and close the individual loggers
+    android_logger_list_free(loggers);
+
+    return lineCount;
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/logd/LogReader.h b/cmds/statsd/src/logd/LogReader.h
new file mode 100644
index 0000000..c51074c
--- /dev/null
+++ b/cmds/statsd/src/logd/LogReader.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LOGREADER_H
+#define LOGREADER_H
+
+#include "logd/LogListener.h"
+
+#include <utils/RefBase.h>
+
+#include <vector>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * Class to read logs from logd.
+ */
+class LogReader : public virtual android::RefBase {
+public:
+    /**
+     * Construct the LogReader with the event listener. (Which is StatsService)
+     */
+    LogReader(const sp<LogListener>& listener);
+
+    /**
+     * Destructor.
+     */
+    virtual ~LogReader();
+
+    /**
+     * Run the main LogReader loop
+     */
+    void Run();
+
+private:
+    /**
+     * Who is going to get the events when they're read.
+     */
+    sp<LogListener> mListener;
+
+    /**
+     * Connect to a single instance of logd, and read until there's a read error.
+     * Logd can crash, exit, be killed etc.
+     *
+     * Returns the number of lines that were read.
+     */
+    int connect_and_read();
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+
+#endif  // LOGREADER_H
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index 37477dc..a740280 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -14,20 +14,16 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "statsd"
+#include "Log.h"
 
-#include "LogEntryPrinter.h"
-#include "LogReader.h"
-#include "StatsLogProcessor.h"
 #include "StatsService.h"
-#include "UidMap.h"
+#include "logd/LogReader.h"
 
 #include <binder/IInterface.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 #include <binder/Status.h>
-#include <cutils/log.h>
 #include <utils/Looper.h>
 #include <utils/StrongPointer.h>
 
@@ -53,16 +49,12 @@
 static void* log_reader_thread_func(void* cookie) {
     log_reader_thread_data* data = static_cast<log_reader_thread_data*>(cookie);
 
-    sp<LogReader> reader = new LogReader();
+    sp<LogReader> reader = new LogReader(data->service);
 
-    // Put the printer one first, so it will print before the real ones.
-    reader->AddListener(new LogEntryPrinter(STDOUT_FILENO));
-    sp<StatsLogProcessor> main_processor = new StatsLogProcessor(data->service->getUidMap());
-    data->service->setProcessor(main_processor);
-    reader->AddListener(main_processor);
+    // Tell StatsService that we're ready to go.
+    data->service->Startup();
 
-    // TODO: Construct and add real LogListners here.
-
+    // Run the read loop. Never returns.
     reader->Run();
 
     ALOGW("statsd LogReader.Run() is not supposed to return.");
@@ -127,6 +119,8 @@
 
     // TODO: This line is temporary, since statsd doesn't start up automatically (and therefore
     // the call in StatsService::SystemRunning() won't ever be called right now).
+    // TODO: Are you sure? Don't we need to reconnect to the system process if we get restarted?
+    //  --joeo
     service->sayHiToStatsCompanion();
 
     // Start the log reader thread
diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
index 9f9b648..78ba762 100644
--- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
+++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
@@ -14,20 +14,21 @@
  * limitations under the License.
  */
 
-#include "CombinationLogMatchingTracker.h"
+#include "Log.h"
 
-#include <cutils/log.h>
-#include "matcher_util.h"
+#include "CombinationLogMatchingTracker.h"
+#include "matchers/matcher_util.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
 using std::set;
 using std::string;
 using std::unique_ptr;
 using std::unordered_map;
 using std::vector;
 
-namespace android {
-namespace os {
-namespace statsd {
-
 CombinationLogMatchingTracker::CombinationLogMatchingTracker(const string& name, const int index)
     : LogMatchingTracker(name, index) {
 }
@@ -91,7 +92,7 @@
     return true;
 }
 
-void CombinationLogMatchingTracker::onLogEvent(const LogEventWrapper& event,
+void CombinationLogMatchingTracker::onLogEvent(const LogEvent& event,
                                                const vector<sp<LogMatchingTracker>>& allTrackers,
                                                vector<MatchingState>& matcherResults) {
     // this event has been processed.
@@ -99,7 +100,7 @@
         return;
     }
 
-    if (mTagIds.find(event.tagId) == mTagIds.end()) {
+    if (mTagIds.find(event.GetTagId()) == mTagIds.end()) {
         matcherResults[mIndex] = MatchingState::kNotMatched;
         return;
     }
diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
index 51ee232..006d74c 100644
--- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
@@ -41,7 +41,7 @@
 
     ~CombinationLogMatchingTracker();
 
-    void onLogEvent(const LogEventWrapper& event,
+    void onLogEvent(const LogEvent& event,
                     const std::vector<sp<LogMatchingTracker>>& allTrackers,
                     std::vector<MatchingState>& matcherResults) override;
 
diff --git a/cmds/statsd/src/matchers/LogMatchingTracker.h b/cmds/statsd/src/matchers/LogMatchingTracker.h
index 4244bd5..d82da3b 100644
--- a/cmds/statsd/src/matchers/LogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/LogMatchingTracker.h
@@ -17,16 +17,16 @@
 #ifndef LOG_MATCHING_TRACKER_H
 #define LOG_MATCHING_TRACKER_H
 
-#include <log/log_read.h>
-#include <log/logprint.h>
-#include <utils/RefBase.h>
-#include <set>
-#include <unordered_map>
-
-#include <vector>
 #include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "matcher_util.h"
+#include "logd/LogEvent.h"
+#include "matchers/matcher_util.h"
+
+#include <utils/RefBase.h>
+
+#include <set>
+#include <unordered_map>
+#include <vector>
 
 namespace android {
 namespace os {
@@ -59,7 +59,7 @@
     // matcherResults: The cached results for all matchers for this event. Parent matchers can
     //                 directly access the children's matching results if they have been evaluated.
     //                 Otherwise, call children matchers' onLogEvent.
-    virtual void onLogEvent(const LogEventWrapper& event,
+    virtual void onLogEvent(const LogEvent& event,
                             const std::vector<sp<LogMatchingTracker>>& allTrackers,
                             std::vector<MatchingState>& matcherResults) = 0;
 
diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
index 1c83039..b2c88a0 100644
--- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
+++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
@@ -14,31 +14,32 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "SimpleLogMatchingTracker"
-#define DEBUG true  // STOPSHIP if true
-#define VLOG(...) \
-    if (DEBUG) ALOGD(__VA_ARGS__);
+#define DEBUG false  // STOPSHIP if true
+#include "Log.h"
 
 #include "SimpleLogMatchingTracker.h"
-#include <cutils/log.h>
+
 #include <log/logprint.h>
 
+namespace android {
+namespace os {
+namespace statsd {
+
 using std::string;
 using std::unique_ptr;
 using std::unordered_map;
 using std::vector;
 
-namespace android {
-namespace os {
-namespace statsd {
 
 SimpleLogMatchingTracker::SimpleLogMatchingTracker(const string& name, const int index,
                                                    const SimpleLogEntryMatcher& matcher)
     : LogMatchingTracker(name, index), mMatcher(matcher) {
-    for (int i = 0; i < matcher.tag_size(); i++) {
-        mTagIds.insert(matcher.tag(i));
+    if (!matcher.has_tag()) {
+        mInitialized = false;
+    } else {
+        mTagIds.insert(matcher.tag());
+        mInitialized = true;
     }
-    mInitialized = true;
 }
 
 SimpleLogMatchingTracker::~SimpleLogMatchingTracker() {
@@ -49,10 +50,10 @@
                                     const unordered_map<string, int>& matcherMap,
                                     vector<bool>& stack) {
     // no need to do anything.
-    return true;
+    return mInitialized;
 }
 
-void SimpleLogMatchingTracker::onLogEvent(const LogEventWrapper& event,
+void SimpleLogMatchingTracker::onLogEvent(const LogEvent& event,
                                           const vector<sp<LogMatchingTracker>>& allTrackers,
                                           vector<MatchingState>& matcherResults) {
     if (matcherResults[mIndex] != MatchingState::kNotComputed) {
@@ -60,7 +61,7 @@
         return;
     }
 
-    if (mTagIds.find(event.tagId) == mTagIds.end()) {
+    if (mTagIds.find(event.GetTagId()) == mTagIds.end()) {
         matcherResults[mIndex] = MatchingState::kNotMatched;
         return;
     }
diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
index 65dbe64..e110ec8 100644
--- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
@@ -42,7 +42,7 @@
               const std::unordered_map<std::string, int>& matcherMap,
               std::vector<bool>& stack) override;
 
-    void onLogEvent(const LogEventWrapper& event,
+    void onLogEvent(const LogEvent& event,
                     const std::vector<sp<LogMatchingTracker>>& allTrackers,
                     std::vector<MatchingState>& matcherResults) override;
 
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index 557c032..6aa2211 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -14,18 +14,23 @@
  * limitations under the License.
  */
 
-#include "matcher_util.h"
-#include <cutils/log.h>
+#include "Log.h"
+
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "matchers/LogMatchingTracker.h"
+#include "matchers/matcher_util.h"
+#include "stats_util.h"
+
 #include <log/event_tag_map.h>
 #include <log/log_event_list.h>
 #include <log/logprint.h>
 #include <utils/Errors.h>
-#include <unordered_map>
-#include "LogMatchingTracker.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "stats_util.h"
 
+#include <sstream>
+#include <unordered_map>
+
+using std::ostringstream;
 using std::set;
 using std::string;
 using std::unordered_map;
@@ -35,74 +40,6 @@
 namespace os {
 namespace statsd {
 
-LogEventWrapper parseLogEvent(log_msg msg) {
-    LogEventWrapper wrapper;
-    wrapper.timestamp_ns = msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec;
-    wrapper.tagId = getTagId(msg);
-
-    // start iterating k,v pairs.
-    android_log_context context =
-            create_android_log_parser(const_cast<log_msg*>(&msg)->msg() + sizeof(uint32_t),
-                                      const_cast<log_msg*>(&msg)->len() - sizeof(uint32_t));
-    android_log_list_element elem;
-
-    if (context) {
-        memset(&elem, 0, sizeof(elem));
-        size_t index = 0;
-        int32_t key = -1;
-        do {
-            elem = android_log_read_next(context);
-            switch ((int)elem.type) {
-                case EVENT_TYPE_INT:
-                    if (index % 2 == 0) {
-                        key = elem.data.int32;
-                    } else {
-                        wrapper.intMap[key] = elem.data.int32;
-                    }
-                    index++;
-                    break;
-                case EVENT_TYPE_FLOAT:
-                    if (index % 2 == 1) {
-                        wrapper.floatMap[key] = elem.data.float32;
-                    }
-                    index++;
-                    break;
-                case EVENT_TYPE_STRING:
-                    if (index % 2 == 1) {
-                        // without explicit calling string() constructor, there will be an
-                        // additional 0 in the end of the string.
-                        wrapper.strMap[key] = string(elem.data.string);
-                    }
-                    index++;
-                    break;
-                case EVENT_TYPE_LONG:
-                    if (index % 2 == 1) {
-                        wrapper.intMap[key] = elem.data.int64;
-                    }
-                    index++;
-                    break;
-                case EVENT_TYPE_LIST:
-                    break;
-                case EVENT_TYPE_LIST_STOP:
-                    break;
-                case EVENT_TYPE_UNKNOWN:
-                    break;
-                default:
-                    elem.complete = true;
-                    break;
-            }
-
-            if (elem.complete) {
-                break;
-            }
-        } while ((elem.type != EVENT_TYPE_UNKNOWN) && !elem.complete);
-
-        android_log_destroy(&context);
-    }
-
-    return wrapper;
-}
-
 bool combinationMatch(const vector<int>& children, const LogicalOperation& operation,
                       const vector<MatchingState>& matcherResults) {
     bool matched;
@@ -152,104 +89,105 @@
     return matched;
 }
 
-bool matchesSimple(const SimpleLogEntryMatcher& simpleMatcher, const LogEventWrapper& event) {
-    const int tagId = event.tagId;
-    const unordered_map<int, long>& intMap = event.intMap;
-    const unordered_map<int, string>& strMap = event.strMap;
-    const unordered_map<int, float>& floatMap = event.floatMap;
-    const unordered_map<int, bool>& boolMap = event.boolMap;
+bool matchesSimple(const SimpleLogEntryMatcher& simpleMatcher, const LogEvent& event) {
+    const int tagId = event.GetTagId();
 
-    for (int i = 0; i < simpleMatcher.tag_size(); i++) {
-        if (simpleMatcher.tag(i) != tagId) {
-            continue;
-        }
+    if (simpleMatcher.tag() != tagId) {
+        return false;
+    }
+    // now see if this event is interesting to us -- matches ALL the matchers
+    // defined in the metrics.
+    bool allMatched = true;
+    for (int j = 0; allMatched && j < simpleMatcher.key_value_matcher_size(); j++) {
+        auto cur = simpleMatcher.key_value_matcher(j);
 
-        // now see if this event is interesting to us -- matches ALL the matchers
-        // defined in the metrics.
-        bool allMatched = true;
-        for (int j = 0; j < simpleMatcher.key_value_matcher_size(); j++) {
-            auto cur = simpleMatcher.key_value_matcher(j);
+        // TODO: Check if this key is a magic key (eg package name).
+        // TODO: Maybe make packages a different type in the config?
+        int key = cur.key_matcher().key();
 
-            // TODO: Check if this key is a magic key (eg package name).
-            int key = cur.key_matcher().key();
-
-            switch (cur.value_matcher_case()) {
-                case KeyValueMatcher::ValueMatcherCase::kEqString: {
-                    auto it = strMap.find(key);
-                    if (it == strMap.end() || cur.eq_string().compare(it->second) != 0) {
-                        allMatched = false;
-                    }
-                    break;
+        const KeyValueMatcher::ValueMatcherCase matcherCase = cur.value_matcher_case();
+        if (matcherCase == KeyValueMatcher::ValueMatcherCase::kEqString) {
+            // String fields
+            status_t err = NO_ERROR;
+            const char* val = event.GetString(key, &err);
+            if (err == NO_ERROR && val != NULL) {
+                if (!(cur.eq_string() == val)) {
+                    allMatched = false;
                 }
-                case KeyValueMatcher::ValueMatcherCase::kEqInt: {
-                    auto it = intMap.find(key);
-                    if (it == intMap.end() || cur.eq_int() != it->second) {
-                        allMatched = false;
-                    }
-                    break;
-                }
-                case KeyValueMatcher::ValueMatcherCase::kEqBool: {
-                    auto it = boolMap.find(key);
-                    if (it == boolMap.end() || cur.eq_bool() != it->second) {
-                        allMatched = false;
-                    }
-                    break;
-                }
-                    // Begin numeric comparisons
-                case KeyValueMatcher::ValueMatcherCase::kLtInt: {
-                    auto it = intMap.find(key);
-                    if (it == intMap.end() || cur.lt_int() <= it->second) {
-                        allMatched = false;
-                    }
-                    break;
-                }
-                case KeyValueMatcher::ValueMatcherCase::kGtInt: {
-                    auto it = intMap.find(key);
-                    if (it == intMap.end() || cur.gt_int() >= it->second) {
-                        allMatched = false;
-                    }
-                    break;
-                }
-                case KeyValueMatcher::ValueMatcherCase::kLtFloat: {
-                    auto it = floatMap.find(key);
-                    if (it == floatMap.end() || cur.lt_float() <= it->second) {
-                        allMatched = false;
-                    }
-                    break;
-                }
-                case KeyValueMatcher::ValueMatcherCase::kGtFloat: {
-                    auto it = floatMap.find(key);
-                    if (it == floatMap.end() || cur.gt_float() >= it->second) {
-                        allMatched = false;
-                    }
-                    break;
-                }
-                // Begin comparisons with equality
-                case KeyValueMatcher::ValueMatcherCase::kLteInt: {
-                    auto it = intMap.find(key);
-                    if (it == intMap.end() || cur.lte_int() < it->second) {
-                        allMatched = false;
-                    }
-                    break;
-                }
-                case KeyValueMatcher::ValueMatcherCase::kGteInt: {
-                    auto it = intMap.find(key);
-                    if (it == intMap.end() || cur.gte_int() > it->second) {
-                        allMatched = false;
-                    }
-                    break;
-                }
-                case KeyValueMatcher::ValueMatcherCase::VALUE_MATCHER_NOT_SET:
-                    // If value matcher is not present, assume that we match.
-                    break;
             }
-        }
-
-        if (allMatched) {
-            return true;
+        } else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kEqInt ||
+                   matcherCase == KeyValueMatcher::ValueMatcherCase::kLtInt ||
+                   matcherCase == KeyValueMatcher::ValueMatcherCase::kGtInt ||
+                   matcherCase == KeyValueMatcher::ValueMatcherCase::kLteInt ||
+                   matcherCase == KeyValueMatcher::ValueMatcherCase::kGteInt) {
+            // Integer fields
+            status_t err = NO_ERROR;
+            int64_t val = event.GetLong(key, &err);
+            if (err == NO_ERROR) {
+                if (matcherCase == KeyValueMatcher::ValueMatcherCase::kEqInt) {
+                    if (!(val == cur.eq_int())) {
+                        allMatched = false;
+                    }
+                } else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kLtInt) {
+                    if (!(val < cur.lt_int())) {
+                        allMatched = false;
+                    }
+                } else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kGtInt) {
+                    if (!(val > cur.gt_int())) {
+                        allMatched = false;
+                    }
+                } else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kLteInt) {
+                    if (!(val <= cur.lte_int())) {
+                        allMatched = false;
+                    }
+                } else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kGteInt) {
+                    if (!(val >= cur.gte_int())) {
+                        allMatched = false;
+                    }
+                }
+            }
+            break;
+        } else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kEqBool) {
+            // Boolean fields
+            status_t err = NO_ERROR;
+            bool val = event.GetBool(key, &err);
+            if (err == NO_ERROR) {
+                if (!(cur.eq_bool() == val)) {
+                    allMatched = false;
+                }
+            }
+        } else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kLtFloat ||
+                   matcherCase == KeyValueMatcher::ValueMatcherCase::kGtFloat) {
+            // Float fields
+            status_t err = NO_ERROR;
+            bool val = event.GetFloat(key, &err);
+            if (err == NO_ERROR) {
+                if (matcherCase == KeyValueMatcher::ValueMatcherCase::kLtFloat) {
+                    if (!(cur.lt_float() <= val)) {
+                        allMatched = false;
+                    }
+                } else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kGtFloat) {
+                    if (!(cur.gt_float() >= val)) {
+                        allMatched = false;
+                    }
+                }
+            }
+        } else {
+            // If value matcher is not present, assume that we match.
         }
     }
-    return false;
+    return allMatched;
+}
+
+vector<KeyValuePair> getDimensionKey(const LogEvent& event,
+                                     const std::vector<KeyMatcher>& dimensions) {
+    vector<KeyValuePair> key;
+    key.reserve(dimensions.size());
+    for (const KeyMatcher& dimension : dimensions) {
+        KeyValuePair k = event.GetKeyValueProto(dimension.key());
+        key.push_back(k);
+    }
+    return key;
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/matchers/matcher_util.h b/cmds/statsd/src/matchers/matcher_util.h
index 6d8e762..4ea6f0b 100644
--- a/cmds/statsd/src/matchers/matcher_util.h
+++ b/cmds/statsd/src/matchers/matcher_util.h
@@ -17,39 +17,35 @@
 #ifndef MATCHER_UTIL_H
 #define MATCHER_UTIL_H
 
+#include "logd/LogEvent.h"
+
 #include <log/log_read.h>
 #include <log/logprint.h>
 #include <set>
+#include <string>
 #include <unordered_map>
 #include <vector>
 #include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "stats_util.h"
 
 namespace android {
 namespace os {
 namespace statsd {
 
-typedef struct {
-    int tagId;
-    long timestamp_ns;
-    std::unordered_map<int, long> intMap;
-    std::unordered_map<int, std::string> strMap;
-    std::unordered_map<int, bool> boolMap;
-    std::unordered_map<int, float> floatMap;
-} LogEventWrapper;
-
 enum MatchingState {
     kNotComputed = -1,
     kNotMatched = 0,
     kMatched = 1,
 };
 
-LogEventWrapper parseLogEvent(log_msg msg);
-
 bool combinationMatch(const std::vector<int>& children, const LogicalOperation& operation,
                       const std::vector<MatchingState>& matcherResults);
 
-bool matchesSimple(const SimpleLogEntryMatcher& simpleMatcher, const LogEventWrapper& wrapper);
+bool matchesSimple(const SimpleLogEntryMatcher& simpleMatcher, const LogEvent& wrapper);
+
+std::vector<KeyValuePair> getDimensionKey(const LogEvent& event,
+                                          const std::vector<KeyMatcher>& dimensions);
 
 }  // namespace statsd
 }  // namespace os
diff --git a/cmds/statsd/src/metrics/CountAnomalyTracker.cpp b/cmds/statsd/src/metrics/CountAnomalyTracker.cpp
index ebd53e0..e1c2b8b 100644
--- a/cmds/statsd/src/metrics/CountAnomalyTracker.cpp
+++ b/cmds/statsd/src/metrics/CountAnomalyTracker.cpp
@@ -14,15 +14,14 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "CountAnomaly"
 #define DEBUG true  // STOPSHIP if true
+#include "Log.h"
+
 #define VLOG(...) \
     if (DEBUG) ALOGD(__VA_ARGS__);
 
 #include "CountAnomalyTracker.h"
 
-#include <cutils/log.h>
-
 namespace android {
 namespace os {
 namespace statsd {
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index e98999e..1f07914 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -14,40 +14,52 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "CountMetric"
 #define DEBUG true  // STOPSHIP if true
-#define VLOG(...) \
-    if (DEBUG) ALOGD(__VA_ARGS__);
+#include "Log.h"
 
-#include "CountMetricProducer.h"
 #include "CountAnomalyTracker.h"
+#include "CountMetricProducer.h"
+#include "stats_util.h"
 
 #include <cutils/log.h>
 #include <limits.h>
 #include <stdlib.h>
 
+using std::map;
+using std::string;
 using std::unordered_map;
+using std::vector;
 
 namespace android {
 namespace os {
 namespace statsd {
 
-CountMetricProducer::CountMetricProducer(const CountMetric& metric, const bool hasCondition)
-    : mMetric(metric),
-      mStartTime(time(nullptr)),
-      mCounter(0),
-      mCurrentBucketStartTime(mStartTime),
+// TODO: add back AnomalyTracker.
+CountMetricProducer::CountMetricProducer(const CountMetric& metric, const int conditionIndex,
+                                         const sp<ConditionWizard>& wizard)
+    // TODO: Pass in the start time from MetricsManager, instead of calling time() here.
+    : MetricProducer((time(nullptr) * NANO_SECONDS_IN_A_SECOND), conditionIndex, wizard),
+      mMetric(metric),
       // TODO: read mAnomalyTracker parameters from config file.
-      mAnomalyTracker(6, 10),
-      mCondition(hasCondition ? ConditionState::kUnknown : ConditionState::kTrue) {
+      mAnomalyTracker(6, 10) {
     // TODO: evaluate initial conditions. and set mConditionMet.
     if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) {
-        mBucketSize_sec = metric.bucket().bucket_size_millis() / 1000;
+        mBucketSizeNs = metric.bucket().bucket_size_millis() * 1000 * 1000;
     } else {
-        mBucketSize_sec = LONG_MAX;
+        mBucketSizeNs = LLONG_MAX;
     }
 
-    VLOG("created. bucket size %lu start_time: %lu", mBucketSize_sec, mStartTime);
+    // TODO: use UidMap if uid->pkg_name is required
+    mDimension.insert(mDimension.begin(), metric.dimension().begin(), metric.dimension().end());
+
+    if (metric.links().size() > 0) {
+        mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
+                               metric.links().end());
+        mConditionSliced = true;
+    }
+
+    VLOG("metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(),
+         (long long)mBucketSizeNs, (long long)mStartTimeNs);
 }
 
 CountMetricProducer::~CountMetricProducer() {
@@ -59,54 +71,146 @@
     // DropboxWriter.
 }
 
-void CountMetricProducer::onDumpReport() {
-    VLOG("dump report now...");
+static void addSlicedCounterToReport(StatsLogReport_CountMetricDataWrapper& wrapper,
+                                     const vector<KeyValuePair>& key,
+                                     const vector<CountBucketInfo>& buckets) {
+    CountMetricData* data = wrapper.add_data();
+    for (const auto& kv : key) {
+        data->add_dimension()->CopyFrom(kv);
+    }
+    for (const auto& bucket : buckets) {
+        data->add_bucket_info()->CopyFrom(bucket);
+        VLOG("\t bucket [%lld - %lld] count: %lld", bucket.start_bucket_nanos(),
+             bucket.end_bucket_nanos(), bucket.count());
+    }
+}
+
+void CountMetricProducer::onSlicedConditionMayChange() {
+    VLOG("Metric %lld onSlicedConditionMayChange", mMetric.metric_id());
+}
+
+StatsLogReport CountMetricProducer::onDumpReport() {
+    VLOG("metric %lld dump report now...", mMetric.metric_id());
+
+    StatsLogReport report;
+    report.set_metric_id(mMetric.metric_id());
+    report.set_start_report_nanos(mStartTimeNs);
+
+    // Dump current bucket if it's stale.
+    // If current bucket is still on-going, don't force dump current bucket.
+    // In finish(), We can force dump current bucket.
+    flushCounterIfNeeded(time(nullptr) * NANO_SECONDS_IN_A_SECOND);
+    report.set_end_report_nanos(mCurrentBucketStartTimeNs);
+
+    StatsLogReport_CountMetricDataWrapper* wrapper = report.mutable_count_metrics();
+
+    for (const auto& pair : mPastBuckets) {
+        const HashableDimensionKey& hashableKey = pair.first;
+        auto it = mDimensionKeyMap.find(hashableKey);
+        if (it == mDimensionKeyMap.end()) {
+            ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str());
+            continue;
+        }
+
+        VLOG("  dimension key %s", hashableKey.c_str());
+        addSlicedCounterToReport(*wrapper, it->second, pair.second);
+    }
+    return report;
+    // TODO: Clear mPastBuckets, mDimensionKeyMap once the report is dumped.
 }
 
 void CountMetricProducer::onConditionChanged(const bool conditionMet) {
-    VLOG("onConditionChanged");
+    VLOG("Metric %lld onConditionChanged", mMetric.metric_id());
     mCondition = conditionMet;
 }
 
-void CountMetricProducer::onMatchedLogEvent(const LogEventWrapper& event) {
-    time_t eventTime = event.timestamp_ns / 1000000000;
-
+void CountMetricProducer::onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event) {
+    uint64_t eventTimeNs = event.GetTimestampNs();
     // this is old event, maybe statsd restarted?
-    if (eventTime < mStartTime) {
+    if (eventTimeNs < mStartTimeNs) {
         return;
     }
 
-    if (mCondition == ConditionState::kTrue) {
-        flushCounterIfNeeded(eventTime);
-        mCounter++;
-        mAnomalyTracker.checkAnomaly(mCounter);
-        VLOG("metric %lld count %d", mMetric.metric_id(), mCounter);
+    flushCounterIfNeeded(eventTimeNs);
+
+    if (mConditionSliced) {
+        map<string, HashableDimensionKey> conditionKeys;
+        for (const auto& link : mConditionLinks) {
+            VLOG("Condition link key_in_main size %d", link.key_in_main_size());
+            HashableDimensionKey conditionKey = getDimensionKeyForCondition(event, link);
+            conditionKeys[link.condition()] = conditionKey;
+        }
+        if (mWizard->query(mConditionTrackerIndex, conditionKeys) != ConditionState::kTrue) {
+            VLOG("metric %lld sliced condition not met", mMetric.metric_id());
+            return;
+        }
+    } else {
+        if (!mCondition) {
+            VLOG("metric %lld condition not met", mMetric.metric_id());
+            return;
+        }
     }
+
+    HashableDimensionKey hashableKey;
+
+    if (mDimension.size() > 0) {
+        vector<KeyValuePair> key = getDimensionKey(event, mDimension);
+        hashableKey = getHashableKey(key);
+        // Add the HashableDimensionKey->vector<KeyValuePair> to the map, because StatsLogReport
+        // expects vector<KeyValuePair>.
+        if (mDimensionKeyMap.find(hashableKey) == mDimensionKeyMap.end()) {
+            mDimensionKeyMap[hashableKey] = key;
+        }
+    } else {
+        hashableKey = DEFAULT_DIMENSION_KEY;
+    }
+
+    auto it = mCurrentSlicedCounter.find(hashableKey);
+
+    if (it == mCurrentSlicedCounter.end()) {
+        // create a counter for the new key
+        mCurrentSlicedCounter[hashableKey] = 1;
+
+    } else {
+        // increment the existing value
+        auto& count = it->second;
+        count++;
+    }
+
+    VLOG("metric %lld %s->%d", mMetric.metric_id(), hashableKey.c_str(),
+         mCurrentSlicedCounter[hashableKey]);
 }
 
-// When a new matched event comes in, we check if it falls into the current
-// bucket. And flush the counter to the StatsLogReport and adjust the bucket if
-// needed.
-void CountMetricProducer::flushCounterIfNeeded(const time_t& eventTime) {
-    if (mCurrentBucketStartTime + mBucketSize_sec > eventTime) {
+// When a new matched event comes in, we check if event falls into the current
+// bucket. If not, flush the old counter to past buckets and initialize the new bucket.
+void CountMetricProducer::flushCounterIfNeeded(const uint64_t eventTimeNs) {
+    if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTimeNs) {
         return;
     }
 
-    // TODO: add a KeyValuePair to StatsLogReport.
-    ALOGD("%lld:  dump counter %d", mMetric.metric_id(), mCounter);
-
     // adjust the bucket start time
-    time_t numBucketsForward = (eventTime - mCurrentBucketStartTime)
-            / mBucketSize_sec;
+    int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
 
-    mCurrentBucketStartTime = mCurrentBucketStartTime +
-            (numBucketsForward) * mBucketSize_sec;
+    CountBucketInfo info;
+    info.set_start_bucket_nanos(mCurrentBucketStartTimeNs);
+    info.set_end_bucket_nanos(mCurrentBucketStartTimeNs + mBucketSizeNs);
 
-    // reset counter
-    mAnomalyTracker.addPastBucket(mCounter, numBucketsForward);
-    mCounter = 0;
+    for (const auto& counter : mCurrentSlicedCounter) {
+        info.set_count(counter.second);
+        // it will auto create new vector of CountbucketInfo if the key is not found.
+        auto& bucketList = mPastBuckets[counter.first];
+        bucketList.push_back(info);
 
-    VLOG("%lld: new bucket start time: %lu", mMetric.metric_id(), mCurrentBucketStartTime);
+        VLOG("metric %lld, dump key value: %s -> %d", mMetric.metric_id(), counter.first.c_str(),
+             counter.second);
+    }
+
+    // Reset counters
+    mCurrentSlicedCounter.clear();
+
+    mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs;
+    VLOG("metric %lld: new bucket start time: %lld", mMetric.metric_id(),
+         (long long)mCurrentBucketStartTimeNs);
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 370cd468..f0d6025 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -19,12 +19,13 @@
 
 #include <unordered_map>
 
-#include "CountAnomalyTracker.h"
 #include "../condition/ConditionTracker.h"
 #include "../matchers/matcher_util.h"
+#include "CountAnomalyTracker.h"
 #include "MetricProducer.h"
 #include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "stats_util.h"
 
 using namespace std;
 
@@ -34,38 +35,37 @@
 
 class CountMetricProducer : public MetricProducer {
 public:
-    CountMetricProducer(const CountMetric& countMetric, const bool hasCondition);
+    // TODO: Pass in the start time from MetricsManager, it should be consistent for all metrics.
+    CountMetricProducer(const CountMetric& countMetric, const int conditionIndex,
+                        const sp<ConditionWizard>& wizard);
 
     virtual ~CountMetricProducer();
 
-    void onMatchedLogEvent(const LogEventWrapper& event) override;
+    void onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event) override;
 
     void onConditionChanged(const bool conditionMet) override;
 
     void finish() override;
 
-    void onDumpReport() override;
+    StatsLogReport onDumpReport() override;
+
+    void onSlicedConditionMayChange() override;
 
     // TODO: Implement this later.
-    virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override {};
+    virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
 
 private:
     const CountMetric mMetric;
 
-    const time_t mStartTime;
-    // TODO: Add dimensions.
-    // Counter value for the current bucket.
-    int mCounter;
-
-    time_t mCurrentBucketStartTime;
-
-    long mBucketSize_sec;
-
     CountAnomalyTracker mAnomalyTracker;
 
-    bool mCondition;
+    // Save the past buckets and we can clear when the StatsLogReport is dumped.
+    std::unordered_map<HashableDimensionKey, std::vector<CountBucketInfo>> mPastBuckets;
 
-    void flushCounterIfNeeded(const time_t& newEventTime);
+    // The current bucket.
+    std::unordered_map<HashableDimensionKey, int> mCurrentSlicedCounter;
+
+    void flushCounterIfNeeded(const uint64_t newEventTime);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
new file mode 100644
index 0000000..aa597f4
--- /dev/null
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define DEBUG true
+#include "DurationMetricProducer.h"
+#include "Log.h"
+#include "stats_util.h"
+
+#include <cutils/log.h>
+#include <limits.h>
+#include <stdlib.h>
+
+using std::string;
+using std::unordered_map;
+using std::vector;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+DurationMetricProducer::DurationMetricProducer(const DurationMetric& metric,
+                                               const int conditionIndex, const size_t startIndex,
+                                               const size_t stopIndex, const size_t stopAllIndex,
+                                               const sp<ConditionWizard>& wizard)
+    // TODO: Pass in the start time from MetricsManager, instead of calling time() here.
+    : MetricProducer(time(nullptr) * NANO_SECONDS_IN_A_SECOND, conditionIndex, wizard),
+      mMetric(metric),
+      mStartIndex(startIndex),
+      mStopIndex(stopIndex),
+      mStopAllIndex(stopAllIndex) {
+    // TODO: The following boiler plate code appears in all MetricProducers, but we can't abstract
+    // them in the base class, because the proto generated CountMetric, and DurationMetric are
+    // not related. Maybe we should add a template in the future??
+    if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) {
+        mBucketSizeNs = metric.bucket().bucket_size_millis() * 1000000;
+    } else {
+        mBucketSizeNs = LLONG_MAX;
+    }
+
+    // TODO: use UidMap if uid->pkg_name is required
+    mDimension.insert(mDimension.begin(), metric.dimension().begin(), metric.dimension().end());
+
+    if (metric.links().size() > 0) {
+        mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
+                               metric.links().end());
+        mConditionSliced = true;
+    }
+
+    VLOG("metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(),
+         (long long)mBucketSizeNs, (long long)mStartTimeNs);
+}
+
+DurationMetricProducer::~DurationMetricProducer() {
+    VLOG("~DurationMetric() called");
+}
+
+void DurationMetricProducer::finish() {
+    // TODO: write the StatsLogReport to dropbox using
+    // DropboxWriter.
+}
+
+void DurationMetricProducer::onSlicedConditionMayChange() {
+    VLOG("Metric %lld onSlicedConditionMayChange", mMetric.metric_id());
+    // Now for each of the on-going event, check if the condition has changed for them.
+    for (auto& pair : mCurrentSlicedDuration) {
+        VLOG("Metric %lld current %s state: %d", mMetric.metric_id(), pair.first.c_str(),
+             pair.second.state);
+        if (pair.second.state == kStopped) {
+            continue;
+        }
+        bool conditionMet = mWizard->query(mConditionTrackerIndex, pair.second.conditionKeys) ==
+                            ConditionState::kTrue;
+        VLOG("key: %s, condition: %d", pair.first.c_str(), conditionMet);
+        noteConditionChanged(pair.first, conditionMet, time(nullptr) * 1000000000);
+    }
+}
+
+void DurationMetricProducer::onConditionChanged(const bool conditionMet) {
+    VLOG("Metric %lld onConditionChanged", mMetric.metric_id());
+    mCondition = conditionMet;
+    // TODO: need to populate the condition change time from the event which triggers the condition
+    // change, instead of using current time.
+    for (auto& pair : mCurrentSlicedDuration) {
+        noteConditionChanged(pair.first, conditionMet, time(nullptr) * 1000000000);
+    }
+}
+
+static void addDurationBucketsToReport(StatsLogReport_DurationMetricDataWrapper& wrapper,
+                                       const vector<KeyValuePair>& key,
+                                       const vector<DurationBucketInfo>& buckets) {
+    DurationMetricData* data = wrapper.add_data();
+    for (const auto& kv : key) {
+        data->add_dimension()->CopyFrom(kv);
+    }
+    for (const auto& bucket : buckets) {
+        data->add_bucket_info()->CopyFrom(bucket);
+        VLOG("\t bucket [%lld - %lld] count: %lld", bucket.start_bucket_nanos(),
+             bucket.end_bucket_nanos(), bucket.duration_nanos());
+    }
+}
+
+StatsLogReport DurationMetricProducer::onDumpReport() {
+    VLOG("metric %lld dump report now...", mMetric.metric_id());
+    StatsLogReport report;
+    report.set_metric_id(mMetric.metric_id());
+    report.set_start_report_nanos(mStartTimeNs);
+    // Dump current bucket if it's stale.
+    // If current bucket is still on-going, don't force dump current bucket.
+    // In finish(), We can force dump current bucket.
+    flushDurationIfNeeded(time(nullptr) * NANO_SECONDS_IN_A_SECOND);
+    report.set_end_report_nanos(mCurrentBucketStartTimeNs);
+
+    StatsLogReport_DurationMetricDataWrapper* wrapper = report.mutable_duration_metrics();
+    for (const auto& pair : mPastBuckets) {
+        const HashableDimensionKey& hashableKey = pair.first;
+        auto it = mDimensionKeyMap.find(hashableKey);
+        if (it == mDimensionKeyMap.end()) {
+            ALOGW("Dimension key %s not found?!?! skip...", hashableKey.c_str());
+            continue;
+        }
+        VLOG("  dimension key %s", hashableKey.c_str());
+        addDurationBucketsToReport(*wrapper, it->second, pair.second);
+    }
+    return report;
+};
+
+void DurationMetricProducer::onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event) {
+    if (event.GetTimestampNs() < mStartTimeNs) {
+        return;
+    }
+
+    flushDurationIfNeeded(event.GetTimestampNs());
+
+    if (matcherIndex == mStopAllIndex) {
+        noteStopAll(event.GetTimestampNs());
+        return;
+    }
+
+    HashableDimensionKey hashableKey;
+    if (mDimension.size() > 0) {
+        // hook up sliced counter with AnomalyMonitor.
+        vector<KeyValuePair> key = getDimensionKey(event, mDimension);
+        hashableKey = getHashableKey(key);
+        // Add the HashableDimensionKey->DimensionKey to the map, because StatsLogReport expects
+        // vector<KeyValuePair>.
+        if (mDimensionKeyMap.find(hashableKey) == mDimensionKeyMap.end()) {
+            mDimensionKeyMap[hashableKey] = key;
+        }
+    } else {
+        hashableKey = DEFAULT_DIMENSION_KEY;
+    }
+
+    if (mCurrentSlicedDuration.find(hashableKey) == mCurrentSlicedDuration.end() &&
+        mConditionSliced) {
+        // add the durationInfo for the current bucket.
+        auto& durationInfo = mCurrentSlicedDuration[hashableKey];
+        auto& conditionKeys = durationInfo.conditionKeys;
+        // get and cache the keys for query condition.
+        for (const auto& link : mConditionLinks) {
+            HashableDimensionKey conditionKey = getDimensionKeyForCondition(event, link);
+            conditionKeys[link.condition()] = conditionKey;
+        }
+    }
+
+    bool conditionMet;
+    if (mConditionSliced) {
+        const auto& conditionKeys = mCurrentSlicedDuration[hashableKey].conditionKeys;
+        conditionMet =
+                mWizard->query(mConditionTrackerIndex, conditionKeys) == ConditionState::kTrue;
+    } else {
+        conditionMet = mCondition;
+    }
+
+    if (matcherIndex == mStartIndex) {
+        VLOG("Metric %lld Key: %s Start, Condition %d", mMetric.metric_id(), hashableKey.c_str(),
+             conditionMet);
+        noteStart(hashableKey, conditionMet, event.GetTimestampNs());
+    } else if (matcherIndex == mStopIndex) {
+        VLOG("Metric %lld Key: %s Stop, Condition %d", mMetric.metric_id(), hashableKey.c_str(),
+             conditionMet);
+        noteStop(hashableKey, event.GetTimestampNs());
+    }
+}
+
+void DurationMetricProducer::noteConditionChanged(const HashableDimensionKey& key,
+                                                  const bool conditionMet,
+                                                  const uint64_t eventTime) {
+    flushDurationIfNeeded(eventTime);
+
+    auto it = mCurrentSlicedDuration.find(key);
+    if (it == mCurrentSlicedDuration.end()) {
+        return;
+    }
+
+    switch (it->second.state) {
+        case kStarted:
+            // if condition becomes false, kStarted -> kPaused. Record the current duration.
+            if (!conditionMet) {
+                it->second.state = DurationState::kPaused;
+                it->second.lastDuration =
+                        updateDuration(it->second.lastDuration,
+                                       eventTime - it->second.lastStartTime, mMetric.type());
+                VLOG("Metric %lld Key: %s Paused because condition is false ", mMetric.metric_id(),
+                     key.c_str());
+            }
+            break;
+        case kStopped:
+            // nothing to do if it's stopped.
+            break;
+        case kPaused:
+            // if condition becomes true, kPaused -> kStarted. and the start time is the condition
+            // change time.
+            if (conditionMet) {
+                it->second.state = DurationState::kStarted;
+                it->second.lastStartTime = eventTime;
+                VLOG("Metric %lld Key: %s Paused->Started", mMetric.metric_id(), key.c_str());
+            }
+            break;
+    }
+}
+
+void DurationMetricProducer::noteStart(const HashableDimensionKey& key, const bool conditionMet,
+                                       const uint64_t eventTime) {
+    // this will add an empty bucket for this key if it didn't exist before.
+    DurationInfo& duration = mCurrentSlicedDuration[key];
+
+    switch (duration.state) {
+        case kStarted:
+            // It's safe to do nothing here. even if condition is not true, it means we are about
+            // to receive the condition change event.
+            break;
+        case kPaused:
+            // Safe to do nothing here. kPaused is waiting for the condition change.
+            break;
+        case kStopped:
+            if (!conditionMet) {
+                // event started, but we need to wait for the condition to become true.
+                duration.state = DurationState::kPaused;
+                break;
+            }
+            duration.state = DurationState::kStarted;
+            duration.lastStartTime = eventTime;
+            break;
+    }
+}
+
+void DurationMetricProducer::noteStop(const HashableDimensionKey& key, const uint64_t eventTime) {
+    if (mCurrentSlicedDuration.find(key) == mCurrentSlicedDuration.end()) {
+        // we didn't see a start event before. do nothing.
+        return;
+    }
+    DurationInfo& duration = mCurrentSlicedDuration[key];
+
+    switch (duration.state) {
+        case DurationState::kStopped:
+            // already stopped, do nothing.
+            break;
+        case DurationState::kStarted: {
+            duration.state = DurationState::kStopped;
+            int64_t durationTime = eventTime - duration.lastStartTime;
+            VLOG("Metric %lld, key %s, Stop %lld %lld %lld", mMetric.metric_id(), key.c_str(),
+                 (long long)duration.lastStartTime, (long long)eventTime, (long long)durationTime);
+            duration.lastDuration =
+                    updateDuration(duration.lastDuration, durationTime, mMetric.type());
+            VLOG("  record duration: %lld ", (long long)duration.lastDuration);
+            break;
+        }
+        case DurationState::kPaused: {
+            duration.state = DurationState::kStopped;
+            break;
+        }
+    }
+}
+
+int64_t DurationMetricProducer::updateDuration(const int64_t lastDuration,
+                                               const int64_t durationTime,
+                                               const DurationMetric_AggregationType type) {
+    int64_t result = lastDuration;
+    switch (type) {
+        case DurationMetric_AggregationType_DURATION_SUM:
+            result += durationTime;
+            break;
+        case DurationMetric_AggregationType_DURATION_MAX_SPARSE:
+            if (lastDuration < durationTime) {
+                result = durationTime;
+            }
+            break;
+        case DurationMetric_AggregationType_DURATION_MIN_SPARSE:
+            if (lastDuration > durationTime) {
+                result = durationTime;
+            }
+            break;
+    }
+    return result;
+}
+
+void DurationMetricProducer::noteStopAll(const uint64_t eventTime) {
+    for (auto& duration : mCurrentSlicedDuration) {
+        noteStop(duration.first, eventTime);
+    }
+}
+
+// When a new matched event comes in, we check if event falls into the current
+// bucket. If not, flush the old counter to past buckets and initialize the current buckt.
+void DurationMetricProducer::flushDurationIfNeeded(const uint64_t eventTime) {
+    if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTime) {
+        return;
+    }
+
+    // adjust the bucket start time
+    int numBucketsForward = (eventTime - mCurrentBucketStartTimeNs) / mBucketSizeNs;
+
+    DurationBucketInfo info;
+    uint64_t endTime = mCurrentBucketStartTimeNs + mBucketSizeNs;
+    info.set_start_bucket_nanos(mCurrentBucketStartTimeNs);
+    info.set_end_bucket_nanos(endTime);
+
+    uint64_t oldBucketStartTimeNs = mCurrentBucketStartTimeNs;
+    mCurrentBucketStartTimeNs += (numBucketsForward)*mBucketSizeNs;
+    VLOG("Metric %lld: new bucket start time: %lld", mMetric.metric_id(),
+         (long long)mCurrentBucketStartTimeNs);
+
+    for (auto it = mCurrentSlicedDuration.begin(); it != mCurrentSlicedDuration.end(); ++it) {
+        int64_t finalDuration = it->second.lastDuration;
+        if (it->second.state == kStarted) {
+            // the event is still on-going, duration needs to be updated.
+            int64_t durationTime = endTime - it->second.lastStartTime;
+            finalDuration = updateDuration(it->second.lastDuration, durationTime, mMetric.type());
+        }
+
+        VLOG("  final duration for last bucket: %lld", (long long)finalDuration);
+
+        // Don't record empty bucket.
+        if (finalDuration != 0) {
+            info.set_duration_nanos(finalDuration);
+            // it will auto create new vector of CountbucketInfo if the key is not found.
+            auto& bucketList = mPastBuckets[it->first];
+            bucketList.push_back(info);
+        }
+
+        // if the event is still on-going, add the buckets between previous bucket and now. Because
+        // the event has been going on across all the buckets in between.
+        // |prev_bucket|...|..|...|now_bucket|
+        if (it->second.state == kStarted) {
+            for (int i = 1; i < numBucketsForward; i++) {
+                DurationBucketInfo info;
+                info.set_start_bucket_nanos(oldBucketStartTimeNs + mBucketSizeNs * i);
+                info.set_end_bucket_nanos(endTime + mBucketSizeNs * i);
+                info.set_duration_nanos(mBucketSizeNs);
+                auto& bucketList = mPastBuckets[it->first];
+                bucketList.push_back(info);
+                VLOG("  add filling bucket with duration %lld", (long long)mBucketSizeNs);
+            }
+        }
+
+        if (it->second.state == DurationState::kStopped) {
+            // No need to keep buckets for events that were stopped before. If the event starts
+            // again, we will add it back.
+            mCurrentSlicedDuration.erase(it);
+        } else {
+            // for kPaused, and kStarted event, we will keep the buckets, and reset the start time
+            // and duration.
+            it->second.lastStartTime = mCurrentBucketStartTimeNs;
+            it->second.lastDuration = 0;
+        }
+    }
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
new file mode 100644
index 0000000..44c3254
--- /dev/null
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DURATION_METRIC_PRODUCER_H
+#define DURATION_METRIC_PRODUCER_H
+
+#include <unordered_map>
+
+#include "../condition/ConditionTracker.h"
+#include "../matchers/matcher_util.h"
+#include "MetricProducer.h"
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "stats_util.h"
+
+using namespace std;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+enum DurationState {
+    kStopped = 0,  // The event is stopped.
+    kStarted = 1,  // The event is on going.
+    kPaused = 2,   // The event is started, but condition is false, clock is paused. When condition
+                   // turns to true, kPaused will become kStarted.
+};
+
+// Hold duration information for current on-going bucket.
+struct DurationInfo {
+    DurationState state;
+    // most recent start time.
+    int64_t lastStartTime;
+    // existing duration in current bucket. Eventually, the duration will be aggregated in
+    // the way specified in AggregateType (Sum, Max, or Min).
+    int64_t lastDuration;
+    // cache the HashableDimensionKeys we need to query the condition for this duration event.
+    std::map<string, HashableDimensionKey> conditionKeys;
+
+    DurationInfo() : state(kStopped), lastStartTime(0), lastDuration(0){};
+};
+
+class DurationMetricProducer : public MetricProducer {
+public:
+    DurationMetricProducer(const DurationMetric& durationMetric, const int conditionIndex,
+                           const size_t startIndex, const size_t stopIndex,
+                           const size_t stopAllIndex, const sp<ConditionWizard>& wizard);
+
+    virtual ~DurationMetricProducer();
+
+    void onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event) override;
+
+    void onConditionChanged(const bool conditionMet) override;
+
+    void finish() override;
+
+    StatsLogReport onDumpReport() override;
+
+    void onSlicedConditionMayChange() override;
+
+    // TODO: Implement this later.
+    virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
+
+private:
+    const DurationMetric mMetric;
+
+    // Index of the SimpleLogEntryMatcher which defines the start.
+    const size_t mStartIndex;
+
+    // Index of the SimpleLogEntryMatcher which defines the stop.
+    const size_t mStopIndex;
+
+    // Index of the SimpleLogEntryMatcher which defines the stop all for all dimensions.
+    const size_t mStopAllIndex;
+
+    // Save the past buckets and we can clear when the StatsLogReport is dumped.
+    std::unordered_map<HashableDimensionKey, std::vector<DurationBucketInfo>> mPastBuckets;
+
+    // The current bucket.
+    std::unordered_map<HashableDimensionKey, DurationInfo> mCurrentSlicedDuration;
+
+    void flushDurationIfNeeded(const uint64_t newEventTime);
+
+    void noteStart(const HashableDimensionKey& key, const bool conditionMet,
+                   const uint64_t eventTime);
+
+    void noteStop(const HashableDimensionKey& key, const uint64_t eventTime);
+
+    void noteStopAll(const uint64_t eventTime);
+
+    static int64_t updateDuration(const int64_t lastDuration, const int64_t durationTime,
+                                  const DurationMetric_AggregationType type);
+
+    void noteConditionChanged(const HashableDimensionKey& key, const bool conditionMet,
+                              const uint64_t eventTime);
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+
+#endif  // DURATION_METRIC_PRODUCER_H
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index b7e9656..afaab648 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -17,10 +17,13 @@
 #ifndef METRIC_PRODUCER_H
 #define METRIC_PRODUCER_H
 
+#include "condition/ConditionWizard.h"
+#include "matchers/matcher_util.h"
+#include "packages/PackageInfoListener.h"
+
 #include <log/logprint.h>
 #include <utils/RefBase.h>
-#include "../matchers/matcher_util.h"
-#include "PackageInfoListener.h"
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 
 namespace android {
 namespace os {
@@ -30,20 +33,59 @@
 // writing the report to dropbox. MetricProducers should respond to package changes as required in
 // PackageInfoListener, but if none of the metrics are slicing by package name, then the update can
 // be a no-op.
-class MetricProducer : public virtual RefBase, public virtual PackageInfoListener {
+class MetricProducer : public virtual PackageInfoListener {
 public:
+    MetricProducer(const int64_t startTimeNs, const int conditionIndex,
+                   const sp<ConditionWizard>& wizard)
+        : mStartTimeNs(startTimeNs),
+          mCurrentBucketStartTimeNs(startTimeNs),
+          mCondition(conditionIndex >= 0 ? false : true),
+          mWizard(wizard),
+          mConditionTrackerIndex(conditionIndex) {
+        // reuse the same map for non-sliced metrics too. this way, we avoid too many if-else.
+        mDimensionKeyMap[DEFAULT_DIMENSION_KEY] = std::vector<KeyValuePair>();
+    };
     virtual ~MetricProducer(){};
 
     // Consume the parsed stats log entry that already matched the "what" of the metric.
-    virtual void onMatchedLogEvent(const LogEventWrapper& event) = 0;
+    virtual void onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event) = 0;
 
     virtual void onConditionChanged(const bool condition) = 0;
 
+    virtual void onSlicedConditionMayChange() = 0;
+
     // This is called when the metric collecting is done, e.g., when there is a new configuration
     // coming. MetricProducer should do the clean up, and dump existing data to dropbox.
     virtual void finish() = 0;
 
-    virtual void onDumpReport() = 0;
+    virtual StatsLogReport onDumpReport() = 0;
+
+    virtual bool isConditionSliced() const {
+        return mConditionSliced;
+    };
+
+protected:
+    const uint64_t mStartTimeNs;
+
+    uint64_t mCurrentBucketStartTimeNs;
+
+    int64_t mBucketSizeNs;
+
+    bool mCondition;
+
+    bool mConditionSliced;
+
+    sp<ConditionWizard> mWizard;
+
+    int mConditionTrackerIndex;
+
+    std::vector<KeyMatcher> mDimension;  // The dimension defined in statsd_config
+
+    // Keep the map from the internal HashableDimensionKey to std::vector<KeyValuePair>
+    // that StatsLogReport wants.
+    std::unordered_map<HashableDimensionKey, std::vector<KeyValuePair>> mDimensionKeyMap;
+
+    std::vector<EventConditionLink> mConditionLinks;
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 1e65f58..c19d462 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -13,13 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_TAG "MetricManager"
 #define DEBUG true  // STOPSHIP if true
-#define VLOG(...) \
-    if (DEBUG) ALOGD(__VA_ARGS__);
+#include "Log.h"
 
 #include "MetricsManager.h"
-#include <cutils/log.h>
 #include <log/logprint.h>
 #include "../condition/CombinationConditionTracker.h"
 #include "../condition/SimpleConditionTracker.h"
@@ -59,20 +56,31 @@
     }
 }
 
+vector<StatsLogReport> MetricsManager::onDumpReport() {
+    VLOG("=========================Metric Reports Start==========================");
+    // one StatsLogReport per MetricProduer
+    vector<StatsLogReport> reportList;
+    for (auto& metric : mAllMetricProducers) {
+        reportList.push_back(metric->onDumpReport());
+    }
+    VLOG("=========================Metric Reports End==========================");
+    return reportList;
+}
+
 // Consume the stats log if it's interesting to this metric.
-void MetricsManager::onLogEvent(const log_msg& logMsg) {
+void MetricsManager::onLogEvent(const LogEvent& event) {
     if (!mConfigValid) {
         return;
     }
 
-    int tagId = getTagId(logMsg);
+    int tagId = event.GetTagId();
     if (mTagIds.find(tagId) == mTagIds.end()) {
         // not interesting...
         return;
     }
 
     // Since at least one of the metrics is interested in this event, we parse it now.
-    LogEventWrapper event = parseLogEvent(logMsg);
+    ALOGD("%s", event.ToString().c_str());
     vector<MatchingState> matcherCache(mAllLogEntryMatchers.size(), MatchingState::kNotComputed);
 
     for (auto& matcher : mAllLogEntryMatchers) {
@@ -95,20 +103,34 @@
                                           ConditionState::kNotEvaluated);
     // A bitmap to track if a condition has changed value.
     vector<bool> changedCache(mAllConditionTrackers.size(), false);
+    vector<bool> slicedChangedCache(mAllConditionTrackers.size(), false);
     for (size_t i = 0; i < mAllConditionTrackers.size(); i++) {
         if (conditionToBeEvaluated[i] == false) {
             continue;
         }
-
         sp<ConditionTracker>& condition = mAllConditionTrackers[i];
         condition->evaluateCondition(event, matcherCache, mAllConditionTrackers, conditionCache,
-                                     changedCache);
-        if (changedCache[i]) {
-            auto pair = mConditionToMetricMap.find(i);
-            if (pair != mConditionToMetricMap.end()) {
-                auto& metricList = pair->second;
-                for (auto metricIndex : metricList) {
+                                     changedCache, slicedChangedCache);
+    }
+
+    for (size_t i = 0; i < mAllConditionTrackers.size(); i++) {
+        if (changedCache[i] == false && slicedChangedCache[i] == false) {
+            continue;
+        }
+        auto pair = mConditionToMetricMap.find(i);
+        if (pair != mConditionToMetricMap.end()) {
+            auto& metricList = pair->second;
+            for (auto metricIndex : metricList) {
+                // metric cares about non sliced condition, and it's changed.
+                // Push the new condition to it directly.
+                if (!mAllMetricProducers[metricIndex]->isConditionSliced() && changedCache[i]) {
                     mAllMetricProducers[metricIndex]->onConditionChanged(conditionCache[i]);
+                    // metric cares about sliced conditions, and it may have changed. Send
+                    // notification, and the metric can query the sliced conditions that are
+                    // interesting to it.
+                } else if (mAllMetricProducers[metricIndex]->isConditionSliced() &&
+                           slicedChangedCache[i]) {
+                    mAllMetricProducers[metricIndex]->onSlicedConditionMayChange();
                 }
             }
         }
@@ -121,7 +143,7 @@
             if (pair != mTrackerToMetricMap.end()) {
                 auto& metricList = pair->second;
                 for (const int metricIndex : metricList) {
-                    mAllMetricProducers[metricIndex]->onMatchedLogEvent(event);
+                    mAllMetricProducers[metricIndex]->onMatchedLogEvent(i, event);
                 }
             }
         }
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 70c34db6..56f57d3 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -14,16 +14,15 @@
  * limitations under the License.
  */
 
-#ifndef METRICS_MANAGER_H
-#define METRICS_MANAGER_H
+#pragma once
 
-#include <cutils/log.h>
-#include <log/logprint.h>
-#include <unordered_map>
-#include "../condition/ConditionTracker.h"
-#include "../matchers/LogMatchingTracker.h"
-#include "MetricProducer.h"
+#include "condition/ConditionTracker.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "logd/LogEvent.h"
+#include "matchers/LogMatchingTracker.h"
+#include "metrics/MetricProducer.h"
+
+#include <unordered_map>
 
 namespace android {
 namespace os {
@@ -39,22 +38,24 @@
     // Return whether the configuration is valid.
     bool isConfigValid() const;
 
-    void onLogEvent(const log_msg& logMsg);
+    void onLogEvent(const LogEvent& event);
 
     // Called when everything should wrap up. We are about to finish (e.g., new config comes).
     void finish();
 
+    // Config source owner can call onDumpReport() to get all the metrics collected.
+    std::vector<StatsLogReport> onDumpReport();
+
 private:
     // All event tags that are interesting to my metrics.
     std::set<int> mTagIds;
 
     // We only store the sp of LogMatchingTracker, MetricProducer, and ConditionTracker in
     // MetricManager. There are relationship between them, and the relationship are denoted by index
-    // instead of poiters. The reasons for this are: (1) the relationship between them are
+    // instead of pointers. The reasons for this are: (1) the relationship between them are
     // complicated, store index instead of pointers reduce the risk of A holds B's sp, and B holds
     // A's sp. (2) When we evaluate matcher results, or condition results, we can quickly get the
     // related results from a cache using the index.
-    // TODO: using unique_ptr may be more appriopreate?
 
     // Hold all the log entry matchers from the config.
     std::vector<sp<LogMatchingTracker>> mAllLogEntryMatchers;
@@ -94,4 +95,3 @@
 }  // namespace os
 }  // namespace android
 
-#endif  // METRICS_MANAGER_H
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 6fdd228..23071aa 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -19,6 +19,7 @@
 #include "../matchers/CombinationLogMatchingTracker.h"
 #include "../matchers/SimpleLogMatchingTracker.h"
 #include "CountMetricProducer.h"
+#include "DurationMetricProducer.h"
 #include "stats_util.h"
 
 using std::set;
@@ -30,11 +31,23 @@
 namespace os {
 namespace statsd {
 
+int getTrackerIndex(const string& name, const unordered_map<string, int>& logTrackerMap) {
+    auto logTrackerIt = logTrackerMap.find(name);
+    if (logTrackerIt == logTrackerMap.end()) {
+        ALOGW("cannot find the LogEventMatcher %s in config", name.c_str());
+        return MATCHER_NOT_FOUND;
+    }
+    return logTrackerIt->second;
+}
+
 bool initLogTrackers(const StatsdConfig& config, unordered_map<string, int>& logTrackerMap,
                      vector<sp<LogMatchingTracker>>& allLogEntryMatchers, set<int>& allTagIds) {
     vector<LogEntryMatcher> matcherConfigs;
+    const int logEntryMatcherCount = config.log_entry_matcher_size();
+    matcherConfigs.reserve(logEntryMatcherCount);
+    allLogEntryMatchers.reserve(logEntryMatcherCount);
 
-    for (int i = 0; i < config.log_entry_matcher_size(); i++) {
+    for (int i = 0; i < logEntryMatcherCount; i++) {
         const LogEntryMatcher& logMatcher = config.log_entry_matcher(i);
 
         int index = allLogEntryMatchers.size();
@@ -77,8 +90,11 @@
                     vector<sp<ConditionTracker>>& allConditionTrackers,
                     unordered_map<int, std::vector<int>>& trackerToConditionMap) {
     vector<Condition> conditionConfigs;
+    const int conditionTrackerCount = config.condition_size();
+    conditionConfigs.reserve(conditionTrackerCount);
+    allConditionTrackers.reserve(conditionTrackerCount);
 
-    for (int i = 0; i < config.condition_size(); i++) {
+    for (int i = 0; i < conditionTrackerCount; i++) {
         const Condition& condition = config.condition(i);
         int index = allConditionTrackers.size();
         switch (condition.contents_case()) {
@@ -121,9 +137,14 @@
 
 bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& logTrackerMap,
                  const unordered_map<string, int>& conditionTrackerMap,
+                 vector<sp<ConditionTracker>>& allConditionTrackers,
                  vector<sp<MetricProducer>>& allMetricProducers,
                  unordered_map<int, std::vector<int>>& conditionToMetricMap,
                  unordered_map<int, std::vector<int>>& trackerToMetricMap) {
+    sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers);
+    const int allMetricsCount = config.count_metric_size() + config.duration_metric_size();
+    allMetricProducers.reserve(allMetricsCount);
+
     // Build MetricProducers for each metric defined in config.
     // (1) build CountMetricProducer
     for (int i = 0; i < config.count_metric_size(); i++) {
@@ -133,36 +154,109 @@
             return false;
         }
 
+        int metricIndex = allMetricProducers.size();
+
         auto logTrackerIt = logTrackerMap.find(metric.what());
         if (logTrackerIt == logTrackerMap.end()) {
             ALOGW("cannot find the LogEntryMatcher %s in config", metric.what().c_str());
             return false;
         }
+        int logTrackerIndex = logTrackerIt->second;
+        auto& metric_list = trackerToMetricMap[logTrackerIndex];
+        metric_list.push_back(metricIndex);
 
         sp<MetricProducer> countProducer;
-        int metricIndex = allMetricProducers.size();
+
         if (metric.has_condition()) {
             auto condition_it = conditionTrackerMap.find(metric.condition());
             if (condition_it == conditionTrackerMap.end()) {
                 ALOGW("cannot find the Condition %s in the config", metric.condition().c_str());
                 return false;
             }
-            countProducer = new CountMetricProducer(metric, true /*has condition*/);
+
+            for (const auto& link : metric.links()) {
+                auto it = conditionTrackerMap.find(link.condition());
+                if (it == conditionTrackerMap.end()) {
+                    ALOGW("cannot find the Condition %s in the config", link.condition().c_str());
+                    return false;
+                }
+                allConditionTrackers[condition_it->second]->setSliced(true);
+                allConditionTrackers[it->second]->setSliced(true);
+                allConditionTrackers[it->second]->addDimensions(vector<KeyMatcher>(
+                        link.key_in_condition().begin(), link.key_in_condition().end()));
+            }
+
+            countProducer = new CountMetricProducer(metric, condition_it->second, wizard);
             // will create new vector if not exist before.
             auto& metricList = conditionToMetricMap[condition_it->second];
             metricList.push_back(metricIndex);
         } else {
-            countProducer = new CountMetricProducer(metric, false /*no condition*/);
+            countProducer = new CountMetricProducer(metric, -1 /*no condition*/, wizard);
         }
-
-        int logTrackerIndex = logTrackerIt->second;
-        auto& metric_list = trackerToMetricMap[logTrackerIndex];
-        metric_list.push_back(metricIndex);
         allMetricProducers.push_back(countProducer);
     }
 
-    // TODO: build other types of metrics too.
+    for (int i = 0; i < config.duration_metric_size(); i++) {
+        int metricIndex = allMetricProducers.size();
+        const DurationMetric metric = config.duration_metric(i);
+        if (!metric.has_start()) {
+            ALOGW("cannot find start in DurationMetric %lld", metric.metric_id());
+            return false;
+        }
 
+        int trackerIndices[] = {-1, -1, -1};
+        trackerIndices[0] = getTrackerIndex(metric.start(), logTrackerMap);
+
+        if (metric.has_stop()) {
+            trackerIndices[1] = getTrackerIndex(metric.stop(), logTrackerMap);
+        }
+
+        if (metric.has_stop_all()) {
+            trackerIndices[2] = getTrackerIndex(metric.stop_all(), logTrackerMap);
+        }
+
+        for (const int& index : trackerIndices) {
+            if (index == MATCHER_NOT_FOUND) {
+                return false;
+            }
+            if (index >= 0) {
+                auto& metric_list = trackerToMetricMap[index];
+                metric_list.push_back(metricIndex);
+            }
+        }
+
+        int conditionIndex = -1;
+
+        if (metric.has_predicate()) {
+            auto condition_it = conditionTrackerMap.find(metric.predicate());
+            if (condition_it == conditionTrackerMap.end()) {
+                ALOGW("cannot find the Condition %s in the config", metric.predicate().c_str());
+                return false;
+            }
+            conditionIndex = condition_it->second;
+
+            for (const auto& link : metric.links()) {
+                auto it = conditionTrackerMap.find(link.condition());
+                if (it == conditionTrackerMap.end()) {
+                    ALOGW("cannot find the Condition %s in the config", link.condition().c_str());
+                    return false;
+                }
+                allConditionTrackers[condition_it->second]->setSliced(true);
+                allConditionTrackers[it->second]->setSliced(true);
+                allConditionTrackers[it->second]->addDimensions(vector<KeyMatcher>(
+                        link.key_in_condition().begin(), link.key_in_condition().end()));
+            }
+
+            auto& metricList = conditionToMetricMap[conditionIndex];
+            metricList.push_back(metricIndex);
+        }
+
+        sp<MetricProducer> durationMetric =
+                new DurationMetricProducer(metric, conditionIndex, trackerIndices[0],
+                                           trackerIndices[1], trackerIndices[2], wizard);
+
+        allMetricProducers.push_back(durationMetric);
+    }
     return true;
 }
 
@@ -187,8 +281,8 @@
         return false;
     }
 
-    if (!initMetrics(config, logTrackerMap, conditionTrackerMap, allMetricProducers,
-                     conditionToMetricMap, trackerToMetricMap)) {
+    if (!initMetrics(config, logTrackerMap, conditionTrackerMap, allConditionTrackers,
+                     allMetricProducers, conditionToMetricMap, trackerToMetricMap)) {
         ALOGE("initMetricProducers failed");
         return false;
     }
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index 5f1f295..38149a6 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -59,7 +59,8 @@
                     const std::unordered_map<std::string, int>& logTrackerMap,
                     std::unordered_map<std::string, int>& conditionTrackerMap,
                     std::vector<sp<ConditionTracker>>& allConditionTrackers,
-                    std::unordered_map<int, std::vector<int>>& trackerToConditionMap);
+                    std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
+                    std::unordered_map<int, std::vector<EventConditionLink>>& eventConditionLinks);
 
 // Initialize MetricProducers.
 // input:
@@ -71,12 +72,14 @@
 // [conditionToMetricMap]: contains the mapping from condition tracker index to
 //                          the list of MetricProducer index
 // [trackerToMetricMap]: contains the mapping from log tracker to MetricProducer index.
-bool initMetrics(const StatsdConfig& config,
-                 const std::unordered_map<std::string, int>& logTrackerMap,
-                 const std::unordered_map<std::string, int>& conditionTrackerMap,
-                 std::vector<sp<MetricProducer>>& allMetricProducers,
-                 std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
-                 std::unordered_map<int, std::vector<int>>& trackerToMetricMap);
+bool initMetrics(
+        const StatsdConfig& config, const std::unordered_map<std::string, int>& logTrackerMap,
+        const std::unordered_map<std::string, int>& conditionTrackerMap,
+        const std::unordered_map<int, std::vector<EventConditionLink>>& eventConditionLinks,
+        vector<sp<ConditionTracker>>& allConditionTrackers,
+        std::vector<sp<MetricProducer>>& allMetricProducers,
+        std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
+        std::unordered_map<int, std::vector<int>>& trackerToMetricMap);
 
 // Initialize MetricManager from StatsdConfig.
 // Parameters are the members of MetricsManager. See MetricsManager for declaration.
@@ -88,6 +91,8 @@
                       std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
                       std::unordered_map<int, std::vector<int>>& trackerToConditionMap);
 
+int getTrackerIndex(const std::string& name, const std::unordered_map<string, int>& logTrackerMap);
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/packages/PackageInfoListener.h b/cmds/statsd/src/packages/PackageInfoListener.h
new file mode 100644
index 0000000..8b948de
--- /dev/null
+++ b/cmds/statsd/src/packages/PackageInfoListener.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STATSD_PACKAGE_INFO_LISTENER_H
+#define STATSD_PACKAGE_INFO_LISTENER_H
+
+#include <utils/RefBase.h>
+#include <string>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class PackageInfoListener : public virtual android::RefBase {
+public:
+    // Uid map will notify this listener that the app with apk name and uid has been upgraded to
+    // the specified version.
+    virtual void notifyAppUpgrade(const std::string& apk, const int uid, const int version) = 0;
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+
+#endif  // STATSD_PACKAGE_INFO_LISTENER_H
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
new file mode 100644
index 0000000..f4621ee
--- /dev/null
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, versionCode 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Log.h"
+
+#include "packages/UidMap.h"
+
+#include <utils/Errors.h>
+
+using namespace android;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+bool UidMap::hasApp(int uid, const string& packageName) const {
+    lock_guard<mutex> lock(mMutex);
+
+    auto range = mMap.equal_range(uid);
+    for (auto it = range.first; it != range.second; ++it) {
+        if (it->second.packageName == packageName) {
+            return true;
+        }
+    }
+    return false;
+}
+
+int UidMap::getAppVersion(int uid, const string& packageName) const {
+    lock_guard<mutex> lock(mMutex);
+
+    auto range = mMap.equal_range(uid);
+    for (auto it = range.first; it != range.second; ++it) {
+        if (it->second.packageName == packageName) {
+            return it->second.versionCode;
+        }
+    }
+    return 0;
+}
+
+void UidMap::updateMap(const vector<int32_t>& uid, const vector<int32_t>& versionCode,
+                       const vector<String16>& packageName) {
+    lock_guard<mutex> lock(mMutex);  // Exclusively lock for updates.
+
+    mMap.clear();
+    for (unsigned long j = 0; j < uid.size(); j++) {
+        mMap.insert(make_pair(uid[j],
+                              AppData(string(String8(packageName[j]).string()), versionCode[j])));
+    }
+
+    if (mOutput.initial_size() == 0) {  // Provide the initial states in the mOutput proto
+        for (unsigned long j = 0; j < uid.size(); j++) {
+            auto t = mOutput.add_initial();
+            t->set_app(string(String8(packageName[j]).string()));
+            t->set_version(int(versionCode[j]));
+            t->set_uid(uid[j]);
+        }
+    }
+}
+
+void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int32_t& versionCode) {
+    lock_guard<mutex> lock(mMutex);
+
+    string app = string(String8(app_16).string());
+
+    // Notify any interested producers that this app has updated
+    for (auto it : mSubscribers) {
+        it->notifyAppUpgrade(app, uid, versionCode);
+    }
+
+    auto log = mOutput.add_changes();
+    log->set_deletion(false);
+    // log.timestamp = TODO: choose how timestamps are computed
+    log->set_app(app);
+    log->set_uid(uid);
+    log->set_version(versionCode);
+
+    auto range = mMap.equal_range(int(uid));
+    for (auto it = range.first; it != range.second; ++it) {
+        if (it->second.packageName == app) {
+            it->second.versionCode = int(versionCode);
+            return;
+        }
+        ALOGD("updateApp failed to find the app %s with uid %i to update", app.c_str(), uid);
+        return;
+    }
+
+    // Otherwise, we need to add an app at this uid.
+    mMap.insert(make_pair(uid, AppData(app, int(versionCode))));
+}
+
+void UidMap::removeApp(const String16& app_16, const int32_t& uid) {
+    lock_guard<mutex> lock(mMutex);
+
+    string app = string(String8(app_16).string());
+
+    auto log = mOutput.add_changes();
+    log->set_deletion(true);
+    // log.timestamp = TODO: choose how timestamps are computed
+    log->set_app(app);
+    log->set_uid(uid);
+
+    auto range = mMap.equal_range(int(uid));
+    for (auto it = range.first; it != range.second; ++it) {
+        if (it->second.packageName == app) {
+            mMap.erase(it);
+            return;
+        }
+    }
+    ALOGD("removeApp failed to find the app %s with uid %i to remove", app.c_str(), uid);
+    return;
+}
+
+void UidMap::addListener(sp<PackageInfoListener> producer) {
+    lock_guard<mutex> lock(mMutex);  // Lock for updates
+    mSubscribers.insert(producer);
+}
+
+void UidMap::removeListener(sp<PackageInfoListener> producer) {
+    lock_guard<mutex> lock(mMutex);  // Lock for updates
+    mSubscribers.erase(producer);
+}
+
+UidMapping UidMap::getAndClearOutput() {
+    lock_guard<mutex> lock(mMutex);  // Lock for updates
+
+    auto ret = UidMapping(mOutput);  // Copy that will be returned.
+    mOutput.Clear();
+
+    // Re-initialize the initial state for the outputs. This results in extra data being uploaded
+    // but helps ensure we can't re-construct the UID->app name, versionCode mapping in server.
+    for (auto it : mMap) {
+        auto t = mOutput.add_initial();
+        t->set_app(it.second.packageName);
+        t->set_version(it.second.versionCode);
+        t->set_uid(it.first);
+    }
+
+    return ret;
+}
+
+void UidMap::printUidMap(FILE* out) {
+    lock_guard<mutex> lock(mMutex);
+
+    for (auto it : mMap) {
+        fprintf(out, "%s, v%d (%i)\n", it.second.packageName.c_str(), it.second.versionCode,
+                it.first);
+    }
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
new file mode 100644
index 0000000..d550372
--- /dev/null
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STATSD_UIDMAP_H
+#define STATSD_UIDMAP_H
+
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "packages/PackageInfoListener.h"
+
+#include <binder/IResultReceiver.h>
+#include <binder/IShellCallback.h>
+#include <log/logprint.h>
+#include <stdio.h>
+#include <utils/RefBase.h>
+#include <mutex>
+#include <set>
+#include <string>
+#include <unordered_map>
+
+using namespace std;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+struct AppData {
+    const string packageName;
+    int versionCode;
+
+    AppData(const string& a, const int v) : packageName(a), versionCode(v){};
+};
+
+// UidMap keeps track of what the corresponding app name (APK name) and version code for every uid
+// at any given moment. This map must be updated by StatsCompanionService.
+class UidMap : public virtual android::RefBase {
+public:
+    /*
+     * All three inputs must be the same size, and the jth element in each array refers to the same
+     * tuple, ie. uid[j] corresponds to packageName[j] with versionCode[j].
+     */
+    void updateMap(const vector<int32_t>& uid, const vector<int32_t>& versionCode,
+                   const vector<String16>& packageName);
+
+    // Returns true if the given uid contains the specified app (eg. com.google.android.gms).
+    bool hasApp(int uid, const string& packageName) const;
+
+    int getAppVersion(int uid, const string& packageName) const;
+
+    void updateApp(const String16& packageName, const int32_t& uid, const int32_t& versionCode);
+    void removeApp(const String16& packageName, const int32_t& uid);
+
+    // Helper for debugging contents of this uid map. Can be triggered with:
+    // adb shell cmd stats print-uid-map
+    void printUidMap(FILE* out);
+
+    // Commands for indicating to the map that a producer should be notified if an app is updated.
+    // This allows the metric producer to distinguish when the same uid or app represents a
+    // different version of an app.
+    void addListener(sp<PackageInfoListener> producer);
+    // Remove the listener from the set of metric producers that subscribe to updates.
+    void removeListener(sp<PackageInfoListener> producer);
+
+    // Grabs the current output contents and then clears it.
+    UidMapping getAndClearOutput();
+
+private:
+    // TODO: Use shared_mutex for improved read-locking if a library can be found in Android.
+    mutable mutex mMutex;
+
+    std::unordered_multimap<int, AppData> mMap;
+
+    // We prepare the output proto as apps are updated, so that we can grab the current output.
+    UidMapping mOutput;
+
+    // Metric producers that should be notified if there's an upgrade in any app.
+    set<sp<PackageInfoListener>> mSubscribers;
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+
+#endif  // STATSD_UIDMAP_H
diff --git a/cmds/statsd/src/stats_events.proto b/cmds/statsd/src/stats_events.proto
index 1e17895..cd00ba8 100644
--- a/cmds/statsd/src/stats_events.proto
+++ b/cmds/statsd/src/stats_events.proto
@@ -15,49 +15,116 @@
  */
 
 syntax = "proto2";
-option optimize_for = LITE_RUNTIME;
 
+// TODO: Not the right package and class name
 package android.os.statsd;
-
 option java_package = "com.android.os";
 option java_outer_classname = "StatsEventProto";
 
+/**
+ * The master event class. This message defines all of the available
+ * raw stats log events from the Android system, also known as "atoms."
+ *
+ * This field contains a single oneof with all of the available messages.
+ * The stats-log-api-gen tool runs as part of the Android build and
+ * generates the android.util.StatsLog class, which contains the constants
+ * and methods that Android uses to log.
+ *
+ * This StatsEvent class is not actually built into the Android system.
+ * Instead, statsd on Android constructs these messages synthetically,
+ * in the format defined here and in stats_log.proto.
+ */
 message StatsEvent {
-  oneof event {
-    // Screen state change.
-    ScreenStateChange screen_state_change = 2;
-    // Process state change.
-    ProcessStateChange process_state_change = 1112;
-  }
+    oneof event {
+        ScreenStateChanged screen_state_changed = 1;
+        ProcessStateChanged process_state_changed = 2;
+        WakeLockChanged wakelock_changed = 3;
+    }
 }
 
-// Logs changes in screen state. This event is logged in
-// frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
-message ScreenStateChange {
-  // Screen state enums follow the values defined in below file.
-  // frameworks/base/core/java/android/view/Display.java
-  enum State {
-    STATE_UNKNOWN = 0;
-    STATE_OFF = 1;
-    STATE_ON = 2;
-    STATE_DOZE = 3;
-    STATE_DOZE_SUSPEND = 4;
-    STATE_VR = 5;
-  }
-  // New screen state.
-  optional State display_state = 1;
+/**
+ * A WorkSource represents the chained attribution of applications that
+ * resulted in a particular bit of work being done.
+ */
+message WorkSource {
+    // TODO
 }
 
-// Logs changes in process state. This event is logged in
-// frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
-message ProcessStateChange {
-  // Type of process event.
-  enum State {
-    START = 1;
-    CRASH = 2;
-  }
-  optional State state = 1;
+/*
+ * *****************************************************************************
+ * Below are all of the individual atoms that are logged by Android via statsd
+ * and Westworld.
+ *
+ * RULES:
+ *   - The field ids for each atom must start at 1, and count upwards by 1.
+ *     Skipping field ids is not allowed.
+ *   - These form an API, so renaming, renumbering or removing fields is
+ *     not allowed between android releases.  (This is not currently enforced,
+ *     but there will be a tool to enforce this restriction).
+ *   - The types must be built-in protocol buffer types, namely, no sub-messages
+ *     are allowed (yet).  The bytes type is also not allowed.
+ *   - The CamelCase name of the message type should match the
+ *     underscore_separated name as defined in StatsEvent.
+ *   - If an atom represents work that can be attributed to an app, there can
+ *     be exactly one WorkSource field. It must be field number 1.
+ *   - A field that is a uid should be a string field, tagged with the [xxx]
+ *     annotation. The generated code on android will be represented by UIDs,
+ *     and those UIDs will be translated in xxx to those strings.
+ *
+ * CONVENTIONS:
+ *   - Events are past tense. e.g. ScreenStateChanged, not ScreenStateChange
+ *   - If there is a UID, it goes first. Think in an object-oriented fashion.
+ * *****************************************************************************
+ */
 
-  // UID associated with the package.
-  optional int32 uid = 2;
+/**
+ * Logs when the screen state changes.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
+ */
+message ScreenStateChanged {
+    // TODO: Use the real screen state.
+    enum State {
+        STATE_UNKNOWN = 0;
+        STATE_OFF = 1;
+        STATE_ON = 2;
+        STATE_DOZE = 3;
+        STATE_DOZE_SUSPEND = 4;
+        STATE_VR = 5;
+    }
+    // New screen state.
+    optional State display_state = 1;
 }
+
+/**
+ * Logs that the state of a process state, as per the activity manager has changed.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
+ */
+message ProcessStateChanged {
+    // TODO: Use the real (mapped) process states.
+    optional int32 uid = 1; // TODO: should be a string tagged w/ uid annotation
+
+    // The state.
+    optional int32 state = 2;
+}
+
+/**
+ * Logs that the state of a wakelock has changed.
+ *
+ * Logged from:
+ *   TODO
+ */
+message WakeLockChanged {
+    // TODO: Add attribution instead of uid.
+    optional int32 uid = 1;
+
+    // The wakelock tag (Called tag in the Java API, sometimes name elsewhere).
+    optional string tag = 2;
+
+    // TODO: Use a constant instead of boolean?
+    optional bool state = 3;
+}
+
diff --git a/cmds/statsd/src/stats_events_copy.proto b/cmds/statsd/src/stats_events_copy.proto
new file mode 100644
index 0000000..5e8ef24
--- /dev/null
+++ b/cmds/statsd/src/stats_events_copy.proto
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// STOPSHIP: this is a duplicate of stats_event.proto with LITE_RUNTIME added
+// to produce device side lite proto. We should move statsd to soong so that
+// we can generate full and lite library from the same proto file.
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+// TODO: Not the right package and class name
+package android.os.statsd;
+option java_package = "com.android.os";
+option java_outer_classname = "StatsEventProto";
+
+/**
+ * The master event class. This message defines all of the available
+ * raw stats log events from the Android system, also known as "atoms."
+ *
+ * This field contains a single oneof with all of the available messages.
+ * The stats-log-api-gen tool runs as part of the Android build and
+ * generates the android.util.StatsLog class, which contains the constants
+ * and methods that Android uses to log.
+ *
+ * This StatsEvent class is not actually built into the Android system.
+ * Instead, statsd on Android constructs these messages synthetically,
+ * in the format defined here and in stats_log.proto.
+ */
+message StatsEvent {
+    oneof event {
+        ScreenStateChanged screen_state_changed = 1;
+        ProcessStateChanged process_state_changed = 2;
+        WakeLockChanged wakelock_changed = 3;
+    }
+}
+
+/**
+ * A WorkSource represents the chained attribution of applications that
+ * resulted in a particular bit of work being done.
+ */
+message WorkSource {
+    // TODO
+}
+
+/*
+ * *****************************************************************************
+ * Below are all of the individual atoms that are logged by Android via statsd
+ * and Westworld.
+ *
+ * RULES:
+ *   - The field ids for each atom must start at 1, and count upwards by 1.
+ *     Skipping field ids is not allowed.
+ *   - These form an API, so renaming, renumbering or removing fields is
+ *     not allowed between android releases.  (This is not currently enforced,
+ *     but there will be a tool to enforce this restriction).
+ *   - The types must be built-in protocol buffer types, namely, no sub-messages
+ *     are allowed (yet).  The bytes type is also not allowed.
+ *   - The CamelCase name of the message type should match the
+ *     underscore_separated name as defined in StatsEvent.
+ *   - If an atom represents work that can be attributed to an app, there can
+ *     be exactly one WorkSource field. It must be field number 1.
+ *   - A field that is a uid should be a string field, tagged with the [xxx]
+ *     annotation. The generated code on android will be represented by UIDs,
+ *     and those UIDs will be translated in xxx to those strings.
+ *
+ * CONVENTIONS:
+ *   - Events are past tense. e.g. ScreenStateChanged, not ScreenStateChange
+ *   - If there is a UID, it goes first. Think in an object-oriented fashion.
+ * *****************************************************************************
+ */
+
+/**
+ * Logs when the screen state changes.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
+ */
+message ScreenStateChanged {
+    // TODO: Use the real screen state.
+    enum State {
+        STATE_UNKNOWN = 0;
+        STATE_OFF = 1;
+        STATE_ON = 2;
+        STATE_DOZE = 3;
+        STATE_DOZE_SUSPEND = 4;
+        STATE_VR = 5;
+    }
+    // New screen state.
+    optional State display_state = 1;
+}
+
+/**
+ * Logs that the state of a process state, as per the activity manager has changed.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
+ */
+message ProcessStateChanged {
+    // TODO: Use the real (mapped) process states.
+    optional int32 uid = 1; // TODO: should be a string tagged w/ uid annotation
+
+    // The state.
+    optional int32 state = 2;
+}
+
+/**
+ * Logs that the state of a wakelock has changed.
+ *
+ * Logged from:
+ *   TODO
+ */
+message WakeLockChanged {
+    // TODO: Add attribution instead of uid.
+    optional int32 uid = 1;
+
+    // The wakelock tag (Called tag in the Java API, sometimes name elsewhere).
+    optional string tag = 2;
+
+    // TODO: Use a constant instead of boolean?
+    optional bool state = 3;
+}
+
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 6421b70..29cd94b 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -22,7 +22,7 @@
 option java_package = "com.android.os";
 option java_outer_classname = "StatsLog";
 
-import "frameworks/base/cmds/statsd/src/stats_events.proto";
+import "frameworks/base/cmds/statsd/src/stats_events_copy.proto";
 
 message KeyValuePair {
   optional int32 key = 1;
@@ -106,7 +106,7 @@
     repeated CountMetricData data = 1;
   }
   message DurationMetricDataWrapper {
-    repeated CountMetricData data = 1;
+    repeated DurationMetricData data = 1;
   }
   oneof data {
     EventMetricDataWrapper event_metrics = 4;
diff --git a/cmds/statsd/src/stats_util.cpp b/cmds/statsd/src/stats_util.cpp
index 978b228..fcce2ff 100644
--- a/cmds/statsd/src/stats_util.cpp
+++ b/cmds/statsd/src/stats_util.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include <log/log_event_list.h>
 #include "stats_util.h"
+#include <log/log_event_list.h>
 
 namespace android {
 namespace os {
@@ -128,162 +128,35 @@
     return eventMetricData;
 }
 
-StatsdConfig buildFakeConfig() {
-    // HACK: Hard code a test metric for counting screen on events...
-    StatsdConfig config;
-    config.set_config_id(12345L);
-
-    // One count metric to count screen on
-    CountMetric* metric = config.add_count_metric();
-    metric->set_metric_id(20150717L);
-    metric->set_what("SCREEN_IS_ON");
-    metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
-
-    // One count metric to count PHOTO_CHANGE_OR_CHROME_CRASH
-    metric = config.add_count_metric();
-    metric->set_metric_id(20150718L);
-    metric->set_what("PHOTO_PROCESS_STATE_CHANGE");
-    metric->mutable_bucket()->set_bucket_size_millis(60 * 1000L);
-    metric->set_condition("SCREEN_IS_ON");
-
-
-    LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
-    eventMatcher->set_name("SCREEN_IS_ON");
-
-    SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
-    simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
-    simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
-            1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
-    simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
-            2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
-
-
-
-    eventMatcher = config.add_log_entry_matcher();
-    eventMatcher->set_name("SCREEN_IS_OFF");
-
-    simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
-    simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
-    simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
-            1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
-    simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
-            1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
-
-
-
-    LogEntryMatcher* procEventMatcher = config.add_log_entry_matcher();
-    procEventMatcher->set_name("PHOTO_CRASH");
-
-    SimpleLogEntryMatcher* simpleLogMatcher2 = procEventMatcher->mutable_simple_log_entry_matcher();
-    simpleLogMatcher2->add_tag(1112 /*PROCESS_STATE_CHANGE*/);
-    KeyValueMatcher* keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
-    keyValueMatcher->mutable_key_matcher()->set_key(
-                1002 /*pkg*/);
-    keyValueMatcher->set_eq_string(
-            "com.google.android.apps.photos" /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
-
-    keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
-    keyValueMatcher->mutable_key_matcher()->set_key(
-                                   1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
-    keyValueMatcher->set_eq_int(2);
-
-
-    procEventMatcher = config.add_log_entry_matcher();
-    procEventMatcher->set_name("PHOTO_START");
-
-    simpleLogMatcher2 = procEventMatcher->mutable_simple_log_entry_matcher();
-    simpleLogMatcher2->add_tag(1112 /*PROCESS_STATE_CHANGE*/);
-    keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
-    keyValueMatcher->mutable_key_matcher()->set_key(
-                1002 /*pkg*/);
-    keyValueMatcher->set_eq_string(
-            "com.google.android.apps.photos" /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
-
-    keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
-    keyValueMatcher->mutable_key_matcher()->set_key(
-                                   1 /*STATE*/);
-    keyValueMatcher->set_eq_int(1);
-
-
-    procEventMatcher = config.add_log_entry_matcher();
-    procEventMatcher->set_name("PHOTO_PROCESS_STATE_CHANGE");
-    LogEntryMatcher_Combination* combinationMatcher = procEventMatcher->mutable_combination();
-    combinationMatcher->set_operation(LogicalOperation::OR);
-    combinationMatcher->add_matcher("PHOTO_START");
-    combinationMatcher->add_matcher("PHOTO_CRASH");
-
-
-    procEventMatcher = config.add_log_entry_matcher();
-    procEventMatcher->set_name("CHROME_CRASH");
-
-    simpleLogMatcher2 = procEventMatcher->mutable_simple_log_entry_matcher();
-    simpleLogMatcher2->add_tag(1112 /*PROCESS_STATE_CHANGE*/);
-    keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
-    keyValueMatcher->mutable_key_matcher()->set_key(
-                1002 /*pkg*/);
-    keyValueMatcher->set_eq_string(
-            "com.android.chrome" /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
-
-    keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
-    keyValueMatcher->mutable_key_matcher()->set_key(
-                                   1 /*STATE*/);
-    keyValueMatcher->set_eq_int(2);
-
-
-
-    procEventMatcher = config.add_log_entry_matcher();
-    procEventMatcher->set_name("PHOTO_CHANGE_OR_CHROME_CRASH");
-    combinationMatcher = procEventMatcher->mutable_combination();
-    combinationMatcher->set_operation(LogicalOperation::OR);
-    combinationMatcher->add_matcher("PHOTO_PROCESS_STATE_CHANGE");
-    combinationMatcher->add_matcher("CHROME_CRASH");
-
-
-
-    Condition* condition = config.add_condition();
-    condition->set_name("SCREEN_IS_ON");
-    SimpleCondition* simpleCondition = condition->mutable_simple_condition();
-    simpleCondition->set_start("SCREEN_IS_ON");
-    simpleCondition->set_stop("SCREEN_IS_OFF");
-
-
-    condition = config.add_condition();
-        condition->set_name("PHOTO_STARTED");
-
-        simpleCondition = condition->mutable_simple_condition();
-        simpleCondition->set_start("PHOTO_START");
-        simpleCondition->set_stop("PHOTO_CRASH");
-
-
-    condition = config.add_condition();
-    condition->set_name("SCREEN_IS_OFF");
-
-    simpleCondition = condition->mutable_simple_condition();
-    simpleCondition->set_start("SCREEN_IS_OFF");
-    simpleCondition->set_stop("SCREEN_IS_ON");
-
-
-    condition = config.add_condition();
-    condition->set_name("SCREEN_IS_EITHER_ON_OFF");
-
-    Condition_Combination* combination = condition->mutable_combination();
-    combination->set_operation(LogicalOperation::OR);
-    combination->add_condition("SCREEN_IS_ON");
-    combination->add_condition("SCREEN_IS_OFF");
-
-
-    condition = config.add_condition();
-    condition->set_name("SCREEN_IS_NEITHER_ON_OFF");
-
-    combination = condition->mutable_combination();
-    combination->set_operation(LogicalOperation::NOR);
-    combination->add_condition("SCREEN_IS_ON");
-    combination->add_condition("SCREEN_IS_OFF");
-
-    return config;
+// There is no existing hash function for the dimension key ("repeated KeyValuePair").
+// Temporarily use a string concatenation as the hashable key.
+// TODO: Find a better hash function for std::vector<KeyValuePair>.
+HashableDimensionKey getHashableKey(std::vector<KeyValuePair> keys) {
+    std::string flattened;
+    for (const KeyValuePair& pair : keys) {
+        flattened += std::to_string(pair.key());
+        flattened += ":";
+        switch (pair.value_case()) {
+            case KeyValuePair::ValueCase::kValueStr:
+                flattened += pair.value_str();
+                break;
+            case KeyValuePair::ValueCase::kValueInt:
+                flattened += std::to_string(pair.value_int());
+                break;
+            case KeyValuePair::ValueCase::kValueBool:
+                flattened += std::to_string(pair.value_bool());
+                break;
+            case KeyValuePair::ValueCase::kValueFloat:
+                flattened += std::to_string(pair.value_float());
+                break;
+            default:
+                break;
+        }
+        flattened += "|";
+    }
+    return flattened;
 }
 
-
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/stats_util.h b/cmds/statsd/src/stats_util.h
index 25b9bba..575588b 100644
--- a/cmds/statsd/src/stats_util.h
+++ b/cmds/statsd/src/stats_util.h
@@ -13,11 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#ifndef PARSE_UTIL_H
-#define PARSE_UTIL_H
+#ifndef STATS_UTIL_H
+#define STATS_UTIL_H
 
-#include "DropboxWriter.h"
-#include "LogReader.h"
+#include "logd/LogReader.h"
+#include "storage/DropboxWriter.h"
 
 #include <log/logprint.h>
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
@@ -26,14 +26,19 @@
 namespace os {
 namespace statsd {
 
+#define DEFAULT_DIMENSION_KEY ""
+#define MATCHER_NOT_FOUND -2
+#define NANO_SECONDS_IN_A_SECOND (1000 * 1000 * 1000)
+
+typedef std::string HashableDimensionKey;
+
 EventMetricData parse(log_msg msg);
 
 int getTagId(log_msg msg);
 
-StatsdConfig buildFakeConfig();
-
+std::string getHashableKey(std::vector<KeyValuePair> key);
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
 
-#endif  // PARSE_UTIL_H
+#endif  // STATS_UTIL_H
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index d7702cd..afb3f2b 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -55,7 +55,7 @@
 }
 
 message SimpleLogEntryMatcher {
-  repeated int32 tag = 1;
+  optional int32 tag = 1;
 
   repeated KeyValueMatcher key_value_matcher = 2;
 }
@@ -103,12 +103,28 @@
   optional int64 bucket_size_millis = 1;
 }
 
+message Alert {
+  message IncidentdDetails {
+    optional string alert_name = 1;
+    repeated int32 incidentd_sections = 2;
+  }
+  optional IncidentdDetails incidentd_details = 1;
+
+  optional int32 number_of_buckets = 3;
+
+  optional int32 refractory_period_secs = 4;
+
+  optional int64 trigger_if_gt = 5;
+}
+
 message EventMetric {
   optional int64 metric_id = 1;
 
   optional string what = 2;
 
   optional string condition = 3;
+
+  repeated EventConditionLink links = 4;
 }
 
 message CountMetric {
@@ -121,26 +137,73 @@
   repeated KeyMatcher dimension = 4;
 
   optional Bucket bucket = 5;
+
+  repeated Alert alerts = 6;
+
+  optional bool include_in_output = 7;
+
+  repeated EventConditionLink links = 8;
 }
 
 message DurationMetric {
   optional int64 metric_id = 1;
 
+  optional string start = 2;
+
+  optional string stop = 3;
+
+  optional string stop_all = 4;
+
   enum AggregationType {
     DURATION_SUM = 1;
 
     DURATION_MAX_SPARSE = 2;
     DURATION_MIN_SPARSE = 3;
   }
-  optional AggregationType type = 2;
+  optional AggregationType type = 5;
 
-  optional string predicate = 3;
+  optional string predicate = 6;
 
-  repeated KeyMatcher dimension = 4;
+  repeated KeyMatcher dimension = 7;
 
-  optional Bucket bucket = 5;
+  optional Bucket bucket = 8;
+
+  repeated EventConditionLink links = 9;
 }
 
+message ValueMetric {
+  optional int64 metric_id = 1;
+
+  optional string what = 2;
+
+  optional int32 value_field = 3;
+
+  optional string condition = 4;
+
+  repeated KeyMatcher dimension = 5;
+
+  optional Bucket bucket = 6;
+
+  enum Operation {
+    SUM_DIFF = 1;
+    MIN_DIFF = 2;
+    MAX_DIFF = 3;
+    SUM = 4;
+    MIN = 5;
+    MAX = 6;
+    FIRST = 7;
+    LAST = 8;
+  }
+  optional Operation operation = 7;
+}
+
+message EventConditionLink {
+    optional string condition = 1;
+
+    repeated KeyMatcher key_in_main = 2;
+    repeated KeyMatcher key_in_condition = 3;
+};
+
 message StatsdConfig {
   optional int64 config_id = 1;
 
@@ -148,7 +211,11 @@
 
   repeated CountMetric count_metric = 3;
 
-  repeated LogEntryMatcher log_entry_matcher = 4;
+  repeated ValueMetric value_metric = 4;
 
-  repeated Condition condition = 5;
+  repeated DurationMetric duration_metric = 5;
+
+  repeated LogEntryMatcher log_entry_matcher = 6;
+
+  repeated Condition condition = 7;
 }
diff --git a/cmds/statsd/src/storage/DropboxReader.cpp b/cmds/statsd/src/storage/DropboxReader.cpp
new file mode 100644
index 0000000..c561959
--- /dev/null
+++ b/cmds/statsd/src/storage/DropboxReader.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <android-base/file.h>
+#include <android/os/DropBoxManager.h>
+#include <androidfw/ZipUtils.h>
+
+#include "storage/DropboxReader.h"
+
+using android::base::unique_fd;
+using android::binder::Status;
+using android::os::DropBoxManager;
+using android::sp;
+using android::String16;
+using android::ZipUtils;
+using std::vector;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+status_t DropboxReader::readStatsLogs(FILE* out, const string& tag, long msec) {
+    sp<DropBoxManager> dropbox = new DropBoxManager();
+    StatsLogReport logReport;
+
+    long timestamp = msec;
+    // instead of while(true), put a hard limit 1000. Dropbox won't have more than 1000 files.
+    for (int i = 0; i < 1000; i++) {
+        DropBoxManager::Entry entry;
+        Status status = dropbox->getNextEntry(String16(tag.c_str()), timestamp, &entry);
+        if (!status.isOk()) {
+            ALOGD("No more entries, or failed to read. We can't tell unfortunately.");
+            return android::OK;
+        }
+
+        const unique_fd& fd = entry.getFd();
+
+        // use this timestamp for next query.
+        timestamp = entry.getTimestamp();
+
+        if (entry.getFlags() & DropBoxManager::IS_GZIPPED) {
+            if (!parseFromGzipFile(fd, logReport)) {
+                // Failed to parse from the file. Continue to fetch the next entry.
+                continue;
+            }
+        } else {
+            if (!parseFromFile(fd, logReport)) {
+                // Failed to parse from the file. Continue to fetch the next entry.
+                continue;
+            }
+        }
+
+        printLog(out, logReport);
+    }
+    return android::OK;
+}
+
+bool DropboxReader::parseFromGzipFile(const unique_fd& fd, StatsLogReport& logReport) {
+    FILE* file = fdopen(fd, "r");
+    bool result = false;
+    bool scanResult;
+    int method;
+    long compressedLen;
+    long uncompressedLen;
+    unsigned long crc32;
+    scanResult = ZipUtils::examineGzip(file, &method, &uncompressedLen, &compressedLen, &crc32);
+    if (scanResult && method == kCompressDeflated) {
+        vector<uint8_t> buf(uncompressedLen);
+        if (ZipUtils::inflateToBuffer(file, &buf[0], uncompressedLen, compressedLen)) {
+            if (logReport.ParseFromArray(&buf[0], uncompressedLen)) {
+                result = true;
+            }
+        }
+    } else {
+        ALOGE("This isn't a valid deflated gzip file");
+    }
+    fclose(file);
+    return result;
+}
+
+// parse a non zipped file.
+bool DropboxReader::parseFromFile(const unique_fd& fd, StatsLogReport& logReport) {
+    string content;
+    if (!android::base::ReadFdToString(fd, &content)) {
+        ALOGE("Failed to read file");
+        return false;
+    }
+    if (!logReport.ParseFromString(content)) {
+        ALOGE("failed to parse log entry from data");
+        return false;
+    }
+    return true;
+}
+
+void DropboxReader::printLog(FILE* out, const StatsLogReport& logReport) {
+    fprintf(out, "start_time_ns=%lld, end_time_ns=%lld, ", logReport.start_report_nanos(),
+            logReport.end_report_nanos());
+    for (int i = 0; i < logReport.event_metrics().data_size(); i++) {
+        EventMetricData eventMetricData = logReport.event_metrics().data(i);
+        // TODO: Pretty-print the proto.
+        // fprintf(out, "EventMetricData=%s", eventMetricData.SerializeAsString().c_str());
+    }
+    fprintf(out, "\n");
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/DropboxReader.h b/cmds/statsd/src/storage/DropboxReader.h
similarity index 100%
rename from cmds/statsd/src/DropboxReader.h
rename to cmds/statsd/src/storage/DropboxReader.h
diff --git a/cmds/statsd/src/storage/DropboxWriter.cpp b/cmds/statsd/src/storage/DropboxWriter.cpp
new file mode 100644
index 0000000..e59bdbd
--- /dev/null
+++ b/cmds/statsd/src/storage/DropboxWriter.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/os/DropBoxManager.h>
+
+#include "storage/DropboxWriter.h"
+
+using android::binder::Status;
+using android::os::DropBoxManager;
+using android::sp;
+using android::String16;
+using std::vector;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+DropboxWriter::DropboxWriter(const string& tag) : mTag(tag), mLogReport(), mBufferSize(0) {
+}
+
+void DropboxWriter::addEventMetricData(const EventMetricData& eventMetricData) {
+    flushIfNecessary(eventMetricData);
+    EventMetricData* newEntry = mLogReport.mutable_event_metrics()->add_data();
+    newEntry->CopyFrom(eventMetricData);
+    mBufferSize += eventMetricData.ByteSize();
+}
+
+void DropboxWriter::flushIfNecessary(const EventMetricData& eventMetricData) {
+    if (eventMetricData.ByteSize() + mBufferSize > kMaxSerializedBytes) {
+        flush();
+    }
+}
+
+void DropboxWriter::flush() {
+    // now we get an exact byte size of the output
+    const int numBytes = mLogReport.ByteSize();
+    vector<uint8_t> buffer(numBytes);
+    sp<DropBoxManager> dropbox = new DropBoxManager();
+    mLogReport.SerializeToArray(&buffer[0], numBytes);
+    Status status = dropbox->addData(String16(mTag.c_str()), &buffer[0], numBytes, 0 /* no flag */);
+    if (!status.isOk()) {
+        ALOGE("failed to write to dropbox");
+        // TODO: What to do if flush fails??
+    }
+    mLogReport.Clear();
+    mBufferSize = 0;
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/DropboxWriter.h b/cmds/statsd/src/storage/DropboxWriter.h
similarity index 100%
rename from cmds/statsd/src/DropboxWriter.h
rename to cmds/statsd/src/storage/DropboxWriter.h
diff --git a/cmds/statsd/tests/AnomalyMonitor_test.cpp b/cmds/statsd/tests/AnomalyMonitor_test.cpp
index d5b6811..59fa160 100644
--- a/cmds/statsd/tests/AnomalyMonitor_test.cpp
+++ b/cmds/statsd/tests/AnomalyMonitor_test.cpp
@@ -12,9 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#define LOG_TAG "statsd_test"
-
-#include "../src/AnomalyMonitor.h"
+#include "anomaly/AnomalyMonitor.h"
 
 #include <gtest/gtest.h>
 
diff --git a/cmds/statsd/tests/ConditionTracker_test.cpp b/cmds/statsd/tests/ConditionTracker_test.cpp
index f8b0fd0..2935ac71 100644
--- a/cmds/statsd/tests/ConditionTracker_test.cpp
+++ b/cmds/statsd/tests/ConditionTracker_test.cpp
@@ -12,11 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#define LOG_TAG "statsd_test"
+#include "condition/condition_util.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
 #include <gtest/gtest.h>
-#include "../src/condition/condition_util.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
 #include <stdio.h>
 #include <vector>
diff --git a/cmds/statsd/tests/ConfigManager_test.cpp b/cmds/statsd/tests/ConfigManager_test.cpp
new file mode 100644
index 0000000..aa896ca
--- /dev/null
+++ b/cmds/statsd/tests/ConfigManager_test.cpp
@@ -0,0 +1,156 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/config/ConfigManager.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <stdio.h>
+#include <iostream>
+
+using namespace android;
+using namespace android::os::statsd;
+using namespace testing;
+using namespace std;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+static ostream& operator<<(ostream& os, const StatsdConfig& config) {
+    return os << "StatsdConfig{id=" << config.config_id() << "}";
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+
+/**
+ * Mock ConfigListener
+ */
+class MockListener : public ConfigListener {
+public:
+    MOCK_METHOD2(OnConfigUpdated, void(const ConfigKey& key, const StatsdConfig& config));
+    MOCK_METHOD1(OnConfigRemoved, void(const ConfigKey& key));
+};
+
+/**
+ * Validate that the ConfigKey is the one we wanted.
+ */
+MATCHER_P2(ConfigKeyEq, uid, name, "") {
+    return arg.GetUid() == uid && arg.GetName() == name;
+}
+
+/**
+ * Validate that the StatsdConfig is the one we wanted.
+ */
+MATCHER_P(StatsdConfigEq, configId, "") {
+    return arg.config_id() == configId;
+}
+
+/**
+ * Test the addOrUpdate and remove methods
+ */
+TEST(ConfigManagerTest, TestAddUpdateRemove) {
+    sp<MockListener> listener = new StrictMock<MockListener>();
+
+    sp<ConfigManager> manager = new ConfigManager();
+    manager->AddListener(listener);
+
+    StatsdConfig config91;
+    config91.set_config_id(91);
+    StatsdConfig config92;
+    config92.set_config_id(92);
+    StatsdConfig config93;
+    config93.set_config_id(93);
+    StatsdConfig config94;
+    config94.set_config_id(94);
+
+    {
+        InSequence s;
+
+        // The built-in fake one.
+        // TODO: Remove this when we get rid of the fake one, and make this
+        // test loading one from disk somewhere.
+        EXPECT_CALL(*(listener.get()),
+                    OnConfigUpdated(ConfigKeyEq(0, "fake"), StatsdConfigEq(12345)))
+                .RetiresOnSaturation();
+        manager->Startup();
+
+        // Add another one
+        EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, "zzz"), StatsdConfigEq(91)))
+                .RetiresOnSaturation();
+        manager->UpdateConfig(ConfigKey(1, "zzz"), config91);
+
+        // Update It
+        EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, "zzz"), StatsdConfigEq(92)))
+                .RetiresOnSaturation();
+        manager->UpdateConfig(ConfigKey(1, "zzz"), config92);
+
+        // Add one with the same uid but a different name
+        EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, "yyy"), StatsdConfigEq(93)))
+                .RetiresOnSaturation();
+        manager->UpdateConfig(ConfigKey(1, "yyy"), config93);
+
+        // Add one with the same name but a different uid
+        EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(2, "zzz"), StatsdConfigEq(94)))
+                .RetiresOnSaturation();
+        manager->UpdateConfig(ConfigKey(2, "zzz"), config94);
+
+        // Remove (1,yyy)
+        EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(1, "yyy")))
+                .RetiresOnSaturation();
+        manager->RemoveConfig(ConfigKey(1, "yyy"));
+
+        // Remove (2,zzz)
+        EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, "zzz")))
+                .RetiresOnSaturation();
+        manager->RemoveConfig(ConfigKey(2, "zzz"));
+
+        // Remove (1,zzz)
+        EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(1, "zzz")))
+                .RetiresOnSaturation();
+        manager->RemoveConfig(ConfigKey(1, "zzz"));
+
+        // Remove (2,zzz) again and we shouldn't get the callback
+        manager->RemoveConfig(ConfigKey(2, "zzz"));
+    }
+}
+
+/**
+ * Test removing all of the configs for a uid.
+ */
+TEST(ConfigManagerTest, TestRemoveUid) {
+    sp<MockListener> listener = new StrictMock<MockListener>();
+
+    sp<ConfigManager> manager = new ConfigManager();
+    manager->AddListener(listener);
+
+    StatsdConfig config;
+
+    EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, _)).Times(6);
+    EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, "xxx")));
+    EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, "yyy")));
+    EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, "zzz")));
+
+    manager->Startup();
+    manager->UpdateConfig(ConfigKey(1, "aaa"), config);
+    manager->UpdateConfig(ConfigKey(2, "xxx"), config);
+    manager->UpdateConfig(ConfigKey(2, "yyy"), config);
+    manager->UpdateConfig(ConfigKey(2, "zzz"), config);
+    manager->UpdateConfig(ConfigKey(3, "bbb"), config);
+
+    manager->RemoveConfigs(2);
+}
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index 6069801..19403c0 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -12,15 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#define LOG_TAG "statsd_test"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "matchers/matcher_util.h"
+#include "stats_util.h"
 
 #include <gtest/gtest.h>
 #include <log/log_event_list.h>
 #include <log/log_read.h>
 #include <log/logprint.h>
-#include "../src/matchers/matcher_util.h"
-#include "../src/stats_util.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
 #include <stdio.h>
 
@@ -28,145 +27,181 @@
 using std::unordered_map;
 using std::vector;
 
-const int kTagIdWakelock = 123;
-const int kKeyIdState = 45;
-const int kKeyIdPackageVersion = 67;
+const int TAG_ID = 123;
+const int FIELD_ID_1 = 1;
+const int FIELD_ID_2 = 2;
+const int FIELD_ID_3 = 2;
+
+// Private API from liblog.
+extern "C" void android_log_rewind(android_log_context ctx);
 
 #ifdef __ANDROID__
 TEST(LogEntryMatcherTest, TestSimpleMatcher) {
     // Set up the matcher
     LogEntryMatcher matcher;
     auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
-    simpleMatcher->add_tag(kTagIdWakelock);
+    simpleMatcher->set_tag(TAG_ID);
 
-    LogEventWrapper wrapper;
-    wrapper.tagId = kTagIdWakelock;
+    // Set up the event
+    android_log_event_list list(TAG_ID);
 
-    EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
+    // Convert to a LogEvent
+    list.convert_to_reader();
+    LogEvent event(999, &list);
+
+    // Test
+    EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
 }
 
 TEST(LogEntryMatcherTest, TestBoolMatcher) {
     // Set up the matcher
     LogEntryMatcher matcher;
     auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
-    simpleMatcher->add_tag(kTagIdWakelock);
-    auto keyValue = simpleMatcher->add_key_value_matcher();
-    keyValue->mutable_key_matcher()->set_key(kKeyIdState);
+    simpleMatcher->set_tag(TAG_ID);
+    auto keyValue1 = simpleMatcher->add_key_value_matcher();
+    keyValue1->mutable_key_matcher()->set_key(FIELD_ID_1);
+    auto keyValue2 = simpleMatcher->add_key_value_matcher();
+    keyValue2->mutable_key_matcher()->set_key(FIELD_ID_2);
 
-    LogEventWrapper wrapper;
-    wrapper.tagId = kTagIdWakelock;
+    // Set up the event
+    android_log_event_list list(TAG_ID);
+    list << true;
+    list << false;
 
-    keyValue->set_eq_bool(true);
-    wrapper.boolMap[kKeyIdState] = true;
-    EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
+    // Convert to a LogEvent
+    list.convert_to_reader();
+    LogEvent event(999, &list);
 
-    keyValue->set_eq_bool(false);
-    EXPECT_FALSE(matchesSimple(*simpleMatcher, wrapper));
+    // Test
+    keyValue1->set_eq_bool(true);
+    keyValue2->set_eq_bool(false);
+    EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
 
-    wrapper.boolMap[kKeyIdState] = false;
-    EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
+    keyValue1->set_eq_bool(false);
+    keyValue2->set_eq_bool(false);
+    EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
+
+    keyValue1->set_eq_bool(true);
+    keyValue2->set_eq_bool(false);
+    EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
+
+    keyValue1->set_eq_bool(true);
+    keyValue2->set_eq_bool(true);
+    EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
 }
 
 TEST(LogEntryMatcherTest, TestStringMatcher) {
     // Set up the matcher
     LogEntryMatcher matcher;
     auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
-    simpleMatcher->add_tag(kTagIdWakelock);
+    simpleMatcher->set_tag(TAG_ID);
     auto keyValue = simpleMatcher->add_key_value_matcher();
-    keyValue->mutable_key_matcher()->set_key(kKeyIdState);
-    keyValue->set_eq_string("wakelock_name");
+    keyValue->mutable_key_matcher()->set_key(FIELD_ID_1);
+    keyValue->set_eq_string("some value");
 
-    LogEventWrapper wrapper;
-    wrapper.tagId = kTagIdWakelock;
+    // Set up the event
+    android_log_event_list list(TAG_ID);
+    list << "some value";
 
-    wrapper.strMap[kKeyIdState] = "wakelock_name";
+    // Convert to a LogEvent
+    list.convert_to_reader();
+    LogEvent event(999, &list);
 
-    EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
+    // Test
+    EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
 }
 
 TEST(LogEntryMatcherTest, TestIntComparisonMatcher) {
     // Set up the matcher
     LogEntryMatcher matcher;
     auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
-    simpleMatcher->add_tag(kTagIdWakelock);
+
+    simpleMatcher->set_tag(TAG_ID);
     auto keyValue = simpleMatcher->add_key_value_matcher();
-    keyValue->mutable_key_matcher()->set_key(kKeyIdState);
+    keyValue->mutable_key_matcher()->set_key(FIELD_ID_1);
 
-    LogEventWrapper wrapper;
-    wrapper.tagId = kTagIdWakelock;
+    // Set up the event
+    android_log_event_list list(TAG_ID);
+    list << 11;
 
+    // Convert to a LogEvent
+    list.convert_to_reader();
+    LogEvent event(999, &list);
+
+    // Test
+
+    // eq_int
+    keyValue->set_eq_int(10);
+    EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
+    keyValue->set_eq_int(11);
+    EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
+    keyValue->set_eq_int(12);
+    EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
+
+    // lt_int
     keyValue->set_lt_int(10);
-    wrapper.intMap[kKeyIdState] = 11;
-    EXPECT_FALSE(matchesSimple(*simpleMatcher, wrapper));
-    wrapper.intMap[kKeyIdState] = 10;
-    EXPECT_FALSE(matchesSimple(*simpleMatcher, wrapper));
-    wrapper.intMap[kKeyIdState] = 9;
-    EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
+    EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
+    keyValue->set_lt_int(11);
+    EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
+    keyValue->set_lt_int(12);
+    EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
 
-    keyValue->set_gt_int(10);
-    wrapper.intMap[kKeyIdState] = 11;
-    EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
-    wrapper.intMap[kKeyIdState] = 10;
-    EXPECT_FALSE(matchesSimple(*simpleMatcher, wrapper));
-    wrapper.intMap[kKeyIdState] = 9;
-    EXPECT_FALSE(matchesSimple(*simpleMatcher, wrapper));
-}
-
-TEST(LogEntryMatcherTest, TestIntWithEqualityComparisonMatcher) {
-    // Set up the matcher
-    LogEntryMatcher matcher;
-    auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
-    simpleMatcher->add_tag(kTagIdWakelock);
-    auto keyValue = simpleMatcher->add_key_value_matcher();
-    keyValue->mutable_key_matcher()->set_key(kKeyIdState);
-
-    LogEventWrapper wrapper;
-    wrapper.tagId = kTagIdWakelock;
-
+    // lte_int
     keyValue->set_lte_int(10);
-    wrapper.intMap[kKeyIdState] = 11;
-    EXPECT_FALSE(matchesSimple(*simpleMatcher, wrapper));
-    wrapper.intMap[kKeyIdState] = 10;
-    EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
-    wrapper.intMap[kKeyIdState] = 9;
-    EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
+    EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
+    keyValue->set_lte_int(11);
+    EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
+    keyValue->set_lte_int(12);
+    EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
 
+    // gt_int
+    keyValue->set_gt_int(10);
+    EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
+    keyValue->set_gt_int(11);
+    EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
+    keyValue->set_gt_int(12);
+    EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
+
+    // gte_int
     keyValue->set_gte_int(10);
-    wrapper.intMap[kKeyIdState] = 11;
-    EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
-    wrapper.intMap[kKeyIdState] = 10;
-    EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
-    wrapper.intMap[kKeyIdState] = 9;
-    EXPECT_FALSE(matchesSimple(*simpleMatcher, wrapper));
+    EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
+    keyValue->set_gte_int(11);
+    EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
+    keyValue->set_gte_int(12);
+    EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
 }
 
+#if 0
+
 TEST(LogEntryMatcherTest, TestFloatComparisonMatcher) {
     // Set up the matcher
     LogEntryMatcher matcher;
     auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
-    simpleMatcher->add_tag(kTagIdWakelock);
-    auto keyValue = simpleMatcher->add_key_value_matcher();
-    keyValue->mutable_key_matcher()->set_key(kKeyIdState);
+    simpleMatcher->set_tag(TAG_ID);
 
-    LogEventWrapper wrapper;
-    wrapper.tagId = kTagIdWakelock;
+    auto keyValue = simpleMatcher->add_key_value_matcher();
+    keyValue->mutable_key_matcher()->set_key(FIELD_ID_1);
+
+    LogEvent event;
+    event.tagId = TAG_ID;
 
     keyValue->set_lt_float(10.0);
-    wrapper.floatMap[kKeyIdState] = 10.1;
-    EXPECT_FALSE(matchesSimple(*simpleMatcher, wrapper));
-    wrapper.floatMap[kKeyIdState] = 9.9;
-    EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
+    event.floatMap[FIELD_ID_1] = 10.1;
+    EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
+    event.floatMap[FIELD_ID_1] = 9.9;
+    EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
 
     keyValue->set_gt_float(10.0);
-    wrapper.floatMap[kKeyIdState] = 10.1;
-    EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
-    wrapper.floatMap[kKeyIdState] = 9.9;
-    EXPECT_FALSE(matchesSimple(*simpleMatcher, wrapper));
+    event.floatMap[FIELD_ID_1] = 10.1;
+    EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
+    event.floatMap[FIELD_ID_1] = 9.9;
+    EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
 }
+#endif
 
 // Helper for the composite matchers.
 void addSimpleMatcher(SimpleLogEntryMatcher* simpleMatcher, int tag, int key, int val) {
-    simpleMatcher->add_tag(tag);
+    simpleMatcher->set_tag(tag);
     auto keyValue = simpleMatcher->add_key_value_matcher();
     keyValue->mutable_key_matcher()->set_key(key);
     keyValue->set_eq_int(val);
diff --git a/cmds/statsd/tests/LogReader_test.cpp b/cmds/statsd/tests/LogReader_test.cpp
index 2002143..7ce1d6a 100644
--- a/cmds/statsd/tests/LogReader_test.cpp
+++ b/cmds/statsd/tests/LogReader_test.cpp
@@ -12,8 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#define LOG_TAG "statsd_test"
-
 #include <gtest/gtest.h>
 
 #include <stdio.h>
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index 673c156..b000e13 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -12,14 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#define LOG_TAG "statsd_test"
-
 #include <gtest/gtest.h>
-#include "../src/condition/ConditionTracker.h"
-#include "../src/matchers/LogMatchingTracker.h"
-#include "../src/metrics/CountMetricProducer.h"
-#include "../src/metrics/MetricProducer.h"
-#include "../src/metrics/metrics_manager_util.h"
+
+#include "src/condition/ConditionTracker.h"
+#include "src/matchers/LogMatchingTracker.h"
+#include "src/metrics/CountMetricProducer.h"
+#include "src/metrics/MetricProducer.h"
+#include "src/metrics/metrics_manager_util.h"
 
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
@@ -46,7 +45,7 @@
     eventMatcher->set_name("SCREEN_IS_ON");
 
     SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
-    simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
+    simpleLogEntryMatcher->set_tag(2 /*SCREEN_STATE_CHANGE*/);
     simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
             1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
     simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
@@ -56,7 +55,7 @@
     eventMatcher->set_name("SCREEN_IS_OFF");
 
     simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
-    simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
+    simpleLogEntryMatcher->set_tag(2 /*SCREEN_STATE_CHANGE*/);
     simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
             1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
     simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
@@ -81,7 +80,7 @@
     eventMatcher->set_name("SCREEN_IS_ON");
 
     SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
-    simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
+    simpleLogEntryMatcher->set_tag(2 /*SCREEN_STATE_CHANGE*/);
     simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
             1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
     simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
@@ -107,7 +106,7 @@
     eventMatcher->set_name("SCREEN_IS_ON");
 
     SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
-    simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
+    simpleLogEntryMatcher->set_tag(2 /*SCREEN_STATE_CHANGE*/);
     simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
             1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
     simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
@@ -133,7 +132,7 @@
     eventMatcher->set_name("SCREEN_IS_ON");
 
     SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
-    simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
+    simpleLogEntryMatcher->set_tag(2 /*SCREEN_STATE_CHANGE*/);
     simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
             1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
     simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
@@ -143,7 +142,7 @@
     eventMatcher->set_name("SCREEN_IS_OFF");
 
     simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
-    simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
+    simpleLogEntryMatcher->set_tag(2 /*SCREEN_STATE_CHANGE*/);
     simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
             1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
     simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index b6f1449..f9a90e4 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -12,10 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#define LOG_TAG "statsd_test"
+#include "packages/UidMap.h"
 
 #include <gtest/gtest.h>
-#include "../src/UidMap.h"
+
 #include <stdio.h>
 
 using namespace android;
@@ -66,4 +66,4 @@
 }
 #else
 GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
\ No newline at end of file
+#endif
diff --git a/cmds/statsd/tests/indexed_priority_queue_test.cpp b/cmds/statsd/tests/indexed_priority_queue_test.cpp
index 74a482e..600b953 100644
--- a/cmds/statsd/tests/indexed_priority_queue_test.cpp
+++ b/cmds/statsd/tests/indexed_priority_queue_test.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "../src/indexed_priority_queue.h"
+#include "src/anomaly/indexed_priority_queue.h"
 
 #include <gtest/gtest.h>
 
diff --git a/config/compiled-classes-phone b/config/compiled-classes-phone
index 42e6ecf..f32c0d6 100644
--- a/config/compiled-classes-phone
+++ b/config/compiled-classes-phone
@@ -3269,6 +3269,7 @@
 android.os.Parcel
 android.os.Parcel$1
 android.os.Parcel$2
+android.os.Parcel$ReadWriteHelper
 android.os.ParcelFileDescriptor
 android.os.ParcelFileDescriptor$1
 android.os.ParcelFileDescriptor$2
diff --git a/core/java/android/accessibilityservice/GestureDescription.java b/core/java/android/accessibilityservice/GestureDescription.java
index 92567d7..56f4ae2 100644
--- a/core/java/android/accessibilityservice/GestureDescription.java
+++ b/core/java/android/accessibilityservice/GestureDescription.java
@@ -428,6 +428,18 @@
         }
 
         @Override
+        public String toString() {
+            return "TouchPoint{"
+                    + "mStrokeId=" + mStrokeId
+                    + ", mContinuedStrokeId=" + mContinuedStrokeId
+                    + ", mIsStartOfPath=" + mIsStartOfPath
+                    + ", mIsEndOfPath=" + mIsEndOfPath
+                    + ", mX=" + mX
+                    + ", mY=" + mY
+                    + '}';
+        }
+
+        @Override
         public int describeContents() {
             return 0;
         }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index d988a42..85f73bb 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1879,7 +1879,7 @@
 
         if (isFinishing()) {
             if (mAutoFillResetNeeded) {
-                getAutofillManager().commit();
+                getAutofillManager().onActivityFinished();
             } else if (mIntent != null
                     && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)) {
                 // Activity was launched when user tapped a link in the Autofill Save UI - since
@@ -6259,6 +6259,8 @@
         final AutofillManager afm = getAutofillManager();
         if (afm != null) {
             afm.dump(prefix, writer);
+        } else {
+            writer.print(prefix); writer.println("No AutofillManager");
         }
     }
 
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 2ba6e01..fc4c8d7 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -16,14 +16,8 @@
 
 package android.app;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-
 import android.Manifest;
+import android.annotation.DrawableRes;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -948,11 +942,14 @@
                 ATTR_TASKDESCRIPTION_PREFIX + "color";
         private static final String ATTR_TASKDESCRIPTIONCOLOR_BACKGROUND =
                 ATTR_TASKDESCRIPTION_PREFIX + "colorBackground";
-        private static final String ATTR_TASKDESCRIPTIONICONFILENAME =
+        private static final String ATTR_TASKDESCRIPTIONICON_FILENAME =
                 ATTR_TASKDESCRIPTION_PREFIX + "icon_filename";
+        private static final String ATTR_TASKDESCRIPTIONICON_RESOURCE =
+                ATTR_TASKDESCRIPTION_PREFIX + "icon_resource";
 
         private String mLabel;
         private Bitmap mIcon;
+        private int mIconRes;
         private String mIconFilename;
         private int mColorPrimary;
         private int mColorBackground;
@@ -966,9 +963,27 @@
          * @param icon An icon that represents the current state of this task.
          * @param colorPrimary A color to override the theme's primary color.  This color must be
          *                     opaque.
+         * @deprecated use TaskDescription constructor with icon resource instead
          */
+        @Deprecated
         public TaskDescription(String label, Bitmap icon, int colorPrimary) {
-            this(label, icon, null, colorPrimary, 0, 0, 0);
+            this(label, icon, 0, null, colorPrimary, 0, 0, 0);
+            if ((colorPrimary != 0) && (Color.alpha(colorPrimary) != 255)) {
+                throw new RuntimeException("A TaskDescription's primary color should be opaque");
+            }
+        }
+
+        /**
+         * Creates the TaskDescription to the specified values.
+         *
+         * @param label A label and description of the current state of this task.
+         * @param iconRes A drawable resource of an icon that represents the current state of this
+         *                activity.
+         * @param colorPrimary A color to override the theme's primary color.  This color must be
+         *                     opaque.
+         */
+        public TaskDescription(String label, @DrawableRes int iconRes, int colorPrimary) {
+            this(label, null, iconRes, null, colorPrimary, 0, 0, 0);
             if ((colorPrimary != 0) && (Color.alpha(colorPrimary) != 255)) {
                 throw new RuntimeException("A TaskDescription's primary color should be opaque");
             }
@@ -979,9 +994,22 @@
          *
          * @param label A label and description of the current state of this activity.
          * @param icon An icon that represents the current state of this activity.
+         * @deprecated use TaskDescription constructor with icon resource instead
          */
+        @Deprecated
         public TaskDescription(String label, Bitmap icon) {
-            this(label, icon, null, 0, 0, 0, 0);
+            this(label, icon, 0, null, 0, 0, 0, 0);
+        }
+
+        /**
+         * Creates the TaskDescription to the specified values.
+         *
+         * @param label A label and description of the current state of this activity.
+         * @param iconRes A drawable resource of an icon that represents the current state of this
+         *                activity.
+         */
+        public TaskDescription(String label, @DrawableRes int iconRes) {
+            this(label, null, iconRes, null, 0, 0, 0, 0);
         }
 
         /**
@@ -990,21 +1018,22 @@
          * @param label A label and description of the current state of this activity.
          */
         public TaskDescription(String label) {
-            this(label, null, null, 0, 0, 0, 0);
+            this(label, null, 0, null, 0, 0, 0, 0);
         }
 
         /**
          * Creates an empty TaskDescription.
          */
         public TaskDescription() {
-            this(null, null, null, 0, 0, 0, 0);
+            this(null, null, 0, null, 0, 0, 0, 0);
         }
 
         /** @hide */
-        public TaskDescription(String label, Bitmap icon, String iconFilename, int colorPrimary,
-                int colorBackground, int statusBarColor, int navigationBarColor) {
+        public TaskDescription(String label, Bitmap bitmap, int iconRes, String iconFilename,
+                int colorPrimary, int colorBackground, int statusBarColor, int navigationBarColor) {
             mLabel = label;
-            mIcon = icon;
+            mIcon = bitmap;
+            mIconRes = iconRes;
             mIconFilename = iconFilename;
             mColorPrimary = colorPrimary;
             mColorBackground = colorBackground;
@@ -1026,6 +1055,7 @@
         public void copyFrom(TaskDescription other) {
             mLabel = other.mLabel;
             mIcon = other.mIcon;
+            mIconRes = other.mIconRes;
             mIconFilename = other.mIconFilename;
             mColorPrimary = other.mColorPrimary;
             mColorBackground = other.mColorBackground;
@@ -1041,6 +1071,7 @@
         public void copyFromPreserveHiddenFields(TaskDescription other) {
             mLabel = other.mLabel;
             mIcon = other.mIcon;
+            mIconRes = other.mIconRes;
             mIconFilename = other.mIconFilename;
             mColorPrimary = other.mColorPrimary;
             if (other.mColorBackground != 0) {
@@ -1113,6 +1144,14 @@
         }
 
         /**
+         * Sets the icon resource for this task description.
+         * @hide
+         */
+        public void setIcon(int iconRes) {
+            mIconRes = iconRes;
+        }
+
+        /**
          * Moves the icon bitmap reference from an actual Bitmap to a file containing the
          * bitmap.
          * @hide
@@ -1140,6 +1179,13 @@
         }
 
         /** @hide */
+        @TestApi
+        public int getIconResource() {
+            return mIconRes;
+        }
+
+        /** @hide */
+        @TestApi
         public String getIconFilename() {
             return mIconFilename;
         }
@@ -1205,7 +1251,10 @@
                         Integer.toHexString(mColorBackground));
             }
             if (mIconFilename != null) {
-                out.attribute(null, ATTR_TASKDESCRIPTIONICONFILENAME, mIconFilename);
+                out.attribute(null, ATTR_TASKDESCRIPTIONICON_FILENAME, mIconFilename);
+            }
+            if (mIconRes != 0) {
+                out.attribute(null, ATTR_TASKDESCRIPTIONICON_RESOURCE, Integer.toString(mIconRes));
             }
         }
 
@@ -1217,8 +1266,10 @@
                 setPrimaryColor((int) Long.parseLong(attrValue, 16));
             } else if (ATTR_TASKDESCRIPTIONCOLOR_BACKGROUND.equals(attrName)) {
                 setBackgroundColor((int) Long.parseLong(attrValue, 16));
-            } else if (ATTR_TASKDESCRIPTIONICONFILENAME.equals(attrName)) {
+            } else if (ATTR_TASKDESCRIPTIONICON_FILENAME.equals(attrName)) {
                 setIconFilename(attrValue);
+            } else if (ATTR_TASKDESCRIPTIONICON_RESOURCE.equals(attrName)) {
+                setIcon(Integer.parseInt(attrValue, 10));
             }
         }
 
@@ -1241,6 +1292,7 @@
                 dest.writeInt(1);
                 mIcon.writeToParcel(dest, 0);
             }
+            dest.writeInt(mIconRes);
             dest.writeInt(mColorPrimary);
             dest.writeInt(mColorBackground);
             dest.writeInt(mStatusBarColor);
@@ -1256,6 +1308,7 @@
         public void readFromParcel(Parcel source) {
             mLabel = source.readInt() > 0 ? source.readString() : null;
             mIcon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null;
+            mIconRes = source.readInt();
             mColorPrimary = source.readInt();
             mColorBackground = source.readInt();
             mStatusBarColor = source.readInt();
@@ -1276,8 +1329,8 @@
         @Override
         public String toString() {
             return "TaskDescription Label: " + mLabel + " Icon: " + mIcon +
-                    " IconFilename: " + mIconFilename + " colorPrimary: " + mColorPrimary +
-                    " colorBackground: " + mColorBackground +
+                    " IconRes: " + mIconRes + " IconFilename: " + mIconFilename +
+                    " colorPrimary: " + mColorPrimary + " colorBackground: " + mColorBackground +
                     " statusBarColor: " + mColorBackground +
                     " navigationBarColor: " + mNavigationBarColor;
         }
@@ -1439,7 +1492,6 @@
             }
             dest.writeInt(stackId);
             dest.writeInt(userId);
-            dest.writeLong(firstActiveTime);
             dest.writeLong(lastActiveTime);
             dest.writeInt(affiliatedTaskId);
             dest.writeInt(affiliatedTaskColor);
@@ -1468,7 +1520,6 @@
                     TaskDescription.CREATOR.createFromParcel(source) : null;
             stackId = source.readInt();
             userId = source.readInt();
-            firstActiveTime = source.readLong();
             lastActiveTime = source.readLong();
             affiliatedTaskId = source.readInt();
             affiliatedTaskColor = source.readInt();
@@ -1511,31 +1562,6 @@
     public static final int RECENT_IGNORE_UNAVAILABLE = 0x0002;
 
     /**
-     * Provides a list that contains recent tasks for all
-     * profiles of a user.
-     * @hide
-     */
-    public static final int RECENT_INCLUDE_PROFILES = 0x0004;
-
-    /**
-     * Ignores all tasks that are on the home stack.
-     * @hide
-     */
-    public static final int RECENT_IGNORE_HOME_AND_RECENTS_STACK_TASKS = 0x0008;
-
-    /**
-     * Ignores the top task in the docked stack.
-     * @hide
-     */
-    public static final int RECENT_INGORE_DOCKED_STACK_TOP_TASK = 0x0010;
-
-    /**
-     * Ignores all tasks that are on the pinned stack.
-     * @hide
-     */
-    public static final int RECENT_INGORE_PINNED_STACK_TASKS = 0x0020;
-
-    /**
      * <p></p>Return a list of the tasks that the user has recently launched, with
      * the most recent being first and older ones after in order.
      *
@@ -1570,33 +1596,7 @@
     public List<RecentTaskInfo> getRecentTasks(int maxNum, int flags)
             throws SecurityException {
         try {
-            return getService().getRecentTasks(maxNum,
-                    flags, UserHandle.myUserId()).getList();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Same as {@link #getRecentTasks(int, int)} but returns the recent tasks for a
-     * specific user. It requires holding
-     * the {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission.
-     * @param maxNum The maximum number of entries to return in the list.  The
-     * actual number returned may be smaller, depending on how many tasks the
-     * user has started and the maximum number the system can remember.
-     * @param flags Information about what to return.  May be any combination
-     * of {@link #RECENT_WITH_EXCLUDED} and {@link #RECENT_IGNORE_UNAVAILABLE}.
-     *
-     * @return Returns a list of RecentTaskInfo records describing each of
-     * the recent tasks. Most recently activated tasks go first.
-     *
-     * @hide
-     */
-    public List<RecentTaskInfo> getRecentTasksForUser(int maxNum, int flags, int userId)
-            throws SecurityException {
-        try {
-            return getService().getRecentTasks(maxNum,
-                    flags, userId).getList();
+            return getService().getRecentTasks(maxNum, flags, UserHandle.myUserId()).getList();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1889,22 +1889,6 @@
     }
 
     /**
-     * Completely remove the given task.
-     *
-     * @param taskId Identifier of the task to be removed.
-     * @return Returns true if the given task was found and removed.
-     *
-     * @hide
-     */
-    public boolean removeTask(int taskId) throws SecurityException {
-        try {
-            return getService().removeTask(taskId);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Sets the windowing mode for a specific task. Only works on tasks of type
      * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}
      * @param taskId The id of the task to set the windowing mode for.
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index f14831d..b62e4c2 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -23,6 +23,7 @@
 
 import android.annotation.Nullable;
 import android.annotation.TestApi;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
@@ -158,6 +159,12 @@
     private static final String KEY_ANIM_SPECS = "android:activity.animSpecs";
 
     /**
+     * Whether the activity should be launched into LockTask mode.
+     * @see #setLockTaskMode(boolean)
+     */
+    private static final String KEY_LOCK_TASK_MODE = "android:activity.lockTaskMode";
+
+    /**
      * The display id the activity should be launched into.
      * @see #setLaunchDisplayId(int)
      * @hide
@@ -278,6 +285,7 @@
     private int mResultCode;
     private int mExitCoordinatorIndex;
     private PendingIntent mUsageTimeReport;
+    private boolean mLockTaskMode = false;
     private int mLaunchDisplayId = INVALID_DISPLAY;
     @WindowConfiguration.WindowingMode
     private int mLaunchWindowingMode = WINDOWING_MODE_UNDEFINED;
@@ -869,6 +877,7 @@
                 mExitCoordinatorIndex = opts.getInt(KEY_EXIT_COORDINATOR_INDEX);
                 break;
         }
+        mLockTaskMode = opts.getBoolean(KEY_LOCK_TASK_MODE, false);
         mLaunchDisplayId = opts.getInt(KEY_LAUNCH_DISPLAY_ID, INVALID_DISPLAY);
         mLaunchWindowingMode = opts.getInt(KEY_LAUNCH_WINDOWING_MODE, WINDOWING_MODE_UNDEFINED);
         mLaunchActivityType = opts.getInt(KEY_LAUNCH_ACTIVITY_TYPE, ACTIVITY_TYPE_UNDEFINED);
@@ -1055,6 +1064,37 @@
     }
 
     /**
+     * Gets whether the activity is to be launched into LockTask mode.
+     * @return {@code true} if the activity is to be launched into LockTask mode.
+     * @see Activity#startLockTask()
+     * @see android.app.admin.DevicePolicyManager#setLockTaskPackages(ComponentName, String[])
+     */
+    public boolean getLockTaskMode() {
+        return mLockTaskMode;
+    }
+
+    /**
+     * Sets whether the activity is to be launched into LockTask mode.
+     *
+     * Use this option to start an activity in LockTask mode. Note that only apps permitted by
+     * {@link android.app.admin.DevicePolicyManager} can run in LockTask mode. Therefore, if
+     * {@link android.app.admin.DevicePolicyManager#isLockTaskPermitted(String)} returns
+     * {@code false} for the package of the target activity, a {@link SecurityException} will be
+     * thrown during {@link Context#startActivity(Intent, Bundle)}.
+     *
+     * Defaults to {@code false} if not set.
+     *
+     * @param lockTaskMode {@code true} if the activity is to be launched into LockTask mode.
+     * @return {@code this} {@link ActivityOptions} instance.
+     * @see Activity#startLockTask()
+     * @see android.app.admin.DevicePolicyManager#setLockTaskPackages(ComponentName, String[])
+     */
+    public ActivityOptions setLockTaskMode(boolean lockTaskMode) {
+        mLockTaskMode = lockTaskMode;
+        return this;
+    }
+
+    /**
      * Gets the id of the display where activity should be launched.
      * @return The id of the display where activity should be launched,
      *         {@link android.view.Display#INVALID_DISPLAY} if not set.
@@ -1247,6 +1287,7 @@
                 mExitCoordinatorIndex = otherOptions.mExitCoordinatorIndex;
                 break;
         }
+        mLockTaskMode = otherOptions.mLockTaskMode;
         mAnimSpecs = otherOptions.mAnimSpecs;
         mAnimationFinishedListener = otherOptions.mAnimationFinishedListener;
         mSpecsFuture = otherOptions.mSpecsFuture;
@@ -1321,6 +1362,7 @@
                 b.putInt(KEY_EXIT_COORDINATOR_INDEX, mExitCoordinatorIndex);
                 break;
         }
+        b.putBoolean(KEY_LOCK_TASK_MODE, mLockTaskMode);
         b.putInt(KEY_LAUNCH_DISPLAY_ID, mLaunchDisplayId);
         b.putInt(KEY_LAUNCH_WINDOWING_MODE, mLaunchWindowingMode);
         b.putInt(KEY_LAUNCH_ACTIVITY_TYPE, mLaunchActivityType);
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index f039516..117854a 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -178,8 +178,8 @@
      * SIGUSR1 is delivered. All others are ignored.
      */
     void signalPersistentProcesses(int signal);
-    ParceledListSlice getRecentTasks(int maxNum,
-            int flags, int userId);
+
+    ParceledListSlice getRecentTasks(int maxNum, int flags, int userId);
     oneway void serviceDoneExecuting(in IBinder token, int type, int startId, int res);
     oneway void activityDestroyed(in IBinder token);
     IIntentSender getIntentSender(int type, in String packageName, in IBinder token,
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 54f74b1..1fe2900 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -387,8 +387,6 @@
      * such as the Home key and the right soft keys, don't work.
      *
      * @return true if in keyguard restricted input mode.
-     *
-     * @see android.view.WindowManagerPolicy#inKeyguardRestrictedKeyInputMode
      */
     public boolean inKeyguardRestrictedInputMode() {
         try {
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index eb52cb7..a52dc1e 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -934,8 +934,14 @@
         public static final int PRIORITY_CATEGORY_CALLS = 1 << 3;
         /** Calls from repeat callers are prioritized. */
         public static final int PRIORITY_CATEGORY_REPEAT_CALLERS = 1 << 4;
+        /** Alarms are prioritized */
+        public static final int PRIORITY_CATEGORY_ALARMS = 1 << 5;
+        /** Media, system, game (catch-all for non-never suppressible sounds) are prioritized */
+        public static final int PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER = 1 << 6;
 
         private static final int[] ALL_PRIORITY_CATEGORIES = {
+            PRIORITY_CATEGORY_ALARMS,
+            PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER,
             PRIORITY_CATEGORY_REMINDERS,
             PRIORITY_CATEGORY_EVENTS,
             PRIORITY_CATEGORY_MESSAGES,
@@ -1135,6 +1141,9 @@
                 case PRIORITY_CATEGORY_MESSAGES: return "PRIORITY_CATEGORY_MESSAGES";
                 case PRIORITY_CATEGORY_CALLS: return "PRIORITY_CATEGORY_CALLS";
                 case PRIORITY_CATEGORY_REPEAT_CALLERS: return "PRIORITY_CATEGORY_REPEAT_CALLERS";
+                case PRIORITY_CATEGORY_ALARMS: return "PRIORITY_CATEGORY_ALARMS";
+                case PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER:
+                    return "PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER";
                 default: return "PRIORITY_CATEGORY_UNKNOWN_" + priorityCategory;
             }
         }
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index 402e209..895d12a 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -77,7 +77,7 @@
     }
 
     @Override
-    public void onTaskRemovalStarted(int taskId) {
+    public void onTaskRemovalStarted(int taskId) throws RemoteException {
     }
 
     @Override
@@ -91,11 +91,10 @@
     }
 
     @Override
-    public void onTaskProfileLocked(int taskId, int userId) {
+    public void onTaskProfileLocked(int taskId, int userId) throws RemoteException {
     }
 
     @Override
-    public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot)
-            throws RemoteException {
+    public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) throws RemoteException {
     }
 }
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 942cc99..081bd81 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -388,11 +388,12 @@
 
         public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault,
                 @SetWallpaperFlags int which) {
-            return peekWallpaperBitmap(context, returnDefault, which, context.getUserId());
+            return peekWallpaperBitmap(context, returnDefault, which, context.getUserId(),
+                    false /* hardware */);
         }
 
         public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault,
-                @SetWallpaperFlags int which, int userId) {
+                @SetWallpaperFlags int which, int userId, boolean hardware) {
             if (mService != null) {
                 try {
                     if (!mService.isWallpaperSupported(context.getOpPackageName())) {
@@ -409,7 +410,7 @@
                 mCachedWallpaper = null;
                 mCachedWallpaperUserId = 0;
                 try {
-                    mCachedWallpaper = getCurrentWallpaperLocked(context, userId);
+                    mCachedWallpaper = getCurrentWallpaperLocked(context, userId, hardware);
                     mCachedWallpaperUserId = userId;
                 } catch (OutOfMemoryError e) {
                     Log.w(TAG, "Out of memory loading the current wallpaper: " + e);
@@ -447,7 +448,7 @@
             }
         }
 
-        private Bitmap getCurrentWallpaperLocked(Context context, int userId) {
+        private Bitmap getCurrentWallpaperLocked(Context context, int userId, boolean hardware) {
             if (mService == null) {
                 Log.w(TAG, "WallpaperService not running");
                 return null;
@@ -460,6 +461,9 @@
                 if (fd != null) {
                     try {
                         BitmapFactory.Options options = new BitmapFactory.Options();
+                        if (hardware) {
+                            options.inPreferredConfig = Bitmap.Config.HARDWARE;
+                        }
                         return BitmapFactory.decodeFileDescriptor(
                                 fd.getFileDescriptor(), null, options);
                     } catch (OutOfMemoryError e) {
@@ -814,12 +818,23 @@
     }
 
     /**
-     * Like {@link #getDrawable()} but returns a Bitmap.
+     * Like {@link #getDrawable()} but returns a Bitmap with default {@link Bitmap.Config}.
      *
      * @hide
      */
     public Bitmap getBitmap() {
-        return getBitmapAsUser(mContext.getUserId());
+        return getBitmap(false);
+    }
+
+    /**
+     * Like {@link #getDrawable()} but returns a Bitmap.
+     *
+     * @param hardware Asks for a hardware backed bitmap.
+     * @see Bitmap.Config#HARDWARE
+     * @hide
+     */
+    public Bitmap getBitmap(boolean hardware) {
+        return getBitmapAsUser(mContext.getUserId(), hardware);
     }
 
     /**
@@ -827,8 +842,8 @@
      *
      * @hide
      */
-    public Bitmap getBitmapAsUser(int userId) {
-        return sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, userId);
+    public Bitmap getBitmapAsUser(int userId, boolean hardware) {
+        return sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, userId, hardware);
     }
 
     /**
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index d9b7cd7..e491a4f 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -616,6 +616,9 @@
         CharSequence[] mAutofillOptions;
         boolean mSanitized;
         HtmlInfo mHtmlInfo;
+        int mMinEms = -1;
+        int mMaxEms = -1;
+        int mMaxLength = -1;
 
         // POJO used to override some autofill-related values when the node is parcelized.
         // Not written to parcel.
@@ -713,6 +716,9 @@
                 if (p instanceof HtmlInfo) {
                     mHtmlInfo = (HtmlInfo) p;
                 }
+                mMinEms = in.readInt();
+                mMaxEms = in.readInt();
+                mMaxLength = in.readInt();
             }
             if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
                 mX = in.readInt();
@@ -876,6 +882,9 @@
                 } else {
                     out.writeParcelable(null, 0);
                 }
+                out.writeInt(mMinEms);
+                out.writeInt(mMaxEms);
+                out.writeInt(mMaxLength);
             }
             if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
                 out.writeInt(mX);
@@ -1444,6 +1453,39 @@
         public ViewNode getChildAt(int index) {
             return mChildren[index];
         }
+
+        /**
+         * Returns the minimum width in ems of the text associated with this node, or {@code -1}
+         * if not supported by the node.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
+         * not for assist purposes.
+         */
+        public int getMinTextEms() {
+            return mMinEms;
+        }
+
+        /**
+         * Returns the maximum width in ems of the text associated with this node, or {@code -1}
+         * if not supported by the node.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
+         * not for assist purposes.
+         */
+        public int getMaxTextEms() {
+            return mMaxEms;
+        }
+
+        /**
+         * Returns the maximum length of the text associated with this node node, or {@code -1}
+         * if not supported by the node or not set.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
+         * not for assist purposes.
+         */
+        public int getMaxTextLength() {
+            return mMaxLength;
+        }
     }
 
     /**
@@ -1776,6 +1818,21 @@
         }
 
         @Override
+        public void setMinTextEms(int minEms) {
+            mNode.mMinEms = minEms;
+        }
+
+        @Override
+        public void setMaxTextEms(int maxEms) {
+            mNode.mMaxEms = maxEms;
+        }
+
+        @Override
+        public void setMaxTextLength(int maxLength) {
+            mNode.mMaxLength = maxLength;
+        }
+
+        @Override
         public void setDataIsSensitive(boolean sensitive) {
             mNode.mSanitized = !sensitive;
         }
diff --git a/core/java/android/app/slice/Slice.java b/core/java/android/app/slice/Slice.java
new file mode 100644
index 0000000..7f9f74b
--- /dev/null
+++ b/core/java/android/app/slice/Slice.java
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.slice;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringDef;
+import android.app.PendingIntent;
+import android.app.RemoteInput;
+import android.content.ContentResolver;
+import android.content.IContentProvider;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.widget.RemoteViews;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A slice is a piece of app content and actions that can be surfaced outside of the app.
+ *
+ * <p>They are constructed using {@link Builder} in a tree structure
+ * that provides the OS some information about how the content should be displayed.
+ */
+public final class Slice implements Parcelable {
+
+    /**
+     * @hide
+     */
+    @StringDef({HINT_TITLE, HINT_LIST, HINT_LIST_ITEM, HINT_LARGE, HINT_ACTIONS, HINT_SELECTED,
+            HINT_SOURCE, HINT_MESSAGE, HINT_HORIZONTAL, HINT_NO_TINT, HINT_PARTIAL})
+    public @interface SliceHint{ }
+
+    /**
+     * Hint that this content is a title of other content in the slice.
+     */
+    public static final String HINT_TITLE       = "title";
+    /**
+     * Hint that all sub-items/sub-slices within this content should be considered
+     * to have {@link #HINT_LIST_ITEM}.
+     */
+    public static final String HINT_LIST        = "list";
+    /**
+     * Hint that this item is part of a list and should be formatted as if is part
+     * of a list.
+     */
+    public static final String HINT_LIST_ITEM   = "list_item";
+    /**
+     * Hint that this content is important and should be larger when displayed if
+     * possible.
+     */
+    public static final String HINT_LARGE       = "large";
+    /**
+     * Hint that this slice contains a number of actions that can be grouped together
+     * in a sort of controls area of the UI.
+     */
+    public static final String HINT_ACTIONS     = "actions";
+    /**
+     * Hint indicating that this item (and its sub-items) are the current selection.
+     */
+    public static final String HINT_SELECTED    = "selected";
+    /**
+     * Hint to indicate that this is a message as part of a communication
+     * sequence in this slice.
+     */
+    public static final String HINT_MESSAGE     = "message";
+    /**
+     * Hint to tag the source (i.e. sender) of a {@link #HINT_MESSAGE}.
+     */
+    public static final String HINT_SOURCE      = "source";
+    /**
+     * Hint that list items within this slice or subslice would appear better
+     * if organized horizontally.
+     */
+    public static final String HINT_HORIZONTAL  = "horizontal";
+    /**
+     * Hint to indicate that this content should not be tinted.
+     */
+    public static final String HINT_NO_TINT     = "no_tint";
+    /**
+     * Hint to indicate that this slice is incomplete and an update will be sent once
+     * loading is complete. Slices which contain HINT_PARTIAL will not be cached by the
+     * OS and should not be cached by apps.
+     */
+    public static final String HINT_PARTIAL     = "partial";
+
+    // These two are coming over from prototyping, but we probably don't want in
+    // public API, at least not right now.
+    /**
+     * @hide
+     */
+    public static final String HINT_ALT         = "alt";
+
+    private final SliceItem[] mItems;
+    private final @SliceHint String[] mHints;
+    private Uri mUri;
+
+    Slice(ArrayList<SliceItem> items, @SliceHint String[] hints, Uri uri) {
+        mHints = hints;
+        mItems = items.toArray(new SliceItem[items.size()]);
+        mUri = uri;
+    }
+
+    protected Slice(Parcel in) {
+        mHints = in.readStringArray();
+        int n = in.readInt();
+        mItems = new SliceItem[n];
+        for (int i = 0; i < n; i++) {
+            mItems[i] = SliceItem.CREATOR.createFromParcel(in);
+        }
+        mUri = Uri.CREATOR.createFromParcel(in);
+    }
+
+    /**
+     * @return The Uri that this Slice represents.
+     */
+    public Uri getUri() {
+        return mUri;
+    }
+
+    /**
+     * @return All child {@link SliceItem}s that this Slice contains.
+     */
+    public List<SliceItem> getItems() {
+        return Arrays.asList(mItems);
+    }
+
+    /**
+     * @return All hints associated with this Slice.
+     */
+    public @SliceHint List<String> getHints() {
+        return Arrays.asList(mHints);
+    }
+
+    /**
+     * @hide
+     */
+    public SliceItem getPrimaryIcon() {
+        for (SliceItem item : getItems()) {
+            if (item.getType() == SliceItem.TYPE_IMAGE) {
+                return item;
+            }
+            if (!(item.getType() == SliceItem.TYPE_SLICE && item.hasHint(Slice.HINT_LIST))
+                    && !item.hasHint(Slice.HINT_ACTIONS)
+                    && !item.hasHint(Slice.HINT_LIST_ITEM)
+                    && (item.getType() != SliceItem.TYPE_ACTION)) {
+                SliceItem icon = SliceQuery.find(item, SliceItem.TYPE_IMAGE);
+                if (icon != null) return icon;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeStringArray(mHints);
+        dest.writeInt(mItems.length);
+        for (int i = 0; i < mItems.length; i++) {
+            mItems[i].writeToParcel(dest, flags);
+        }
+        mUri.writeToParcel(dest, 0);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * @hide
+     */
+    public boolean hasHint(@SliceHint String hint) {
+        return ArrayUtils.contains(mHints, hint);
+    }
+
+    /**
+     * A Builder used to construct {@link Slice}s
+     */
+    public static class Builder {
+
+        private final Uri mUri;
+        private ArrayList<SliceItem> mItems = new ArrayList<>();
+        private @SliceHint ArrayList<String> mHints = new ArrayList<>();
+
+        /**
+         * Create a builder which will construct a {@link Slice} for the Given Uri.
+         * @param uri Uri to tag for this slice.
+         */
+        public Builder(@NonNull Uri uri) {
+            mUri = uri;
+        }
+
+        /**
+         * Create a builder for a {@link Slice} that is a sub-slice of the slice
+         * being constructed by the provided builder.
+         * @param parent The builder constructing the parent slice
+         */
+        public Builder(@NonNull Slice.Builder parent) {
+            mUri = parent.mUri.buildUpon().appendPath("_gen")
+                    .appendPath(String.valueOf(mItems.size())).build();
+        }
+
+        /**
+         * Add hints to the Slice being constructed
+         */
+        public Builder addHints(@SliceHint String... hints) {
+            mHints.addAll(Arrays.asList(hints));
+            return this;
+        }
+
+        /**
+         * Add hints to the Slice being constructed
+         */
+        public Builder addHints(@SliceHint List<String> hints) {
+            return addHints(hints.toArray(new String[hints.size()]));
+        }
+
+        /**
+         * Add a sub-slice to the slice being constructed
+         */
+        public Builder addSubSlice(@NonNull Slice slice) {
+            mItems.add(new SliceItem(slice, SliceItem.TYPE_SLICE, slice.getHints().toArray(
+                    new String[slice.getHints().size()])));
+            return this;
+        }
+
+        /**
+         * Add an action to the slice being constructed
+         */
+        public Slice.Builder addAction(@NonNull PendingIntent action, @NonNull Slice s) {
+            mItems.add(new SliceItem(action, s, SliceItem.TYPE_ACTION, new String[0]));
+            return this;
+        }
+
+        /**
+         * Add text to the slice being constructed
+         */
+        public Builder addText(CharSequence text, @SliceHint String... hints) {
+            mItems.add(new SliceItem(text, SliceItem.TYPE_TEXT, hints));
+            return this;
+        }
+
+        /**
+         * Add text to the slice being constructed
+         */
+        public Builder addText(CharSequence text, @SliceHint List<String> hints) {
+            return addText(text, hints.toArray(new String[hints.size()]));
+        }
+
+        /**
+         * Add an image to the slice being constructed
+         */
+        public Builder addIcon(Icon icon, @SliceHint String... hints) {
+            mItems.add(new SliceItem(icon, SliceItem.TYPE_IMAGE, hints));
+            return this;
+        }
+
+        /**
+         * Add an image to the slice being constructed
+         */
+        public Builder addIcon(Icon icon, @SliceHint List<String> hints) {
+            return addIcon(icon, hints.toArray(new String[hints.size()]));
+        }
+
+        /**
+         * @hide This isn't final
+         */
+        public Builder addRemoteView(RemoteViews remoteView, @SliceHint String... hints) {
+            mItems.add(new SliceItem(remoteView, SliceItem.TYPE_REMOTE_VIEW, hints));
+            return this;
+        }
+
+        /**
+         * Add remote input to the slice being constructed
+         */
+        public Slice.Builder addRemoteInput(RemoteInput remoteInput,
+                @SliceHint List<String> hints) {
+            return addRemoteInput(remoteInput, hints.toArray(new String[hints.size()]));
+        }
+
+        /**
+         * Add remote input to the slice being constructed
+         */
+        public Slice.Builder addRemoteInput(RemoteInput remoteInput, @SliceHint String... hints) {
+            mItems.add(new SliceItem(remoteInput, SliceItem.TYPE_REMOTE_INPUT, hints));
+            return this;
+        }
+
+        /**
+         * Add a color to the slice being constructed
+         */
+        public Builder addColor(int color, @SliceHint String... hints) {
+            mItems.add(new SliceItem(color, SliceItem.TYPE_COLOR, hints));
+            return this;
+        }
+
+        /**
+         * Add a color to the slice being constructed
+         */
+        public Builder addColor(int color, @SliceHint List<String> hints) {
+            return addColor(color, hints.toArray(new String[hints.size()]));
+        }
+
+        /**
+         * Add a timestamp to the slice being constructed
+         */
+        public Slice.Builder addTimestamp(long time, @SliceHint String... hints) {
+            mItems.add(new SliceItem(time, SliceItem.TYPE_TIMESTAMP, hints));
+            return this;
+        }
+
+        /**
+         * Add a timestamp to the slice being constructed
+         */
+        public Slice.Builder addTimestamp(long time, @SliceHint List<String> hints) {
+            return addTimestamp(time, hints.toArray(new String[hints.size()]));
+        }
+
+        /**
+         * Construct the slice.
+         */
+        public Slice build() {
+            return new Slice(mItems, mHints.toArray(new String[mHints.size()]), mUri);
+        }
+    }
+
+    public static final Creator<Slice> CREATOR = new Creator<Slice>() {
+        @Override
+        public Slice createFromParcel(Parcel in) {
+            return new Slice(in);
+        }
+
+        @Override
+        public Slice[] newArray(int size) {
+            return new Slice[size];
+        }
+    };
+
+    /**
+     * @hide
+     * @return A string representation of this slice.
+     */
+    public String toString() {
+        return toString("");
+    }
+
+    private String toString(String indent) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < mItems.length; i++) {
+            sb.append(indent);
+            if (mItems[i].getType() == SliceItem.TYPE_SLICE) {
+                sb.append("slice:\n");
+                sb.append(mItems[i].getSlice().toString(indent + "   "));
+            } else if (mItems[i].getType() == SliceItem.TYPE_TEXT) {
+                sb.append("text: ");
+                sb.append(mItems[i].getText());
+                sb.append("\n");
+            } else {
+                sb.append(SliceItem.typeToString(mItems[i].getType()));
+                sb.append("\n");
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Turns a slice Uri into slice content.
+     *
+     * @param resolver ContentResolver to be used.
+     * @param uri The URI to a slice provider
+     * @return The Slice provided by the app or null if none is given.
+     * @see Slice
+     */
+    public static @Nullable Slice bindSlice(ContentResolver resolver, @NonNull Uri uri) {
+        Preconditions.checkNotNull(uri, "uri");
+        IContentProvider provider = resolver.acquireProvider(uri);
+        if (provider == null) {
+            throw new IllegalArgumentException("Unknown URI " + uri);
+        }
+        try {
+            Bundle extras = new Bundle();
+            extras.putParcelable(SliceProvider.EXTRA_BIND_URI, uri);
+            final Bundle res = provider.call(resolver.getPackageName(), SliceProvider.METHOD_SLICE,
+                    null, extras);
+            Bundle.setDefusable(res, true);
+            return res.getParcelable(SliceProvider.EXTRA_SLICE);
+        } catch (RemoteException e) {
+            // Arbitrary and not worth documenting, as Activity
+            // Manager will kill this process shortly anyway.
+            return null;
+        } finally {
+            resolver.releaseProvider(provider);
+        }
+    }
+}
diff --git a/core/java/android/app/slice/SliceItem.java b/core/java/android/app/slice/SliceItem.java
new file mode 100644
index 0000000..6e69b05
--- /dev/null
+++ b/core/java/android/app/slice/SliceItem.java
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.slice;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.app.PendingIntent;
+import android.app.RemoteInput;
+import android.graphics.drawable.Icon;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Pair;
+import android.widget.RemoteViews;
+
+import com.android.internal.util.ArrayUtils;
+
+import java.util.Arrays;
+import java.util.List;
+
+
+/**
+ * A SliceItem is a single unit in the tree structure of a {@link Slice}.
+ *
+ * A SliceItem a piece of content and some hints about what that content
+ * means or how it should be displayed. The types of content can be:
+ * <li>{@link #TYPE_SLICE}</li>
+ * <li>{@link #TYPE_TEXT}</li>
+ * <li>{@link #TYPE_IMAGE}</li>
+ * <li>{@link #TYPE_ACTION}</li>
+ * <li>{@link #TYPE_COLOR}</li>
+ * <li>{@link #TYPE_TIMESTAMP}</li>
+ * <li>{@link #TYPE_REMOTE_INPUT}</li>
+ *
+ * The hints that a {@link SliceItem} are a set of strings which annotate
+ * the content. The hints that are guaranteed to be understood by the system
+ * are defined on {@link Slice}.
+ */
+public final class SliceItem implements Parcelable {
+
+    /**
+     * @hide
+     */
+    @IntDef({TYPE_SLICE, TYPE_TEXT, TYPE_IMAGE, TYPE_ACTION, TYPE_COLOR,
+            TYPE_TIMESTAMP, TYPE_REMOTE_INPUT})
+    public @interface SliceType {}
+
+    /**
+     * A {@link SliceItem} that contains a {@link Slice}
+     */
+    public static final int TYPE_SLICE        = 1;
+    /**
+     * A {@link SliceItem} that contains a {@link CharSequence}
+     */
+    public static final int TYPE_TEXT         = 2;
+    /**
+     * A {@link SliceItem} that contains an {@link Icon}
+     */
+    public static final int TYPE_IMAGE        = 3;
+    /**
+     * A {@link SliceItem} that contains a {@link PendingIntent}
+     *
+     * Note: Actions contain 2 pieces of data, In addition to the pending intent, the
+     * item contains a {@link Slice} that the action applies to.
+     */
+    public static final int TYPE_ACTION       = 4;
+    /**
+     * @hide This isn't final
+     */
+    public static final int TYPE_REMOTE_VIEW  = 5;
+    /**
+     * A {@link SliceItem} that contains a Color int.
+     */
+    public static final int TYPE_COLOR        = 6;
+    /**
+     * A {@link SliceItem} that contains a timestamp.
+     */
+    public static final int TYPE_TIMESTAMP    = 8;
+    /**
+     * A {@link SliceItem} that contains a {@link RemoteInput}.
+     */
+    public static final int TYPE_REMOTE_INPUT = 9;
+
+    /**
+     * @hide
+     */
+    protected @Slice.SliceHint
+    String[] mHints;
+    private final int mType;
+    private final Object mObj;
+
+    /**
+     * @hide
+     */
+    public SliceItem(Object obj, @SliceType int type, @Slice.SliceHint String[] hints) {
+        mHints = hints;
+        mType = type;
+        mObj = obj;
+    }
+
+    /**
+     * @hide
+     */
+    public SliceItem(PendingIntent intent, Slice slice, int type, @Slice.SliceHint String[] hints) {
+        this(new Pair<>(intent, slice), type, hints);
+    }
+
+    /**
+     * Gets all hints associated with this SliceItem.
+     * @return Array of hints.
+     */
+    public @NonNull @Slice.SliceHint List<String> getHints() {
+        return Arrays.asList(mHints);
+    }
+
+    /**
+     * @hide
+     */
+    public void addHint(@Slice.SliceHint String hint) {
+        mHints = ArrayUtils.appendElement(String.class, mHints, hint);
+    }
+
+    /**
+     * @hide
+     */
+    public void removeHint(String hint) {
+        ArrayUtils.removeElement(String.class, mHints, hint);
+    }
+
+    public @SliceType int getType() {
+        return mType;
+    }
+
+    /**
+     * @return The text held by this {@link #TYPE_TEXT} SliceItem
+     */
+    public CharSequence getText() {
+        return (CharSequence) mObj;
+    }
+
+    /**
+     * @return The icon held by this {@link #TYPE_IMAGE} SliceItem
+     */
+    public Icon getIcon() {
+        return (Icon) mObj;
+    }
+
+    /**
+     * @return The pending intent held by this {@link #TYPE_ACTION} SliceItem
+     */
+    public PendingIntent getAction() {
+        return ((Pair<PendingIntent, Slice>) mObj).first;
+    }
+
+    /**
+     * @hide This isn't final
+     */
+    public RemoteViews getRemoteView() {
+        return (RemoteViews) mObj;
+    }
+
+    /**
+     * @return The remote input held by this {@link #TYPE_REMOTE_INPUT} SliceItem
+     */
+    public RemoteInput getRemoteInput() {
+        return (RemoteInput) mObj;
+    }
+
+    /**
+     * @return The color held by this {@link #TYPE_COLOR} SliceItem
+     */
+    public int getColor() {
+        return (Integer) mObj;
+    }
+
+    /**
+     * @return The slice held by this {@link #TYPE_ACTION} or {@link #TYPE_SLICE} SliceItem
+     */
+    public Slice getSlice() {
+        if (getType() == TYPE_ACTION) {
+            return ((Pair<PendingIntent, Slice>) mObj).second;
+        }
+        return (Slice) mObj;
+    }
+
+    /**
+     * @return The timestamp held by this {@link #TYPE_TIMESTAMP} SliceItem
+     */
+    public long getTimestamp() {
+        return (Long) mObj;
+    }
+
+    /**
+     * @param hint The hint to check for
+     * @return true if this item contains the given hint
+     */
+    public boolean hasHint(@Slice.SliceHint String hint) {
+        return ArrayUtils.contains(mHints, hint);
+    }
+
+    /**
+     * @hide
+     */
+    public SliceItem(Parcel in) {
+        mHints = in.readStringArray();
+        mType = in.readInt();
+        mObj = readObj(mType, in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeStringArray(mHints);
+        dest.writeInt(mType);
+        writeObj(dest, flags, mObj, mType);
+    }
+
+    /**
+     * @hide
+     */
+    public boolean hasHints(@Slice.SliceHint String[] hints) {
+        if (hints == null) return true;
+        for (String hint : hints) {
+            if (!TextUtils.isEmpty(hint) && !ArrayUtils.contains(mHints, hint)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * @hide
+     */
+    public boolean hasAnyHints(@Slice.SliceHint String[] hints) {
+        if (hints == null) return false;
+        for (String hint : hints) {
+            if (ArrayUtils.contains(mHints, hint)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void writeObj(Parcel dest, int flags, Object obj, int type) {
+        switch (type) {
+            case TYPE_SLICE:
+            case TYPE_REMOTE_VIEW:
+            case TYPE_IMAGE:
+            case TYPE_REMOTE_INPUT:
+                ((Parcelable) obj).writeToParcel(dest, flags);
+                break;
+            case TYPE_ACTION:
+                ((Pair<PendingIntent, Slice>) obj).first.writeToParcel(dest, flags);
+                ((Pair<PendingIntent, Slice>) obj).second.writeToParcel(dest, flags);
+                break;
+            case TYPE_TEXT:
+                TextUtils.writeToParcel((CharSequence) mObj, dest, flags);
+                break;
+            case TYPE_COLOR:
+                dest.writeInt((Integer) mObj);
+                break;
+            case TYPE_TIMESTAMP:
+                dest.writeLong((Long) mObj);
+                break;
+        }
+    }
+
+    private static Object readObj(int type, Parcel in) {
+        switch (type) {
+            case TYPE_SLICE:
+                return Slice.CREATOR.createFromParcel(in);
+            case TYPE_TEXT:
+                return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+            case TYPE_IMAGE:
+                return Icon.CREATOR.createFromParcel(in);
+            case TYPE_ACTION:
+                return new Pair<PendingIntent, Slice>(
+                        PendingIntent.CREATOR.createFromParcel(in),
+                        Slice.CREATOR.createFromParcel(in));
+            case TYPE_REMOTE_VIEW:
+                return RemoteViews.CREATOR.createFromParcel(in);
+            case TYPE_COLOR:
+                return in.readInt();
+            case TYPE_TIMESTAMP:
+                return in.readLong();
+            case TYPE_REMOTE_INPUT:
+                return RemoteInput.CREATOR.createFromParcel(in);
+        }
+        throw new RuntimeException("Unsupported type " + type);
+    }
+
+    public static final Creator<SliceItem> CREATOR = new Creator<SliceItem>() {
+        @Override
+        public SliceItem createFromParcel(Parcel in) {
+            return new SliceItem(in);
+        }
+
+        @Override
+        public SliceItem[] newArray(int size) {
+            return new SliceItem[size];
+        }
+    };
+
+    /**
+     * @hide
+     */
+    public static String typeToString(int type) {
+        switch (type) {
+            case TYPE_SLICE:
+                return "Slice";
+            case TYPE_TEXT:
+                return "Text";
+            case TYPE_IMAGE:
+                return "Image";
+            case TYPE_ACTION:
+                return "Action";
+            case TYPE_REMOTE_VIEW:
+                return "RemoteView";
+            case TYPE_COLOR:
+                return "Color";
+            case TYPE_TIMESTAMP:
+                return "Timestamp";
+            case TYPE_REMOTE_INPUT:
+                return "RemoteInput";
+        }
+        return "Unrecognized type: " + type;
+    }
+}
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
new file mode 100644
index 0000000..df87b45
--- /dev/null
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.slice;
+
+import android.Manifest.permission;
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.StrictMode;
+import android.os.StrictMode.ThreadPolicy;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * A SliceProvider allows app to provide content to be displayed in system
+ * spaces. This content is templated and can contain actions, and the behavior
+ * of how it is surfaced is specific to the system surface.
+ *
+ * <p>Slices are not currently live content. They are bound once and shown to the
+ * user. If the content changes due to a callback from user interaction, then
+ * {@link ContentResolver#notifyChange(Uri, ContentObserver)}
+ * should be used to notify the system.</p>
+ *
+ * <p>The provider needs to be declared in the manifest to provide the authority
+ * for the app. The authority for most slices is expected to match the package
+ * of the application.</p>
+ * <pre class="prettyprint">
+ * {@literal
+ * <provider
+ *     android:name="com.android.mypkg.MySliceProvider"
+ *     android:authorities="com.android.mypkg" />}
+ * </pre>
+ *
+ * @see Slice
+ */
+public abstract class SliceProvider extends ContentProvider {
+
+    /**
+     * This is the Android platform's MIME type for a slice: URI
+     * containing a slice implemented through {@link SliceProvider}.
+     */
+    public static final String SLICE_TYPE = "vnd.android.slice";
+
+    private static final String TAG = "SliceProvider";
+    /**
+     * @hide
+     */
+    public static final String EXTRA_BIND_URI = "slice_uri";
+    /**
+     * @hide
+     */
+    public static final String METHOD_SLICE = "bind_slice";
+    /**
+     * @hide
+     */
+    public static final String EXTRA_SLICE = "slice";
+
+    private static final boolean DEBUG = false;
+
+    /**
+     * Implemented to create a slice. Will be called on the main thread.
+     * <p>
+     * onBindSlice should return as quickly as possible so that the UI tied
+     * to this slice can be responsive. No network or other IO will be allowed
+     * during onBindSlice. Any loading that needs to be done should happen
+     * off the main thread with a call to {@link ContentResolver#notifyChange(Uri, ContentObserver)}
+     * when the app is ready to provide the complete data in onBindSlice.
+     * <p>
+     *
+     * @see {@link Slice}.
+     * @see {@link Slice#HINT_PARTIAL}
+     */
+    // TODO: Provide alternate notifyChange that takes in the slice (i.e. notifyChange(Uri, Slice)).
+    public abstract Slice onBindSlice(Uri sliceUri);
+
+    @Override
+    public final int update(Uri uri, ContentValues values, String selection,
+            String[] selectionArgs) {
+        if (DEBUG) Log.d(TAG, "update " + uri);
+        return 0;
+    }
+
+    @Override
+    public final int delete(Uri uri, String selection, String[] selectionArgs) {
+        if (DEBUG) Log.d(TAG, "delete " + uri);
+        return 0;
+    }
+
+    @Override
+    public final Cursor query(Uri uri, String[] projection, String selection,
+            String[] selectionArgs, String sortOrder) {
+        if (DEBUG) Log.d(TAG, "query " + uri);
+        return null;
+    }
+
+    @Override
+    public final Cursor query(Uri uri, String[] projection, String selection, String[]
+            selectionArgs, String sortOrder, CancellationSignal cancellationSignal) {
+        if (DEBUG) Log.d(TAG, "query " + uri);
+        return null;
+    }
+
+    @Override
+    public final Cursor query(Uri uri, String[] projection, Bundle queryArgs,
+            CancellationSignal cancellationSignal) {
+        if (DEBUG) Log.d(TAG, "query " + uri);
+        return null;
+    }
+
+    @Override
+    public final Uri insert(Uri uri, ContentValues values) {
+        if (DEBUG) Log.d(TAG, "insert " + uri);
+        return null;
+    }
+
+    @Override
+    public final String getType(Uri uri) {
+        if (DEBUG) Log.d(TAG, "getType " + uri);
+        return SLICE_TYPE;
+    }
+
+    @Override
+    public Bundle call(String method, String arg, Bundle extras) {
+        if (method.equals(METHOD_SLICE)) {
+            getContext().enforceCallingPermission(permission.BIND_SLICE,
+                    "Slice binding requires the permission BIND_SLICE");
+            Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+
+            Slice s = handleBindSlice(uri);
+            Bundle b = new Bundle();
+            b.putParcelable(EXTRA_SLICE, s);
+            return b;
+        }
+        return super.call(method, arg, extras);
+    }
+
+    private Slice handleBindSlice(Uri sliceUri) {
+        Slice[] output = new Slice[1];
+        CountDownLatch latch = new CountDownLatch(1);
+        Handler mainHandler = new Handler(Looper.getMainLooper());
+        mainHandler.post(() -> {
+            ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
+            try {
+                StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
+                        .detectAll()
+                        .penaltyDeath()
+                        .build());
+                output[0] = onBindSlice(sliceUri);
+            } finally {
+                StrictMode.setThreadPolicy(oldPolicy);
+                latch.countDown();
+            }
+        });
+        try {
+            latch.await();
+            return output[0];
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/core/java/android/app/slice/SliceQuery.java b/core/java/android/app/slice/SliceQuery.java
new file mode 100644
index 0000000..d1fe2c9
--- /dev/null
+++ b/core/java/android/app/slice/SliceQuery.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.slice;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.Spliterators;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+/**
+ * A bunch of utilities for searching the contents of a slice.
+ * @hide
+ */
+public class SliceQuery {
+    private static final String TAG = "SliceQuery";
+
+    /**
+     * @hide
+     */
+    public static SliceItem findNotContaining(SliceItem container, List<SliceItem> list) {
+        SliceItem ret = null;
+        while (ret == null && list.size() != 0) {
+            SliceItem remove = list.remove(0);
+            if (!contains(container, remove)) {
+                ret = remove;
+            }
+        }
+        return ret;
+    }
+
+    /**
+     * @hide
+     */
+    private static boolean contains(SliceItem container, SliceItem item) {
+        if (container == null || item == null) return false;
+        return stream(container).filter(s -> (s == item)).findAny().isPresent();
+    }
+
+    /**
+     * @hide
+     */
+    public static List<SliceItem> findAll(SliceItem s, int type) {
+        return findAll(s, type, (String[]) null, null);
+    }
+
+    /**
+     * @hide
+     */
+    public static List<SliceItem> findAll(SliceItem s, int type, String hints, String nonHints) {
+        return findAll(s, type, new String[]{ hints }, new String[]{ nonHints });
+    }
+
+    /**
+     * @hide
+     */
+    public static List<SliceItem> findAll(SliceItem s, int type, String[] hints,
+            String[] nonHints) {
+        return stream(s).filter(item -> (type == -1 || item.getType() == type)
+                && (item.hasHints(hints) && !item.hasAnyHints(nonHints)))
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * @hide
+     */
+    public static SliceItem find(Slice s, int type, String hints, String nonHints) {
+        return find(s, type, new String[]{ hints }, new String[]{ nonHints });
+    }
+
+    /**
+     * @hide
+     */
+    public static SliceItem find(Slice s, int type) {
+        return find(s, type, (String[]) null, null);
+    }
+
+    /**
+     * @hide
+     */
+    public static SliceItem find(SliceItem s, int type) {
+        return find(s, type, (String[]) null, null);
+    }
+
+    /**
+     * @hide
+     */
+    public static SliceItem find(SliceItem s, int type, String hints, String nonHints) {
+        return find(s, type, new String[]{ hints }, new String[]{ nonHints });
+    }
+
+    /**
+     * @hide
+     */
+    public static SliceItem find(Slice s, int type, String[] hints, String[] nonHints) {
+        List<String> h = s.getHints();
+        return find(new SliceItem(s, SliceItem.TYPE_SLICE, h.toArray(new String[h.size()])), type,
+                hints, nonHints);
+    }
+
+    /**
+     * @hide
+     */
+    public static SliceItem find(SliceItem s, int type, String[] hints, String[] nonHints) {
+        return stream(s).filter(item -> (item.getType() == type || type == -1)
+                && (item.hasHints(hints) && !item.hasAnyHints(nonHints))).findFirst().orElse(null);
+    }
+
+    /**
+     * @hide
+     */
+    public static Stream<SliceItem> stream(SliceItem slice) {
+        Queue<SliceItem> items = new LinkedList();
+        items.add(slice);
+        Iterator<SliceItem> iterator = new Iterator<SliceItem>() {
+            @Override
+            public boolean hasNext() {
+                return items.size() != 0;
+            }
+
+            @Override
+            public SliceItem next() {
+                SliceItem item = items.poll();
+                if (item.getType() == SliceItem.TYPE_SLICE
+                        || item.getType() == SliceItem.TYPE_ACTION) {
+                    items.addAll(item.getSlice().getItems());
+                }
+                return item;
+            }
+        };
+        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);
+    }
+}
diff --git a/core/java/android/app/slice/views/ActionRow.java b/core/java/android/app/slice/views/ActionRow.java
new file mode 100644
index 0000000..c7d99f7
--- /dev/null
+++ b/core/java/android/app/slice/views/ActionRow.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.slice.views;
+
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.app.RemoteInput;
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
+import android.app.slice.SliceQuery;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.graphics.drawable.Icon;
+import android.os.AsyncTask;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewParent;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/**
+ * @hide
+ */
+public class ActionRow extends FrameLayout {
+
+    private static final int MAX_ACTIONS = 5;
+    private final int mSize;
+    private final int mIconPadding;
+    private final LinearLayout mActionsGroup;
+    private final boolean mFullActions;
+    private int mColor = Color.BLACK;
+
+    public ActionRow(Context context, boolean fullActions) {
+        super(context);
+        mFullActions = fullActions;
+        mSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48,
+                context.getResources().getDisplayMetrics());
+        mIconPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 12,
+                context.getResources().getDisplayMetrics());
+        mActionsGroup = new LinearLayout(context);
+        mActionsGroup.setOrientation(LinearLayout.HORIZONTAL);
+        mActionsGroup.setLayoutParams(
+                new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
+        addView(mActionsGroup);
+    }
+
+    private void setColor(int color) {
+        mColor = color;
+        for (int i = 0; i < mActionsGroup.getChildCount(); i++) {
+            View view = mActionsGroup.getChildAt(i);
+            SliceItem item = (SliceItem) view.getTag();
+            boolean tint = !item.hasHint(Slice.HINT_NO_TINT);
+            if (tint) {
+                ((ImageView) view).setImageTintList(ColorStateList.valueOf(mColor));
+            }
+        }
+    }
+
+    private ImageView addAction(Icon icon, boolean allowTint, SliceItem image) {
+        ImageView imageView = new ImageView(getContext());
+        imageView.setPadding(mIconPadding, mIconPadding, mIconPadding, mIconPadding);
+        imageView.setScaleType(ScaleType.FIT_CENTER);
+        imageView.setImageIcon(icon);
+        if (allowTint) {
+            imageView.setImageTintList(ColorStateList.valueOf(mColor));
+        }
+        imageView.setBackground(SliceViewUtil.getDrawable(getContext(),
+                android.R.attr.selectableItemBackground));
+        imageView.setTag(image);
+        addAction(imageView);
+        return imageView;
+    }
+
+    /**
+     * Set the actions and color for this action row.
+     */
+    public void setActions(SliceItem actionRow, SliceItem defColor) {
+        removeAllViews();
+        mActionsGroup.removeAllViews();
+        addView(mActionsGroup);
+
+        SliceItem color = SliceQuery.find(actionRow, SliceItem.TYPE_COLOR);
+        if (color == null) {
+            color = defColor;
+        }
+        if (color != null) {
+            setColor(color.getColor());
+        }
+        SliceQuery.findAll(actionRow, SliceItem.TYPE_ACTION).forEach(action -> {
+            if (mActionsGroup.getChildCount() >= MAX_ACTIONS) {
+                return;
+            }
+            SliceItem image = SliceQuery.find(action, SliceItem.TYPE_IMAGE);
+            if (image == null) {
+                return;
+            }
+            boolean tint = !image.hasHint(Slice.HINT_NO_TINT);
+            SliceItem input = SliceQuery.find(action, SliceItem.TYPE_REMOTE_INPUT);
+            if (input != null && input.getRemoteInput().getAllowFreeFormInput()) {
+                addAction(image.getIcon(), tint, image).setOnClickListener(
+                        v -> handleRemoteInputClick(v, action.getAction(), input.getRemoteInput()));
+                createRemoteInputView(mColor, getContext());
+            } else {
+                addAction(image.getIcon(), tint, image).setOnClickListener(v -> AsyncTask.execute(
+                        () -> {
+                            try {
+                                action.getAction().send();
+                            } catch (CanceledException e) {
+                                e.printStackTrace();
+                            }
+                        }));
+            }
+        });
+        setVisibility(getChildCount() != 0 ? View.VISIBLE : View.GONE);
+    }
+
+    private void addAction(View child) {
+        mActionsGroup.addView(child, new LinearLayout.LayoutParams(mSize, mSize, 1));
+    }
+
+    private void createRemoteInputView(int color, Context context) {
+        View riv = RemoteInputView.inflate(context, this);
+        riv.setVisibility(View.INVISIBLE);
+        addView(riv, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+        riv.setBackgroundColor(color);
+    }
+
+    private boolean handleRemoteInputClick(View view, PendingIntent pendingIntent,
+            RemoteInput input) {
+        if (input == null) {
+            return false;
+        }
+
+        ViewParent p = view.getParent().getParent();
+        RemoteInputView riv = null;
+        while (p != null) {
+            if (p instanceof View) {
+                View pv = (View) p;
+                riv = findRemoteInputView(pv);
+                if (riv != null) {
+                    break;
+                }
+            }
+            p = p.getParent();
+        }
+        if (riv == null) {
+            return false;
+        }
+
+        int width = view.getWidth();
+        if (view instanceof TextView) {
+            // Center the reveal on the text which might be off-center from the TextView
+            TextView tv = (TextView) view;
+            if (tv.getLayout() != null) {
+                int innerWidth = (int) tv.getLayout().getLineWidth(0);
+                innerWidth += tv.getCompoundPaddingLeft() + tv.getCompoundPaddingRight();
+                width = Math.min(width, innerWidth);
+            }
+        }
+        int cx = view.getLeft() + width / 2;
+        int cy = view.getTop() + view.getHeight() / 2;
+        int w = riv.getWidth();
+        int h = riv.getHeight();
+        int r = Math.max(
+                Math.max(cx + cy, cx + (h - cy)),
+                Math.max((w - cx) + cy, (w - cx) + (h - cy)));
+
+        riv.setRevealParameters(cx, cy, r);
+        riv.setPendingIntent(pendingIntent);
+        riv.setRemoteInput(new RemoteInput[] {
+                input
+        }, input);
+        riv.focusAnimated();
+        return true;
+    }
+
+    private RemoteInputView findRemoteInputView(View v) {
+        if (v == null) {
+            return null;
+        }
+        return (RemoteInputView) v.findViewWithTag(RemoteInputView.VIEW_TAG);
+    }
+}
diff --git a/core/java/android/app/slice/views/GridView.java b/core/java/android/app/slice/views/GridView.java
new file mode 100644
index 0000000..6f30c50
--- /dev/null
+++ b/core/java/android/app/slice/views/GridView.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.slice.views;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
+import android.app.slice.views.LargeSliceAdapter.SliceListView;
+import android.content.Context;
+import android.graphics.Color;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.internal.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @hide
+ */
+public class GridView extends LinearLayout implements SliceListView {
+
+    private static final String TAG = "GridView";
+
+    private static final int MAX_IMAGES = 3;
+    private static final int MAX_ALL = 5;
+    private boolean mIsAllImages;
+
+    public GridView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (mIsAllImages) {
+            int width = MeasureSpec.getSize(widthMeasureSpec);
+            int height = width / getChildCount();
+            heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.EXACTLY,
+                    height);
+            getLayoutParams().height = height;
+            for (int i = 0; i < getChildCount(); i++) {
+                getChildAt(i).getLayoutParams().height = height;
+            }
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    @Override
+    public void setSliceItem(SliceItem slice) {
+        mIsAllImages = true;
+        removeAllViews();
+        int total = 1;
+        if (slice.getType() == SliceItem.TYPE_SLICE) {
+            List<SliceItem> items = slice.getSlice().getItems();
+            total = items.size();
+            for (int i = 0; i < total; i++) {
+                SliceItem item = items.get(i);
+                if (isFull()) {
+                    continue;
+                }
+                if (!addItem(item)) {
+                    mIsAllImages = false;
+                }
+            }
+        } else {
+            if (!isFull()) {
+                if (!addItem(slice)) {
+                    mIsAllImages = false;
+                }
+            }
+        }
+        if (total > getChildCount() && mIsAllImages) {
+            addExtraCount(total - getChildCount());
+        }
+    }
+
+    private void addExtraCount(int numExtra) {
+        View last = getChildAt(getChildCount() - 1);
+        FrameLayout frame = new FrameLayout(getContext());
+        frame.setLayoutParams(last.getLayoutParams());
+
+        removeView(last);
+        frame.addView(last, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
+
+        TextView v = new TextView(getContext());
+        v.setTextColor(Color.WHITE);
+        v.setBackgroundColor(0x4d000000);
+        v.setText(getResources().getString(R.string.slice_more_content, numExtra));
+        v.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
+        v.setGravity(Gravity.CENTER);
+        frame.addView(v, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
+
+        addView(frame);
+    }
+
+    private boolean isFull() {
+        return getChildCount() >= (mIsAllImages ? MAX_IMAGES : MAX_ALL);
+    }
+
+    /**
+     * Returns true if this item is just an image.
+     */
+    private boolean addItem(SliceItem item) {
+        if (item.getType() == SliceItem.TYPE_IMAGE) {
+            ImageView v = new ImageView(getContext());
+            v.setImageIcon(item.getIcon());
+            v.setScaleType(ScaleType.CENTER_CROP);
+            addView(v, new LayoutParams(0, MATCH_PARENT, 1));
+            return true;
+        } else {
+            LinearLayout v = new LinearLayout(getContext());
+            int s = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                    12, getContext().getResources().getDisplayMetrics());
+            v.setPadding(0, s, 0, 0);
+            v.setOrientation(LinearLayout.VERTICAL);
+            v.setGravity(Gravity.CENTER_HORIZONTAL);
+            // TODO: Unify sporadic inflates that happen throughout the code.
+            ArrayList<SliceItem> items = new ArrayList<>();
+            if (item.getType() == SliceItem.TYPE_SLICE) {
+                items.addAll(item.getSlice().getItems());
+            }
+            items.forEach(i -> {
+                Context context = getContext();
+                switch (i.getType()) {
+                    case SliceItem.TYPE_TEXT:
+                        boolean title = false;
+                        if ((item.hasAnyHints(new String[] {
+                                Slice.HINT_LARGE, Slice.HINT_TITLE
+                        }))) {
+                            title = true;
+                        }
+                        TextView tv = (TextView) LayoutInflater.from(context).inflate(
+                                title ? R.layout.slice_title : R.layout.slice_secondary_text, null);
+                        tv.setText(i.getText());
+                        v.addView(tv);
+                        break;
+                    case SliceItem.TYPE_IMAGE:
+                        ImageView iv = new ImageView(context);
+                        iv.setImageIcon(i.getIcon());
+                        if (item.hasHint(Slice.HINT_LARGE)) {
+                            iv.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
+                        } else {
+                            int size = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                                    48, context.getResources().getDisplayMetrics());
+                            iv.setLayoutParams(new LayoutParams(size, size));
+                        }
+                        v.addView(iv);
+                        break;
+                    case SliceItem.TYPE_REMOTE_VIEW:
+                        v.addView(i.getRemoteView().apply(context, v));
+                        break;
+                    case SliceItem.TYPE_COLOR:
+                        // TODO: Support color to tint stuff here.
+                        break;
+                }
+            });
+            addView(v, new LayoutParams(0, WRAP_CONTENT, 1));
+            return false;
+        }
+    }
+}
diff --git a/core/java/android/app/slice/views/LargeSliceAdapter.java b/core/java/android/app/slice/views/LargeSliceAdapter.java
new file mode 100644
index 0000000..6794ff9
--- /dev/null
+++ b/core/java/android/app/slice/views/LargeSliceAdapter.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.slice.views;
+
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
+import android.app.slice.SliceQuery;
+import android.app.slice.views.LargeSliceAdapter.SliceViewHolder;
+import android.content.Context;
+import android.util.ArrayMap;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.FrameLayout;
+
+import com.android.internal.R;
+import com.android.internal.widget.RecyclerView;
+import com.android.internal.widget.RecyclerView.ViewHolder;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @hide
+ */
+public class LargeSliceAdapter extends RecyclerView.Adapter<SliceViewHolder> {
+
+    public static final int TYPE_DEFAULT       = 1;
+    public static final int TYPE_HEADER        = 2;
+    public static final int TYPE_GRID          = 3;
+    public static final int TYPE_MESSAGE       = 4;
+    public static final int TYPE_MESSAGE_LOCAL = 5;
+    public static final int TYPE_REMOTE_VIEWS  = 6;
+
+    private final IdGenerator mIdGen = new IdGenerator();
+    private final Context mContext;
+    private List<SliceWrapper> mSlices = new ArrayList<>();
+    private SliceItem mColor;
+
+    public LargeSliceAdapter(Context context) {
+        mContext = context;
+        setHasStableIds(true);
+    }
+
+    /**
+     * Set the {@link SliceItem}'s to be displayed in the adapter and the accent color.
+     */
+    public void setSliceItems(List<SliceItem> slices, SliceItem color) {
+        mColor = color;
+        mIdGen.resetUsage();
+        mSlices = slices.stream().map(s -> new SliceWrapper(s, mIdGen))
+                .collect(Collectors.toList());
+        notifyDataSetChanged();
+    }
+
+    @Override
+    public SliceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        View v = inflateforType(viewType);
+        v.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
+        return new SliceViewHolder(v);
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        return mSlices.get(position).mType;
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return mSlices.get(position).mId;
+    }
+
+    @Override
+    public int getItemCount() {
+        return mSlices.size();
+    }
+
+    @Override
+    public void onBindViewHolder(SliceViewHolder holder, int position) {
+        SliceWrapper slice = mSlices.get(position);
+        if (holder.mSliceView != null) {
+            holder.mSliceView.setColor(mColor);
+            holder.mSliceView.setSliceItem(slice.mItem);
+        } else if (slice.mType == TYPE_REMOTE_VIEWS) {
+            FrameLayout frame = (FrameLayout) holder.itemView;
+            frame.removeAllViews();
+            frame.addView(slice.mItem.getRemoteView().apply(mContext, frame));
+        }
+    }
+
+    private View inflateforType(int viewType) {
+        switch (viewType) {
+            case TYPE_REMOTE_VIEWS:
+                return new FrameLayout(mContext);
+            case TYPE_GRID:
+                return LayoutInflater.from(mContext).inflate(R.layout.slice_grid, null);
+            case TYPE_MESSAGE:
+                return LayoutInflater.from(mContext).inflate(R.layout.slice_message, null);
+            case TYPE_MESSAGE_LOCAL:
+                return LayoutInflater.from(mContext).inflate(R.layout.slice_message_local, null);
+        }
+        return new SmallTemplateView(mContext);
+    }
+
+    protected static class SliceWrapper {
+        private final SliceItem mItem;
+        private final int mType;
+        private final long mId;
+
+        public SliceWrapper(SliceItem item, IdGenerator idGen) {
+            mItem = item;
+            mType = getType(item);
+            mId = idGen.getId(item);
+        }
+
+        public static int getType(SliceItem item) {
+            if (item.getType() == SliceItem.TYPE_REMOTE_VIEW) {
+                return TYPE_REMOTE_VIEWS;
+            }
+            if (item.hasHint(Slice.HINT_MESSAGE)) {
+                // TODO: Better way to determine me or not? Something more like Messaging style.
+                if (SliceQuery.find(item, -1, Slice.HINT_SOURCE, null) != null) {
+                    return TYPE_MESSAGE;
+                } else {
+                    return TYPE_MESSAGE_LOCAL;
+                }
+            }
+            if (item.hasHint(Slice.HINT_HORIZONTAL)) {
+                return TYPE_GRID;
+            }
+            return TYPE_DEFAULT;
+        }
+    }
+
+    /**
+     * A {@link ViewHolder} for presenting slices in {@link LargeSliceAdapter}.
+     */
+    public static class SliceViewHolder extends ViewHolder {
+        public final SliceListView mSliceView;
+
+        public SliceViewHolder(View itemView) {
+            super(itemView);
+            mSliceView = itemView instanceof SliceListView ? (SliceListView) itemView : null;
+        }
+    }
+
+    /**
+     * View slices being displayed in {@link LargeSliceAdapter}.
+     */
+    public interface SliceListView {
+        /**
+         * Set the slice item for this view.
+         */
+        void setSliceItem(SliceItem slice);
+
+        /**
+         * Set the color for the items in this view.
+         */
+        default void setColor(SliceItem color) {
+
+        }
+    }
+
+    private static class IdGenerator {
+        private long mNextLong = 0;
+        private final ArrayMap<String, Long> mCurrentIds = new ArrayMap<>();
+        private final ArrayMap<String, Integer> mUsedIds = new ArrayMap<>();
+
+        public long getId(SliceItem item) {
+            String str = genString(item);
+            if (!mCurrentIds.containsKey(str)) {
+                mCurrentIds.put(str, mNextLong++);
+            }
+            long id = mCurrentIds.get(str);
+            int index = mUsedIds.getOrDefault(str, 0);
+            mUsedIds.put(str, index + 1);
+            return id + index * 10000;
+        }
+
+        private String genString(SliceItem item) {
+            StringBuilder builder = new StringBuilder();
+            SliceQuery.stream(item).forEach(i -> {
+                builder.append(i.getType());
+                i.removeHint(Slice.HINT_SELECTED);
+                builder.append(i.getHints());
+                switch (i.getType()) {
+                    case SliceItem.TYPE_REMOTE_VIEW:
+                        builder.append(i.getRemoteView());
+                        break;
+                    case SliceItem.TYPE_IMAGE:
+                        builder.append(i.getIcon());
+                        break;
+                    case SliceItem.TYPE_TEXT:
+                        builder.append(i.getText());
+                        break;
+                    case SliceItem.TYPE_COLOR:
+                        builder.append(i.getColor());
+                        break;
+                }
+            });
+            return builder.toString();
+        }
+
+        public void resetUsage() {
+            mUsedIds.clear();
+        }
+    }
+}
diff --git a/core/java/android/app/slice/views/LargeTemplateView.java b/core/java/android/app/slice/views/LargeTemplateView.java
new file mode 100644
index 0000000..9e22516
--- /dev/null
+++ b/core/java/android/app/slice/views/LargeTemplateView.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.slice.views;
+
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
+import android.app.slice.SliceQuery;
+import android.app.slice.views.SliceView.SliceModeView;
+import android.content.Context;
+import android.util.TypedValue;
+
+import com.android.internal.widget.LinearLayoutManager;
+import com.android.internal.widget.RecyclerView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @hide
+ */
+public class LargeTemplateView extends SliceModeView {
+    private final LargeSliceAdapter mAdapter;
+    private final RecyclerView mRecyclerView;
+    private final int mDefaultHeight;
+    private final int mMaxHeight;
+    private Slice mSlice;
+
+    public LargeTemplateView(Context context) {
+        super(context);
+
+        mRecyclerView = new RecyclerView(getContext());
+        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+        mAdapter = new LargeSliceAdapter(context);
+        mRecyclerView.setAdapter(mAdapter);
+        addView(mRecyclerView);
+        int width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 300,
+                getResources().getDisplayMetrics());
+        setLayoutParams(new LayoutParams(width, WRAP_CONTENT));
+        mDefaultHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200,
+                getResources().getDisplayMetrics());
+        mMaxHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200,
+                getResources().getDisplayMetrics());
+    }
+
+    @Override
+    public String getMode() {
+        return SliceView.MODE_LARGE;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        mRecyclerView.getLayoutParams().height = WRAP_CONTENT;
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        if (mRecyclerView.getMeasuredHeight() > mMaxHeight
+                || mSlice.hasHint(Slice.HINT_PARTIAL)) {
+            mRecyclerView.getLayoutParams().height = mDefaultHeight;
+        } else {
+            mRecyclerView.getLayoutParams().height = mRecyclerView.getMeasuredHeight();
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    @Override
+    public void setSlice(Slice slice) {
+        SliceItem color = SliceQuery.find(slice, SliceItem.TYPE_COLOR);
+        mSlice = slice;
+        List<SliceItem> items = new ArrayList<>();
+        boolean[] hasHeader = new boolean[1];
+        if (slice.hasHint(Slice.HINT_LIST)) {
+            addList(slice, items);
+        } else {
+            slice.getItems().forEach(item -> {
+                if (item.hasHint(Slice.HINT_ACTIONS)) {
+                    return;
+                } else if (item.getType() == SliceItem.TYPE_COLOR) {
+                    return;
+                } else if (item.getType() == SliceItem.TYPE_SLICE
+                        && item.hasHint(Slice.HINT_LIST)) {
+                    addList(item.getSlice(), items);
+                } else if (item.hasHint(Slice.HINT_LIST_ITEM)) {
+                    items.add(item);
+                } else if (!hasHeader[0]) {
+                    hasHeader[0] = true;
+                    items.add(0, item);
+                } else {
+                    item.addHint(Slice.HINT_LIST_ITEM);
+                    items.add(item);
+                }
+            });
+        }
+        mAdapter.setSliceItems(items, color);
+    }
+
+    private void addList(Slice slice, List<SliceItem> items) {
+        List<SliceItem> sliceItems = slice.getItems();
+        sliceItems.forEach(i -> i.addHint(Slice.HINT_LIST_ITEM));
+        items.addAll(sliceItems);
+    }
+}
diff --git a/core/java/android/app/slice/views/MessageView.java b/core/java/android/app/slice/views/MessageView.java
new file mode 100644
index 0000000..77252bf
--- /dev/null
+++ b/core/java/android/app/slice/views/MessageView.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.slice.views;
+
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
+import android.app.slice.SliceQuery;
+import android.app.slice.views.LargeSliceAdapter.SliceListView;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.text.SpannableStringBuilder;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/**
+ * @hide
+ */
+public class MessageView extends LinearLayout implements SliceListView {
+
+    private TextView mDetails;
+    private ImageView mIcon;
+
+    public MessageView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mDetails = findViewById(android.R.id.summary);
+        mIcon = findViewById(android.R.id.icon);
+    }
+
+    @Override
+    public void setSliceItem(SliceItem slice) {
+        SliceItem source = SliceQuery.find(slice, SliceItem.TYPE_IMAGE, Slice.HINT_SOURCE, null);
+        if (source != null) {
+            final int iconSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                    24, getContext().getResources().getDisplayMetrics());
+            // TODO try and turn this into a drawable
+            Bitmap iconBm = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
+            Canvas iconCanvas = new Canvas(iconBm);
+            Drawable d = source.getIcon().loadDrawable(getContext());
+            d.setBounds(0, 0, iconSize, iconSize);
+            d.draw(iconCanvas);
+            mIcon.setImageBitmap(SliceViewUtil.getCircularBitmap(iconBm));
+        }
+        SpannableStringBuilder builder = new SpannableStringBuilder();
+        SliceQuery.findAll(slice, SliceItem.TYPE_TEXT).forEach(text -> {
+            if (builder.length() != 0) {
+                builder.append('\n');
+            }
+            builder.append(text.getText());
+        });
+        mDetails.setText(builder.toString());
+    }
+
+}
diff --git a/core/java/android/app/slice/views/RemoteInputView.java b/core/java/android/app/slice/views/RemoteInputView.java
new file mode 100644
index 0000000..e53cb1e
--- /dev/null
+++ b/core/java/android/app/slice/views/RemoteInputView.java
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.slice.views;
+
+import android.animation.Animator;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.RemoteInput;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ShortcutManager;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewAnimationUtils;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.internal.R;
+
+/**
+ * Host for the remote input.
+ *
+ * @hide
+ */
+// TODO this should be unified with SystemUI RemoteInputView (b/67527720)
+public class RemoteInputView extends LinearLayout implements View.OnClickListener, TextWatcher {
+
+    private static final String TAG = "RemoteInput";
+
+    /**
+     * A marker object that let's us easily find views of this class.
+     */
+    public static final Object VIEW_TAG = new Object();
+
+    private RemoteEditText mEditText;
+    private ImageButton mSendButton;
+    private ProgressBar mProgressBar;
+    private PendingIntent mPendingIntent;
+    private RemoteInput[] mRemoteInputs;
+    private RemoteInput mRemoteInput;
+
+    private int mRevealCx;
+    private int mRevealCy;
+    private int mRevealR;
+    private boolean mResetting;
+
+    public RemoteInputView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        mProgressBar = findViewById(R.id.remote_input_progress);
+        mSendButton = findViewById(R.id.remote_input_send);
+        mSendButton.setOnClickListener(this);
+
+        mEditText = (RemoteEditText) getChildAt(0);
+        mEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
+            @Override
+            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+                final boolean isSoftImeEvent = event == null
+                        && (actionId == EditorInfo.IME_ACTION_DONE
+                                || actionId == EditorInfo.IME_ACTION_NEXT
+                                || actionId == EditorInfo.IME_ACTION_SEND);
+                final boolean isKeyboardEnterKey = event != null
+                        && KeyEvent.isConfirmKey(event.getKeyCode())
+                        && event.getAction() == KeyEvent.ACTION_DOWN;
+
+                if (isSoftImeEvent || isKeyboardEnterKey) {
+                    if (mEditText.length() > 0) {
+                        sendRemoteInput();
+                    }
+                    // Consume action to prevent IME from closing.
+                    return true;
+                }
+                return false;
+            }
+        });
+        mEditText.addTextChangedListener(this);
+        mEditText.setInnerFocusable(false);
+        mEditText.mRemoteInputView = this;
+    }
+
+    private void sendRemoteInput() {
+        Bundle results = new Bundle();
+        results.putString(mRemoteInput.getResultKey(), mEditText.getText().toString());
+        Intent fillInIntent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        RemoteInput.addResultsToIntent(mRemoteInputs, fillInIntent,
+                results);
+
+        mEditText.setEnabled(false);
+        mSendButton.setVisibility(INVISIBLE);
+        mProgressBar.setVisibility(VISIBLE);
+        mEditText.mShowImeOnInputConnection = false;
+
+        // Tell ShortcutManager that this package has been "activated".  ShortcutManager
+        // will reset the throttling for this package.
+        // Strictly speaking, the intent receiver may be different from the intent creator,
+        // but that's an edge case, and also because we can't always know which package will receive
+        // an intent, so we just reset for the creator.
+        getContext().getSystemService(ShortcutManager.class).onApplicationActive(
+                mPendingIntent.getCreatorPackage(),
+                getContext().getUserId());
+
+        try {
+            mPendingIntent.send(mContext, 0, fillInIntent);
+            reset();
+        } catch (PendingIntent.CanceledException e) {
+            Log.i(TAG, "Unable to send remote input result", e);
+            Toast.makeText(mContext, "Failure sending pending intent for inline reply :(",
+                    Toast.LENGTH_SHORT).show();
+            reset();
+        }
+    }
+
+    /**
+     * Creates a remote input view.
+     */
+    public static RemoteInputView inflate(Context context, ViewGroup root) {
+        RemoteInputView v = (RemoteInputView) LayoutInflater.from(context).inflate(
+                R.layout.slice_remote_input, root, false);
+        v.setTag(VIEW_TAG);
+        return v;
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v == mSendButton) {
+            sendRemoteInput();
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        super.onTouchEvent(event);
+
+        // We never want for a touch to escape to an outer view or one we covered.
+        return true;
+    }
+
+    private void onDefocus() {
+        setVisibility(INVISIBLE);
+    }
+
+    /**
+     * Set the pending intent for remote input.
+     */
+    public void setPendingIntent(PendingIntent pendingIntent) {
+        mPendingIntent = pendingIntent;
+    }
+
+    /**
+     * Set the remote inputs for this view.
+     */
+    public void setRemoteInput(RemoteInput[] remoteInputs, RemoteInput remoteInput) {
+        mRemoteInputs = remoteInputs;
+        mRemoteInput = remoteInput;
+        mEditText.setHint(mRemoteInput.getLabel());
+    }
+
+    /**
+     * Focuses the remote input view.
+     */
+    public void focusAnimated() {
+        if (getVisibility() != VISIBLE) {
+            Animator animator = ViewAnimationUtils.createCircularReveal(
+                    this, mRevealCx, mRevealCy, 0, mRevealR);
+            animator.setDuration(200);
+            animator.start();
+        }
+        focus();
+    }
+
+    private void focus() {
+        setVisibility(VISIBLE);
+        mEditText.setInnerFocusable(true);
+        mEditText.mShowImeOnInputConnection = true;
+        mEditText.setSelection(mEditText.getText().length());
+        mEditText.requestFocus();
+        updateSendButton();
+    }
+
+    private void reset() {
+        mResetting = true;
+
+        mEditText.getText().clear();
+        mEditText.setEnabled(true);
+        mSendButton.setVisibility(VISIBLE);
+        mProgressBar.setVisibility(INVISIBLE);
+        updateSendButton();
+        onDefocus();
+
+        mResetting = false;
+    }
+
+    @Override
+    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+        if (mResetting && child == mEditText) {
+            // Suppress text events if it happens during resetting. Ideally this would be
+            // suppressed by the text view not being shown, but that doesn't work here because it
+            // needs to stay visible for the animation.
+            return false;
+        }
+        return super.onRequestSendAccessibilityEvent(child, event);
+    }
+
+    private void updateSendButton() {
+        mSendButton.setEnabled(mEditText.getText().length() != 0);
+    }
+
+    @Override
+    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+    }
+
+    @Override
+    public void onTextChanged(CharSequence s, int start, int before, int count) {
+    }
+
+    @Override
+    public void afterTextChanged(Editable s) {
+        updateSendButton();
+    }
+
+    /**
+     * Tries to find an action that matches the current pending intent of this view and updates its
+     * state to that of the found action
+     *
+     * @return true if a matching action was found, false otherwise
+     */
+    public boolean updatePendingIntentFromActions(Notification.Action[] actions) {
+        if (mPendingIntent == null || actions == null) {
+            return false;
+        }
+        Intent current = mPendingIntent.getIntent();
+        if (current == null) {
+            return false;
+        }
+
+        for (Notification.Action a : actions) {
+            RemoteInput[] inputs = a.getRemoteInputs();
+            if (a.actionIntent == null || inputs == null) {
+                continue;
+            }
+            Intent candidate = a.actionIntent.getIntent();
+            if (!current.filterEquals(candidate)) {
+                continue;
+            }
+
+            RemoteInput input = null;
+            for (RemoteInput i : inputs) {
+                if (i.getAllowFreeFormInput()) {
+                    input = i;
+                }
+            }
+            if (input == null) {
+                continue;
+            }
+            setPendingIntent(a.actionIntent);
+            setRemoteInput(inputs, input);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @hide
+     */
+    public void setRevealParameters(int cx, int cy, int r) {
+        mRevealCx = cx;
+        mRevealCy = cy;
+        mRevealR = r;
+    }
+
+    @Override
+    public void dispatchStartTemporaryDetach() {
+        super.dispatchStartTemporaryDetach();
+        // Detach the EditText temporarily such that it doesn't get onDetachedFromWindow and
+        // won't lose IME focus.
+        detachViewFromParent(mEditText);
+    }
+
+    @Override
+    public void dispatchFinishTemporaryDetach() {
+        if (isAttachedToWindow()) {
+            attachViewToParent(mEditText, 0, mEditText.getLayoutParams());
+        } else {
+            removeDetachedView(mEditText, false /* animate */);
+        }
+        super.dispatchFinishTemporaryDetach();
+    }
+
+    /**
+     * An EditText that changes appearance based on whether it's focusable and becomes un-focusable
+     * whenever the user navigates away from it or it becomes invisible.
+     */
+    public static class RemoteEditText extends EditText {
+
+        private final Drawable mBackground;
+        private RemoteInputView mRemoteInputView;
+        boolean mShowImeOnInputConnection;
+
+        public RemoteEditText(Context context, AttributeSet attrs) {
+            super(context, attrs);
+            mBackground = getBackground();
+        }
+
+        private void defocusIfNeeded(boolean animate) {
+            if (mRemoteInputView != null || isTemporarilyDetached()) {
+                if (isTemporarilyDetached()) {
+                    // We might get reattached but then the other one of HUN / expanded might steal
+                    // our focus, so we'll need to save our text here.
+                }
+                return;
+            }
+            if (isFocusable() && isEnabled()) {
+                setInnerFocusable(false);
+                if (mRemoteInputView != null) {
+                    mRemoteInputView.onDefocus();
+                }
+                mShowImeOnInputConnection = false;
+            }
+        }
+
+        @Override
+        protected void onVisibilityChanged(View changedView, int visibility) {
+            super.onVisibilityChanged(changedView, visibility);
+
+            if (!isShown()) {
+                defocusIfNeeded(false /* animate */);
+            }
+        }
+
+        @Override
+        protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
+            super.onFocusChanged(focused, direction, previouslyFocusedRect);
+            if (!focused) {
+                defocusIfNeeded(true /* animate */);
+            }
+        }
+
+        @Override
+        public void getFocusedRect(Rect r) {
+            super.getFocusedRect(r);
+            r.top = mScrollY;
+            r.bottom = mScrollY + (mBottom - mTop);
+        }
+
+        @Override
+        public boolean onKeyDown(int keyCode, KeyEvent event) {
+            if (keyCode == KeyEvent.KEYCODE_BACK) {
+                // Eat the DOWN event here to prevent any default behavior.
+                return true;
+            }
+            return super.onKeyDown(keyCode, event);
+        }
+
+        @Override
+        public boolean onKeyUp(int keyCode, KeyEvent event) {
+            if (keyCode == KeyEvent.KEYCODE_BACK) {
+                defocusIfNeeded(true /* animate */);
+                return true;
+            }
+            return super.onKeyUp(keyCode, event);
+        }
+
+        @Override
+        public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+            final InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
+
+            if (mShowImeOnInputConnection && inputConnection != null) {
+                final InputMethodManager imm = InputMethodManager.getInstance();
+                if (imm != null) {
+                    // onCreateInputConnection is called by InputMethodManager in the middle of
+                    // setting up the connection to the IME; wait with requesting the IME until that
+                    // work has completed.
+                    post(new Runnable() {
+                        @Override
+                        public void run() {
+                            imm.viewClicked(RemoteEditText.this);
+                            imm.showSoftInput(RemoteEditText.this, 0);
+                        }
+                    });
+                }
+            }
+
+            return inputConnection;
+        }
+
+        @Override
+        public void onCommitCompletion(CompletionInfo text) {
+            clearComposingText();
+            setText(text.getText());
+            setSelection(getText().length());
+        }
+
+        void setInnerFocusable(boolean focusable) {
+            setFocusableInTouchMode(focusable);
+            setFocusable(focusable);
+            setCursorVisible(focusable);
+
+            if (focusable) {
+                requestFocus();
+                setBackground(mBackground);
+            } else {
+                setBackground(null);
+            }
+
+        }
+    }
+}
diff --git a/core/java/android/app/slice/views/ShortcutView.java b/core/java/android/app/slice/views/ShortcutView.java
new file mode 100644
index 0000000..b6790c7
--- /dev/null
+++ b/core/java/android/app/slice/views/ShortcutView.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.slice.views;
+
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
+import android.app.slice.SliceQuery;
+import android.app.slice.views.SliceView.SliceModeView;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.OvalShape;
+import android.net.Uri;
+import android.view.ViewGroup;
+
+import com.android.internal.R;
+
+/**
+ * @hide
+ */
+public class ShortcutView extends SliceModeView {
+
+    private static final String TAG = "ShortcutView";
+
+    private PendingIntent mAction;
+    private Uri mUri;
+    private int mLargeIconSize;
+    private int mSmallIconSize;
+
+    public ShortcutView(Context context) {
+        super(context);
+        mLargeIconSize = getContext().getResources()
+                .getDimensionPixelSize(R.dimen.slice_shortcut_size);
+        mSmallIconSize = getContext().getResources().getDimensionPixelSize(R.dimen.slice_icon_size);
+        setLayoutParams(new ViewGroup.LayoutParams(mLargeIconSize, mLargeIconSize));
+    }
+
+    @Override
+    public void setSlice(Slice slice) {
+        removeAllViews();
+        SliceItem sliceItem = SliceQuery.find(slice, SliceItem.TYPE_ACTION);
+        SliceItem iconItem = slice.getPrimaryIcon();
+        SliceItem textItem = sliceItem != null
+                ? SliceQuery.find(sliceItem, SliceItem.TYPE_TEXT)
+                : SliceQuery.find(slice, SliceItem.TYPE_TEXT);
+        SliceItem colorItem = sliceItem != null
+                ? SliceQuery.find(sliceItem, SliceItem.TYPE_COLOR)
+                : SliceQuery.find(slice, SliceItem.TYPE_COLOR);
+        if (colorItem == null) {
+            colorItem = SliceQuery.find(slice, SliceItem.TYPE_COLOR);
+        }
+        // TODO: pick better default colour
+        final int color = colorItem != null ? colorItem.getColor() : Color.GRAY;
+        ShapeDrawable circle = new ShapeDrawable(new OvalShape());
+        circle.setTint(color);
+        setBackground(circle);
+        if (iconItem != null) {
+            final boolean isLarge = iconItem.hasHint(Slice.HINT_LARGE);
+            final int iconSize = isLarge ? mLargeIconSize : mSmallIconSize;
+            SliceViewUtil.createCircledIcon(getContext(), color, iconSize, iconItem.getIcon(),
+                    isLarge, this /* parent */);
+            mAction = sliceItem != null ? sliceItem.getAction()
+                    : null;
+            mUri = slice.getUri();
+            setClickable(true);
+        } else {
+            setClickable(false);
+        }
+    }
+
+    @Override
+    public String getMode() {
+        return SliceView.MODE_SHORTCUT;
+    }
+
+    @Override
+    public boolean performClick() {
+        if (!callOnClick()) {
+            try {
+                if (mAction != null) {
+                    mAction.send();
+                } else {
+                    Intent intent = new Intent(Intent.ACTION_VIEW).setData(mUri);
+                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    getContext().startActivity(intent);
+                }
+            } catch (CanceledException e) {
+                e.printStackTrace();
+            }
+        }
+        return true;
+    }
+}
diff --git a/core/java/android/app/slice/views/SliceView.java b/core/java/android/app/slice/views/SliceView.java
new file mode 100644
index 0000000..32484fc
--- /dev/null
+++ b/core/java/android/app/slice/views/SliceView.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.slice.views;
+
+import android.annotation.StringDef;
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
+import android.app.slice.SliceQuery;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.ColorDrawable;
+import android.net.Uri;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
+import java.util.List;
+
+/**
+ * A view that can display a {@link Slice} in different {@link SliceMode}'s.
+ *
+ * @hide
+ */
+public class SliceView extends LinearLayout {
+
+    private static final String TAG = "SliceView";
+
+    /**
+     * @hide
+     */
+    public abstract static class SliceModeView extends FrameLayout {
+
+        public SliceModeView(Context context) {
+            super(context);
+        }
+
+        /**
+         * @return the {@link SliceMode} of the slice being presented.
+         */
+        public abstract String getMode();
+
+        /**
+         * @param slice the slice to show in this view.
+         */
+        public abstract void setSlice(Slice slice);
+    }
+
+    /**
+     * @hide
+     */
+    @StringDef({
+            MODE_SMALL, MODE_LARGE, MODE_SHORTCUT
+    })
+    public @interface SliceMode {}
+
+    /**
+     * Mode indicating this slice should be presented in small template format.
+     */
+    public static final String MODE_SMALL       = "SLICE_SMALL";
+    /**
+     * Mode indicating this slice should be presented in large template format.
+     */
+    public static final String MODE_LARGE       = "SLICE_LARGE";
+    /**
+     * Mode indicating this slice should be presented as an icon.
+     */
+    public static final String MODE_SHORTCUT    = "SLICE_ICON";
+
+    /**
+     * Will select the type of slice binding based on size of the View. TODO: Put in some info about
+     * that selection.
+     */
+    private static final String MODE_AUTO = "auto";
+
+    private String mMode = MODE_AUTO;
+    private SliceModeView mCurrentView;
+    private final ActionRow mActions;
+    private Slice mCurrentSlice;
+    private boolean mShowActions = true;
+
+    /**
+     * Simple constructor to create a slice view from code.
+     *
+     * @param context The context the view is running in.
+     */
+    public SliceView(Context context) {
+        super(context);
+        setOrientation(LinearLayout.VERTICAL);
+        mActions = new ActionRow(mContext, true);
+        mActions.setBackground(new ColorDrawable(0xffeeeeee));
+        mCurrentView = new LargeTemplateView(mContext);
+        addView(mCurrentView);
+        addView(mActions);
+    }
+
+    /**
+     * @hide
+     */
+    public void bindSlice(Intent intent) {
+        // TODO
+    }
+
+    /**
+     * Binds this view to the {@link Slice} associated with the provided {@link Uri}.
+     */
+    public void bindSlice(Uri sliceUri) {
+        validate(sliceUri);
+        Slice s = Slice.bindSlice(mContext.getContentResolver(), sliceUri);
+        bindSlice(s);
+    }
+
+    /**
+     * Binds this view to the provided {@link Slice}.
+     */
+    public void bindSlice(Slice slice) {
+        mCurrentSlice = slice;
+        if (mCurrentSlice != null) {
+            reinflate();
+        }
+    }
+
+    /**
+     * Call to clean up the view.
+     */
+    public void unbindSlice() {
+        mCurrentSlice = null;
+    }
+
+    /**
+     * Set the {@link SliceMode} this view should present in.
+     */
+    public void setMode(@SliceMode String mode) {
+        setMode(mode, false /* animate */);
+    }
+
+    /**
+     * @hide
+     */
+    public void setMode(@SliceMode String mode, boolean animate) {
+        if (animate) {
+            Log.e(TAG, "Animation not supported yet");
+        }
+        mMode = mode;
+        reinflate();
+    }
+
+    /**
+     * @return the {@link SliceMode} this view is presenting in.
+     */
+    public @SliceMode String getMode() {
+        if (mMode.equals(MODE_AUTO)) {
+            return MODE_LARGE;
+        }
+        return mMode;
+    }
+
+    /**
+     * @hide
+     *
+     * Whether this view should show a row of actions with it.
+     */
+    public void setShowActionRow(boolean show) {
+        mShowActions = show;
+        reinflate();
+    }
+
+    private SliceModeView createView(String mode) {
+        switch (mode) {
+            case MODE_SHORTCUT:
+                return new ShortcutView(getContext());
+            case MODE_SMALL:
+                return new SmallTemplateView(getContext());
+        }
+        return new LargeTemplateView(getContext());
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        unbindSlice();
+    }
+
+    private void reinflate() {
+        if (mCurrentSlice == null) {
+            return;
+        }
+        // TODO: Smarter mapping here from one state to the next.
+        SliceItem color = SliceQuery.find(mCurrentSlice, SliceItem.TYPE_COLOR);
+        List<SliceItem> items = mCurrentSlice.getItems();
+        SliceItem actionRow = SliceQuery.find(mCurrentSlice, SliceItem.TYPE_SLICE,
+                Slice.HINT_ACTIONS,
+                Slice.HINT_ALT);
+        String mode = getMode();
+        if (!mode.equals(mCurrentView.getMode())) {
+            removeAllViews();
+            mCurrentView = createView(mode);
+            addView(mCurrentView);
+            addView(mActions);
+        }
+        if (items.size() > 1 || (items.size() != 0 && items.get(0) != actionRow)) {
+            mCurrentView.setVisibility(View.VISIBLE);
+            mCurrentView.setSlice(mCurrentSlice);
+        } else {
+            mCurrentView.setVisibility(View.GONE);
+        }
+
+        boolean showActions = mShowActions && actionRow != null
+                && !mode.equals(MODE_SHORTCUT);
+        if (showActions) {
+            mActions.setActions(actionRow, color);
+            mActions.setVisibility(View.VISIBLE);
+        } else {
+            mActions.setVisibility(View.GONE);
+        }
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        // TODO -- may need to rethink for AGSA
+        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+            requestDisallowInterceptTouchEvent(true);
+        }
+        return super.onInterceptTouchEvent(ev);
+    }
+
+    private static void validate(Uri sliceUri) {
+        if (!ContentResolver.SCHEME_CONTENT.equals(sliceUri.getScheme())) {
+            throw new RuntimeException("Invalid uri " + sliceUri);
+        }
+        if (sliceUri.getPathSegments().size() == 0) {
+            throw new RuntimeException("Invalid uri " + sliceUri);
+        }
+    }
+}
diff --git a/core/java/android/app/slice/views/SliceViewUtil.java b/core/java/android/app/slice/views/SliceViewUtil.java
new file mode 100644
index 0000000..19e8e7c
--- /dev/null
+++ b/core/java/android/app/slice/views/SliceViewUtil.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.slice.views;
+
+import android.annotation.ColorInt;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.view.Gravity;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+/**
+ * A bunch of utilities for slice UI.
+ *
+ * @hide
+ */
+public class SliceViewUtil {
+
+    /**
+     * @hide
+     */
+    @ColorInt
+    public static int getColorAccent(Context context) {
+        return getColorAttr(context, android.R.attr.colorAccent);
+    }
+
+    /**
+     * @hide
+     */
+    @ColorInt
+    public static int getColorError(Context context) {
+        return getColorAttr(context, android.R.attr.colorError);
+    }
+
+    /**
+     * @hide
+     */
+    @ColorInt
+    public static int getDefaultColor(Context context, int resId) {
+        final ColorStateList list = context.getResources().getColorStateList(resId,
+                context.getTheme());
+
+        return list.getDefaultColor();
+    }
+
+    /**
+     * @hide
+     */
+    @ColorInt
+    public static int getDisabled(Context context, int inputColor) {
+        return applyAlphaAttr(context, android.R.attr.disabledAlpha, inputColor);
+    }
+
+    /**
+     * @hide
+     */
+    @ColorInt
+    public static int applyAlphaAttr(Context context, int attr, int inputColor) {
+        TypedArray ta = context.obtainStyledAttributes(new int[] {
+                attr
+        });
+        float alpha = ta.getFloat(0, 0);
+        ta.recycle();
+        return applyAlpha(alpha, inputColor);
+    }
+
+    /**
+     * @hide
+     */
+    @ColorInt
+    public static int applyAlpha(float alpha, int inputColor) {
+        alpha *= Color.alpha(inputColor);
+        return Color.argb((int) (alpha), Color.red(inputColor), Color.green(inputColor),
+                Color.blue(inputColor));
+    }
+
+    /**
+     * @hide
+     */
+    @ColorInt
+    public static int getColorAttr(Context context, int attr) {
+        TypedArray ta = context.obtainStyledAttributes(new int[] {
+                attr
+        });
+        @ColorInt
+        int colorAccent = ta.getColor(0, 0);
+        ta.recycle();
+        return colorAccent;
+    }
+
+    /**
+     * @hide
+     */
+    public static int getThemeAttr(Context context, int attr) {
+        TypedArray ta = context.obtainStyledAttributes(new int[] {
+                attr
+        });
+        int theme = ta.getResourceId(0, 0);
+        ta.recycle();
+        return theme;
+    }
+
+    /**
+     * @hide
+     */
+    public static Drawable getDrawable(Context context, int attr) {
+        TypedArray ta = context.obtainStyledAttributes(new int[] {
+                attr
+        });
+        Drawable drawable = ta.getDrawable(0);
+        ta.recycle();
+        return drawable;
+    }
+
+    /**
+     * @hide
+     */
+    public static void createCircledIcon(Context context, int color, int iconSize, Icon icon,
+            boolean isLarge, ViewGroup parent) {
+        ImageView v = new ImageView(context);
+        v.setImageIcon(icon);
+        parent.addView(v);
+        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) v.getLayoutParams();
+        if (isLarge) {
+            // XXX better way to convert from icon -> bitmap or crop an icon (?)
+            Bitmap iconBm = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
+            Canvas iconCanvas = new Canvas(iconBm);
+            v.layout(0, 0, iconSize, iconSize);
+            v.draw(iconCanvas);
+            v.setImageBitmap(getCircularBitmap(iconBm));
+        } else {
+            v.setColorFilter(Color.WHITE);
+        }
+        lp.width = iconSize;
+        lp.height = iconSize;
+        lp.gravity = Gravity.CENTER;
+    }
+
+    /**
+     * @hide
+     */
+    public static Bitmap getCircularBitmap(Bitmap bitmap) {
+        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
+                bitmap.getHeight(), Config.ARGB_8888);
+        Canvas canvas = new Canvas(output);
+        final Paint paint = new Paint();
+        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
+        paint.setAntiAlias(true);
+        canvas.drawARGB(0, 0, 0, 0);
+        canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2,
+                bitmap.getWidth() / 2, paint);
+        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
+        canvas.drawBitmap(bitmap, rect, rect, paint);
+        return output;
+    }
+}
diff --git a/core/java/android/app/slice/views/SmallTemplateView.java b/core/java/android/app/slice/views/SmallTemplateView.java
new file mode 100644
index 0000000..42b2d21
--- /dev/null
+++ b/core/java/android/app/slice/views/SmallTemplateView.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.slice.views;
+
+import android.app.PendingIntent.CanceledException;
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
+import android.app.slice.SliceQuery;
+import android.app.slice.views.LargeSliceAdapter.SliceListView;
+import android.app.slice.views.SliceView.SliceModeView;
+import android.content.Context;
+import android.os.AsyncTask;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.internal.R;
+
+import java.text.Format;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Small template is also used to construct list items for use with {@link LargeTemplateView}.
+ *
+ * @hide
+ */
+public class SmallTemplateView extends SliceModeView implements SliceListView {
+
+    private static final String TAG = "SmallTemplateView";
+
+    private int mIconSize;
+    private int mPadding;
+
+    private LinearLayout mStartContainer;
+    private TextView mTitleText;
+    private TextView mSecondaryText;
+    private LinearLayout mEndContainer;
+
+    public SmallTemplateView(Context context) {
+        super(context);
+        inflate(context, R.layout.slice_small_template, this);
+        mIconSize = getContext().getResources().getDimensionPixelSize(R.dimen.slice_icon_size);
+        mPadding = getContext().getResources().getDimensionPixelSize(R.dimen.slice_padding);
+
+        mStartContainer = (LinearLayout) findViewById(android.R.id.icon_frame);
+        mTitleText = (TextView) findViewById(android.R.id.title);
+        mSecondaryText = (TextView) findViewById(android.R.id.summary);
+        mEndContainer = (LinearLayout) findViewById(android.R.id.widget_frame);
+    }
+
+    @Override
+    public String getMode() {
+        return SliceView.MODE_SMALL;
+    }
+
+    @Override
+    public void setSliceItem(SliceItem slice) {
+        resetViews();
+        SliceItem colorItem = SliceQuery.find(slice, SliceItem.TYPE_COLOR);
+        int color = colorItem != null ? colorItem.getColor() : -1;
+
+        // Look for any title elements
+        List<SliceItem> titleItems = SliceQuery.findAll(slice, -1, Slice.HINT_TITLE,
+                null);
+        boolean hasTitleText = false;
+        boolean hasTitleItem = false;
+        for (int i = 0; i < titleItems.size(); i++) {
+            SliceItem item = titleItems.get(i);
+            if (!hasTitleItem) {
+                // icon, action icon, or timestamp
+                if (item.getType() == SliceItem.TYPE_ACTION) {
+                    hasTitleItem = addIcon(item, color, mStartContainer);
+                } else if (item.getType() == SliceItem.TYPE_IMAGE) {
+                    addIcon(item, color, mStartContainer);
+                    hasTitleItem = true;
+                } else if (item.getType() == SliceItem.TYPE_TIMESTAMP) {
+                    TextView tv = new TextView(getContext());
+                    tv.setText(convertTimeToString(item.getTimestamp()));
+                    hasTitleItem = true;
+                }
+            }
+            if (!hasTitleText && item.getType() == SliceItem.TYPE_TEXT) {
+                mTitleText.setText(item.getText());
+                hasTitleText = true;
+            }
+            if (hasTitleText && hasTitleItem) {
+                break;
+            }
+        }
+        mTitleText.setVisibility(hasTitleText ? View.VISIBLE : View.GONE);
+        mStartContainer.setVisibility(hasTitleItem ? View.VISIBLE : View.GONE);
+
+        if (slice.getType() != SliceItem.TYPE_SLICE) {
+            return;
+        }
+
+        // Deal with remaining items
+        int itemCount = 0;
+        boolean hasSummary = false;
+        ArrayList<SliceItem> sliceItems = new ArrayList<SliceItem>(
+                slice.getSlice().getItems());
+        for (int i = 0; i < sliceItems.size(); i++) {
+            SliceItem item = sliceItems.get(i);
+            if (!hasSummary && item.getType() == SliceItem.TYPE_TEXT
+                    && !item.hasHint(Slice.HINT_TITLE)) {
+                // TODO -- Should combine all text items?
+                mSecondaryText.setText(item.getText());
+                hasSummary = true;
+            }
+            if (itemCount <= 3) {
+                if (item.getType() == SliceItem.TYPE_ACTION) {
+                    if (addIcon(item, color, mEndContainer)) {
+                        itemCount++;
+                    }
+                } else if (item.getType() == SliceItem.TYPE_IMAGE) {
+                    addIcon(item, color, mEndContainer);
+                    itemCount++;
+                } else if (item.getType() == SliceItem.TYPE_TIMESTAMP) {
+                    TextView tv = new TextView(getContext());
+                    tv.setText(convertTimeToString(item.getTimestamp()));
+                    mEndContainer.addView(tv);
+                    itemCount++;
+                } else if (item.getType() == SliceItem.TYPE_SLICE) {
+                    List<SliceItem> subItems = item.getSlice().getItems();
+                    for (int j = 0; j < subItems.size(); j++) {
+                        sliceItems.add(subItems.get(j));
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public void setSlice(Slice slice) {
+        setSliceItem(new SliceItem(slice, SliceItem.TYPE_SLICE,
+                slice.getHints().toArray(new String[slice.getHints().size()])));
+    }
+
+    /**
+     * @return Whether an icon was added.
+     */
+    private boolean addIcon(SliceItem sliceItem, int color, LinearLayout container) {
+        SliceItem image = null;
+        SliceItem action = null;
+        if (sliceItem.getType() == SliceItem.TYPE_ACTION) {
+            image = SliceQuery.find(sliceItem.getSlice(), SliceItem.TYPE_IMAGE);
+            action = sliceItem;
+        } else if (sliceItem.getType() == SliceItem.TYPE_IMAGE) {
+            image = sliceItem;
+        }
+        if (image != null) {
+            ImageView iv = new ImageView(getContext());
+            iv.setImageIcon(image.getIcon());
+            if (action != null) {
+                final SliceItem sliceAction = action;
+                iv.setOnClickListener(v -> AsyncTask.execute(
+                        () -> {
+                            try {
+                                sliceAction.getAction().send();
+                            } catch (CanceledException e) {
+                                e.printStackTrace();
+                            }
+                        }));
+                iv.setBackground(SliceViewUtil.getDrawable(getContext(),
+                        android.R.attr.selectableItemBackground));
+            }
+            if (color != -1 && !sliceItem.hasHint(Slice.HINT_NO_TINT)) {
+                iv.setColorFilter(color);
+            }
+            container.addView(iv);
+            LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) iv.getLayoutParams();
+            lp.width = mIconSize;
+            lp.height = mIconSize;
+            lp.setMarginStart(mPadding);
+            return true;
+        }
+        return false;
+    }
+
+    private String convertTimeToString(long time) {
+        // TODO -- figure out what format(s) we support
+        Date date = new Date(time);
+        Format format = new SimpleDateFormat("MM dd yyyy HH:mm:ss");
+        return format.format(date);
+    }
+
+    private void resetViews() {
+        mStartContainer.removeAllViews();
+        mEndContainer.removeAllViews();
+        mTitleText.setText(null);
+        mSecondaryText.setText(null);
+    }
+}
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 051dccb..fd579fc 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -48,10 +48,10 @@
  * </pre>
  * A request for data in the middle of a time interval will include that interval.
  * <p/>
- * <b>NOTE:</b> This API requires the permission android.permission.PACKAGE_USAGE_STATS, which
- * is a system-level permission and will not be granted to third-party apps. However, declaring
- * the permission implies intention to use the API and the user of the device can grant permission
- * through the Settings application.
+ * <b>NOTE:</b> This API requires the permission android.permission.PACKAGE_USAGE_STATS.
+ * However, declaring the permission implies intention to use the API and the user of the device
+ * still needs to grant permission through the Settings application.
+ * See {@link android.provider.Settings#ACTION_USAGE_ACCESS_SETTINGS}
  */
 @SystemService(Context.USAGE_STATS_SERVICE)
 public final class UsageStatsManager {
@@ -122,7 +122,7 @@
      * @param intervalType The time interval by which the stats are aggregated.
      * @param beginTime The inclusive beginning of the range of stats to include in the results.
      * @param endTime The exclusive end of the range of stats to include in the results.
-     * @return A list of {@link UsageStats} or null if none are available.
+     * @return A list of {@link UsageStats}
      *
      * @see #INTERVAL_DAILY
      * @see #INTERVAL_WEEKLY
@@ -139,7 +139,7 @@
                 return slice.getList();
             }
         } catch (RemoteException e) {
-            // fallthrough and return null.
+            // fallthrough and return the empty list.
         }
         return Collections.emptyList();
     }
@@ -152,7 +152,7 @@
      * @param intervalType The time interval by which the stats are aggregated.
      * @param beginTime The inclusive beginning of the range of stats to include in the results.
      * @param endTime The exclusive end of the range of stats to include in the results.
-     * @return A list of {@link ConfigurationStats} or null if none are available.
+     * @return A list of {@link ConfigurationStats}
      */
     public List<ConfigurationStats> queryConfigurations(int intervalType, long beginTime,
             long endTime) {
@@ -185,7 +185,7 @@
                 return iter;
             }
         } catch (RemoteException e) {
-            // fallthrough and return null
+            // fallthrough and return empty result.
         }
         return sEmptyResults;
     }
@@ -197,8 +197,7 @@
      *
      * @param beginTime The inclusive beginning of the range of stats to include in the results.
      * @param endTime The exclusive end of the range of stats to include in the results.
-     * @return A {@link java.util.Map} keyed by package name, or null if no stats are
-     *         available.
+     * @return A {@link java.util.Map} keyed by package name
      */
     public Map<String, UsageStats> queryAndAggregateUsageStats(long beginTime, long endTime) {
         List<UsageStats> stats = queryUsageStats(INTERVAL_BEST, beginTime, endTime);
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 84765f6..3526e18 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -2277,6 +2277,8 @@
      *
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN)
     public boolean enableNoAutoConnect() {
         if (isEnabled()) {
             if (DBG) Log.d(TAG, "enableNoAutoConnect(): BT already enabled!");
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index d982bb7..ad7a93c 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1098,6 +1098,8 @@
      * @return true on success, false on error
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN)
     public boolean cancelBondProcess() {
         final IBluetooth service = sService;
         if (service == null) {
@@ -1125,6 +1127,8 @@
      * @return true on success, false on error
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN)
     public boolean removeBond() {
         final IBluetooth service = sService;
         if (service == null) {
@@ -1174,6 +1178,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH)
     public boolean isConnected() {
         final IBluetooth service = sService;
         if (service == null) {
@@ -1197,6 +1202,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH)
     public boolean isEncrypted() {
         final IBluetooth service = sService;
         if (service == null) {
@@ -1444,6 +1450,8 @@
      * @return Whether the value has been successfully set.
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
     public boolean setPhonebookAccessPermission(int value) {
         final IBluetooth service = sService;
         if (service == null) {
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 85550c7..1241f23 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -16,8 +16,10 @@
 
 package android.bluetooth;
 
+import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.Binder;
@@ -416,6 +418,8 @@
      * @return false on immediate error, true otherwise
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN)
     public boolean connect(BluetoothDevice device) {
         if (DBG) log("connect(" + device + ")");
         final IBluetoothHeadset service = mService;
@@ -456,6 +460,8 @@
      * @return false on immediate error, true otherwise
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN)
     public boolean disconnect(BluetoothDevice device) {
         if (DBG) log("disconnect(" + device + ")");
         final IBluetoothHeadset service = mService;
@@ -543,6 +549,8 @@
      * @return true if priority is set, false on error
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN)
     public boolean setPriority(BluetoothDevice device, int priority) {
         if (DBG) log("setPriority(" + device + ", " + priority + ")");
         final IBluetoothHeadset service = mService;
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 5b2bf45..cdeaea3 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -2099,8 +2099,7 @@
     public static Uri maybeAddUserId(Uri uri, int userId) {
         if (uri == null) return null;
         if (userId != UserHandle.USER_CURRENT
-                && (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())
-                        || ContentResolver.SCHEME_SLICE.equals(uri.getScheme()))) {
+                && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
             if (!uriHasUserId(uri)) {
                 //We don't add the user Id if there's already one
                 Uri.Builder builder = uri.buildUpon();
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 02e70f5..9ccc552 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -47,8 +47,6 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
-import android.slice.Slice;
-import android.slice.SliceProvider;
 import android.text.TextUtils;
 import android.util.EventLog;
 import android.util.Log;
@@ -180,8 +178,6 @@
     public static final Intent ACTION_SYNC_CONN_STATUS_CHANGED =
             new Intent("com.android.sync.SYNC_CONN_STATUS_CHANGED");
 
-    /** @hide */
-    public static final String SCHEME_SLICE = "slice";
     public static final String SCHEME_CONTENT = "content";
     public static final String SCHEME_ANDROID_RESOURCE = "android.resource";
     public static final String SCHEME_FILE = "file";
@@ -1722,36 +1718,6 @@
     }
 
     /**
-     * Turns a slice Uri into slice content.
-     *
-     * @param uri The URI to a slice provider
-     * @return The Slice provided by the app or null if none is given.
-     * @see Slice
-     * @hide
-     */
-    public final @Nullable Slice bindSlice(@NonNull Uri uri) {
-        Preconditions.checkNotNull(uri, "uri");
-        IContentProvider provider = acquireProvider(uri);
-        if (provider == null) {
-            throw new IllegalArgumentException("Unknown URI " + uri);
-        }
-        try {
-            Bundle extras = new Bundle();
-            extras.putParcelable(SliceProvider.EXTRA_BIND_URI, uri);
-            final Bundle res = provider.call(mPackageName, SliceProvider.METHOD_SLICE, null,
-                    extras);
-            Bundle.setDefusable(res, true);
-            return res.getParcelable(SliceProvider.EXTRA_SLICE);
-        } catch (RemoteException e) {
-            // Arbitrary and not worth documenting, as Activity
-            // Manager will kill this process shortly anyway.
-            return null;
-        } finally {
-            releaseProvider(provider);
-        }
-    }
-
-    /**
      * Returns the content provider for the given content URI.
      *
      * @param uri The URI to a content provider
@@ -1759,7 +1725,7 @@
      * @hide
      */
     public final IContentProvider acquireProvider(Uri uri) {
-        if (!SCHEME_CONTENT.equals(uri.getScheme()) && !SCHEME_SLICE.equals(uri.getScheme())) {
+        if (!SCHEME_CONTENT.equals(uri.getScheme())) {
             return null;
         }
         final String auth = uri.getAuthority();
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index c9ad951..e47de75 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -53,6 +53,7 @@
 import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.XmlUtils;
 
@@ -9371,6 +9372,57 @@
         }
     }
 
+    /** @hide */
+    public void writeToProto(ProtoOutputStream proto, long fieldId, boolean secure, boolean comp,
+            boolean extras, boolean clip) {
+        long token = proto.start(fieldId);
+        if (mAction != null) {
+            proto.write(IntentProto.ACTION, mAction);
+        }
+        if (mCategories != null)  {
+            for (String category : mCategories) {
+                proto.write(IntentProto.CATEGORIES, category);
+            }
+        }
+        if (mData != null) {
+            proto.write(IntentProto.DATA, secure ? mData.toSafeString() : mData.toString());
+        }
+        if (mType != null) {
+            proto.write(IntentProto.TYPE, mType);
+        }
+        if (mFlags != 0) {
+            proto.write(IntentProto.FLAG, "0x" + Integer.toHexString(mFlags));
+        }
+        if (mPackage != null) {
+            proto.write(IntentProto.PACKAGE, mPackage);
+        }
+        if (comp && mComponent != null) {
+            proto.write(IntentProto.COMPONENT, mComponent.flattenToShortString());
+        }
+        if (mSourceBounds != null) {
+            proto.write(IntentProto.SOURCE_BOUNDS, mSourceBounds.toShortString());
+        }
+        if (mClipData != null) {
+            StringBuilder b = new StringBuilder();
+            if (clip) {
+                mClipData.toShortString(b);
+            } else {
+                mClipData.toShortStringShortItems(b, false);
+            }
+            proto.write(IntentProto.CLIP_DATA, b.toString());
+        }
+        if (extras && mExtras != null) {
+            proto.write(IntentProto.EXTRAS, mExtras.toShortString());
+        }
+        if (mContentUserHint != 0) {
+            proto.write(IntentProto.CONTENT_USER_HINT, mContentUserHint);
+        }
+        if (mSelector != null) {
+            proto.write(IntentProto.SELECTOR, mSelector.toShortString(secure, comp, extras, clip));
+        }
+        proto.end(token);
+    }
+
     /**
      * Call {@link #toUri} with 0 flags.
      * @deprecated Use {@link #toUri} instead.
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index c9bce53..a957aed 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -26,6 +26,7 @@
 import android.util.AndroidException;
 import android.util.Log;
 import android.util.Printer;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.XmlUtils;
 
@@ -918,6 +919,15 @@
             dest.writeInt(mPort);
         }
 
+        void writeToProto(ProtoOutputStream proto, long fieldId) {
+            long token = proto.start(fieldId);
+            // The original host information is already contained in host and wild, no output now.
+            proto.write(AuthorityEntryProto.HOST, mHost);
+            proto.write(AuthorityEntryProto.WILD, mWild);
+            proto.write(AuthorityEntryProto.PORT, mPort);
+            proto.end(token);
+        }
+
         public String getHost() {
             return mOrigHost;
         }
@@ -1739,6 +1749,59 @@
         }
     }
 
+    /** @hide */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        long token = proto.start(fieldId);
+        if (mActions.size() > 0) {
+            Iterator<String> it = mActions.iterator();
+            while (it.hasNext()) {
+                proto.write(IntentFilterProto.ACTIONS, it.next());
+            }
+        }
+        if (mCategories != null) {
+            Iterator<String> it = mCategories.iterator();
+            while (it.hasNext()) {
+                proto.write(IntentFilterProto.CATEGORIES, it.next());
+            }
+        }
+        if (mDataSchemes != null) {
+            Iterator<String> it = mDataSchemes.iterator();
+            while (it.hasNext()) {
+                proto.write(IntentFilterProto.DATA_SCHEMES, it.next());
+            }
+        }
+        if (mDataSchemeSpecificParts != null) {
+            Iterator<PatternMatcher> it = mDataSchemeSpecificParts.iterator();
+            while (it.hasNext()) {
+                it.next().writeToProto(proto, IntentFilterProto.DATA_SCHEME_SPECS);
+            }
+        }
+        if (mDataAuthorities != null) {
+            Iterator<AuthorityEntry> it = mDataAuthorities.iterator();
+            while (it.hasNext()) {
+                it.next().writeToProto(proto, IntentFilterProto.DATA_AUTHORITIES);
+            }
+        }
+        if (mDataPaths != null) {
+            Iterator<PatternMatcher> it = mDataPaths.iterator();
+            while (it.hasNext()) {
+                it.next().writeToProto(proto, IntentFilterProto.DATA_PATHS);
+            }
+        }
+        if (mDataTypes != null) {
+            Iterator<String> it = mDataTypes.iterator();
+            while (it.hasNext()) {
+                proto.write(IntentFilterProto.DATA_TYPES, it.next());
+            }
+        }
+        if (mPriority != 0 || mHasPartialTypes) {
+            proto.write(IntentFilterProto.PRIORITY, mPriority);
+            proto.write(IntentFilterProto.HAS_PARTIAL_TYPES, mHasPartialTypes);
+        }
+        proto.write(IntentFilterProto.GET_AUTO_VERIFY, getAutoVerify());
+        proto.end(token);
+    }
+
     public void dump(Printer du, String prefix) {
         StringBuilder sb = new StringBuilder(256);
         if (mActions.size() > 0) {
diff --git a/core/java/android/content/pm/FeatureInfo.java b/core/java/android/content/pm/FeatureInfo.java
index 9ee6fa2..ff9fd8e 100644
--- a/core/java/android/content/pm/FeatureInfo.java
+++ b/core/java/android/content/pm/FeatureInfo.java
@@ -18,6 +18,7 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.proto.ProtoOutputStream;
 
 /**
  * Definition of a single optional hardware or software feature of an Android
@@ -113,6 +114,18 @@
         dest.writeInt(flags);
     }
 
+    /** @hide */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        long token = proto.start(fieldId);
+        if (name != null) {
+            proto.write(FeatureInfoProto.NAME, name);
+        }
+        proto.write(FeatureInfoProto.VERSION, version);
+        proto.write(FeatureInfoProto.GLES_VERSION, getGlEsVersion());
+        proto.write(FeatureInfoProto.FLAGS, flags);
+        proto.end(token);
+    }
+
     public static final Creator<FeatureInfo> CREATOR = new Creator<FeatureInfo>() {
         @Override
         public FeatureInfo createFromParcel(Parcel source) {
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index aa9562f..b94a410 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -20,8 +20,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
-import android.annotation.SystemService;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemService;
 import android.annotation.TestApi;
 import android.app.PendingIntent;
 import android.appwidget.AppWidgetManager;
@@ -37,10 +37,10 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Rect;
+import android.graphics.drawable.AdaptiveIconDrawable;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
-import android.graphics.drawable.AdaptiveIconDrawable;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -282,12 +282,27 @@
         public static final int FLAG_GET_MANIFEST = FLAG_MATCH_MANIFEST;
 
         /**
-         * Does not retrieve CHOOSER only shortcuts.
-         * TODO: Add another flag for MATCH_ALL_PINNED
+         * @hide include all pinned shortcuts by any launchers, not just by the caller,
+         * in the result.
+         * If the caller doesn't havve the {@link android.Manifest.permission#ACCESS_SHORTCUTS}
+         * permission, this flag will be ignored.
+         */
+        @TestApi
+        public static final int FLAG_MATCH_ALL_PINNED = 1 << 10;
+
+        /**
+         * FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST
          * @hide
          */
         public static final int FLAG_MATCH_ALL_KINDS =
-                FLAG_GET_DYNAMIC | FLAG_GET_PINNED | FLAG_GET_MANIFEST;
+                FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST;
+
+        /**
+         * FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST | FLAG_MATCH_ALL_PINNED
+         * @hide
+         */
+        public static final int FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED =
+                FLAG_MATCH_ALL_KINDS | FLAG_MATCH_ALL_PINNED;
 
         /** @hide kept for unit tests */
         @Deprecated
@@ -319,6 +334,7 @@
                         FLAG_MATCH_PINNED,
                         FLAG_MATCH_MANIFEST,
                         FLAG_GET_KEY_FIELDS_ONLY,
+                        FLAG_MATCH_MANIFEST,
                 })
         @Retention(RetentionPolicy.SOURCE)
         public @interface QueryFlags {}
@@ -678,6 +694,21 @@
         }
     }
 
+    private List<ShortcutInfo> maybeUpdateDisabledMessage(List<ShortcutInfo> shortcuts) {
+        if (shortcuts == null) {
+            return null;
+        }
+        for (int i = shortcuts.size() - 1; i >= 0; i--) {
+            final ShortcutInfo si = shortcuts.get(i);
+            final String message = ShortcutInfo.getDisabledReasonForRestoreIssue(mContext,
+                    si.getDisabledReason());
+            if (message != null) {
+                si.setDisabledMessage(message);
+            }
+        }
+        return shortcuts;
+    }
+
     /**
      * Returns {@link ShortcutInfo}s that match {@code query}.
      *
@@ -698,10 +729,16 @@
             @NonNull UserHandle user) {
         logErrorForInvalidProfileAccess(user);
         try {
-            return mService.getShortcuts(mContext.getPackageName(),
+            // Note this is the only case we need to update the disabled message for shortcuts
+            // that weren't restored.
+            // The restore problem messages are only shown by the user, and publishers will never
+            // see them. The only other API that the launcher gets shortcuts is the shortcut
+            // changed callback, but that only returns shortcuts with the "key" information, so
+            // that won't return disabled message.
+            return maybeUpdateDisabledMessage(mService.getShortcuts(mContext.getPackageName(),
                     query.mChangedSince, query.mPackage, query.mShortcutIds, query.mActivity,
                     query.mQueryFlags, user)
-                    .getList();
+                    .getList());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index 7993167..3f63d80 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -222,6 +222,40 @@
     }
 
     /**
+     * @return The resource that would be used when loading
+     * the label for this resolve info.
+     *
+     * @hide
+     */
+    public int resolveLabelResId() {
+        if (labelRes != 0) {
+            return labelRes;
+        }
+        final ComponentInfo componentInfo = getComponentInfo();
+        if (componentInfo.labelRes != 0) {
+            return componentInfo.labelRes;
+        }
+        return componentInfo.applicationInfo.labelRes;
+    }
+
+    /**
+     * @return The resource that would be used when loading
+     * the icon for this resolve info.
+     *
+     * @hide
+     */
+    public int resolveIconResId() {
+        if (icon != 0) {
+            return icon;
+        }
+        final ComponentInfo componentInfo = getComponentInfo();
+        if (componentInfo.icon != 0) {
+            return componentInfo.icon;
+        }
+        return componentInfo.applicationInfo.icon;
+    }
+
+    /**
      * Retrieve the current graphical icon associated with this resolution.  This
      * will call back on the given PackageManager to load the icon from
      * the application.
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 6b9c753..9ff0775 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -18,6 +18,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.annotation.UserIdInt;
 import android.app.TaskStackBuilder;
 import android.content.ComponentName;
@@ -100,6 +101,13 @@
     /** @hide When this is set, the bitmap icon is waiting to be saved. */
     public static final int FLAG_ICON_FILE_PENDING_SAVE = 1 << 11;
 
+    /**
+     * "Shadow" shortcuts are the ones that are restored, but the owner package hasn't been
+     * installed yet.
+     * @hide
+     */
+    public static final int FLAG_SHADOW = 1 << 12;
+
     /** @hide */
     @IntDef(flag = true,
             value = {
@@ -158,6 +166,124 @@
     public @interface CloneFlags {}
 
     /**
+     * Shortcut is not disabled.
+     */
+    public static final int DISABLED_REASON_NOT_DISABLED = 0;
+
+    /**
+     * Shortcut has been disabled by the publisher app with the
+     * {@link ShortcutManager#disableShortcuts(List)} API.
+     */
+    public static final int DISABLED_REASON_BY_APP = 1;
+
+    /**
+     * Shortcut has been disabled due to changes to the publisher app. (e.g. a manifest shortcut
+     * no longer exists.)
+     */
+    public static final int DISABLED_REASON_APP_CHANGED = 2;
+
+    /**
+     * A disabled reason that's equal to or bigger than this is due to backup and restore issue.
+     * A shortcut with such a reason wil be visible to the launcher, but not to the publisher.
+     * ({@link #isVisibleToPublisher()} will be false.)
+     */
+    private static final int DISABLED_REASON_RESTORE_ISSUE_START = 100;
+
+    /**
+     * Shortcut has been restored from the previous device, but the publisher app on the current
+     * device is of a lower version. The shortcut will not be usable until the app is upgraded to
+     * the same version or higher.
+     */
+    public static final int DISABLED_REASON_VERSION_LOWER = 100;
+
+    /**
+     * Shortcut has not been restored because the publisher app does not support backup and restore.
+     */
+    public static final int DISABLED_REASON_BACKUP_NOT_SUPPORTED = 101;
+
+    /**
+     * Shortcut has not been restored because the publisher app's signature has changed.
+     */
+    public static final int DISABLED_REASON_SIGNATURE_MISMATCH = 102;
+
+    /**
+     * Shortcut has not been restored for unknown reason.
+     */
+    public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103;
+
+    /** @hide */
+    @IntDef(value = {
+            DISABLED_REASON_NOT_DISABLED,
+            DISABLED_REASON_BY_APP,
+            DISABLED_REASON_APP_CHANGED,
+            DISABLED_REASON_VERSION_LOWER,
+            DISABLED_REASON_BACKUP_NOT_SUPPORTED,
+            DISABLED_REASON_SIGNATURE_MISMATCH,
+            DISABLED_REASON_OTHER_RESTORE_ISSUE,
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DisabledReason{}
+
+    /**
+     * Return a label for disabled reasons, which are *not* supposed to be shown to the user.
+     * @hide
+     */
+    public static String getDisabledReasonDebugString(@DisabledReason int disabledReason) {
+        switch (disabledReason) {
+            case DISABLED_REASON_NOT_DISABLED:
+                return "[Not disabled]";
+            case DISABLED_REASON_BY_APP:
+                return "[Disabled: by app]";
+            case DISABLED_REASON_APP_CHANGED:
+                return "[Disabled: app changed]";
+            case DISABLED_REASON_VERSION_LOWER:
+                return "[Disabled: lower version]";
+            case DISABLED_REASON_BACKUP_NOT_SUPPORTED:
+                return "[Disabled: backup not supported]";
+            case DISABLED_REASON_SIGNATURE_MISMATCH:
+                return "[Disabled: signature mismatch]";
+            case DISABLED_REASON_OTHER_RESTORE_ISSUE:
+                return "[Disabled: unknown restore issue]";
+        }
+        return "[Disabled: unknown reason:" + disabledReason + "]";
+    }
+
+    /**
+     * Return a label for a disabled reason for shortcuts that are disabled due to a backup and
+     * restore issue. If the reason is not due to backup & restore, then it'll return null.
+     *
+     * This method returns localized, user-facing strings, which will be returned by
+     * {@link #getDisabledMessage()}.
+     *
+     * @hide
+     */
+    public static String getDisabledReasonForRestoreIssue(Context context,
+            @DisabledReason int disabledReason) {
+        final Resources res = context.getResources();
+
+        switch (disabledReason) {
+            case DISABLED_REASON_VERSION_LOWER:
+                return res.getString(
+                        com.android.internal.R.string.shortcut_restored_on_lower_version);
+            case DISABLED_REASON_BACKUP_NOT_SUPPORTED:
+                return res.getString(
+                        com.android.internal.R.string.shortcut_restore_not_supported);
+            case DISABLED_REASON_SIGNATURE_MISMATCH:
+                return res.getString(
+                        com.android.internal.R.string.shortcut_restore_signature_mismatch);
+            case DISABLED_REASON_OTHER_RESTORE_ISSUE:
+                return res.getString(
+                        com.android.internal.R.string.shortcut_restore_unknown_issue);
+        }
+        return null;
+    }
+
+    /** @hide */
+    public static boolean isDisabledForRestoreIssue(@DisabledReason int disabledReason) {
+        return disabledReason >= DISABLED_REASON_RESTORE_ISSUE_START;
+    }
+
+    /**
      * Shortcut category for messaging related actions, such as chat.
      */
     public static final String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
@@ -240,6 +366,11 @@
 
     private final int mUserId;
 
+    /** @hide */
+    public static final int VERSION_CODE_UNKNOWN = -1;
+
+    private int mDisabledReason;
+
     private ShortcutInfo(Builder b) {
         mUserId = b.mContext.getUserId();
 
@@ -352,6 +483,7 @@
         mActivity = source.mActivity;
         mFlags = source.mFlags;
         mLastChangedTimestamp = source.mLastChangedTimestamp;
+        mDisabledReason = source.mDisabledReason;
 
         // Just always keep it since it's cheep.
         mIconResId = source.mIconResId;
@@ -615,13 +747,23 @@
 
     /**
      * @hide
+     *
+     * @isUpdating set true if it's "update", as opposed to "replace".
      */
-    public void ensureUpdatableWith(ShortcutInfo source) {
+    public void ensureUpdatableWith(ShortcutInfo source, boolean isUpdating) {
+        if (isUpdating) {
+            Preconditions.checkState(isVisibleToPublisher(),
+                    "[Framework BUG] Invisible shortcuts can't be updated");
+        }
         Preconditions.checkState(mUserId == source.mUserId, "Owner User ID must match");
         Preconditions.checkState(mId.equals(source.mId), "ID must match");
         Preconditions.checkState(mPackageName.equals(source.mPackageName),
                 "Package name must match");
-        Preconditions.checkState(!isImmutable(), "Target ShortcutInfo is immutable");
+
+        if (isVisibleToPublisher()) {
+            // Don't do this check for restore-blocked shortcuts.
+            Preconditions.checkState(!isImmutable(), "Target ShortcutInfo is immutable");
+        }
     }
 
     /**
@@ -638,7 +780,7 @@
      * @hide
      */
     public void copyNonNullFieldsFrom(ShortcutInfo source) {
-        ensureUpdatableWith(source);
+        ensureUpdatableWith(source, /*isUpdating=*/ true);
 
         if (source.mActivity != null) {
             mActivity = source.mActivity;
@@ -1169,6 +1311,19 @@
         return mDisabledMessageResId;
     }
 
+    /** @hide */
+    public void setDisabledReason(@DisabledReason int reason) {
+        mDisabledReason = reason;
+    }
+
+    /**
+     * Returns why a shortcut has been disabled.
+     */
+    @DisabledReason
+    public int getDisabledReason() {
+        return mDisabledReason;
+    }
+
     /**
      * Return the shortcut's categories.
      *
@@ -1403,6 +1558,21 @@
         return hasFlags(FLAG_IMMUTABLE);
     }
 
+    /** @hide */
+    public boolean isDynamicVisible() {
+        return isDynamic() && isVisibleToPublisher();
+    }
+
+    /** @hide */
+    public boolean isPinnedVisible() {
+        return isPinned() && isVisibleToPublisher();
+    }
+
+    /** @hide */
+    public boolean isManifestVisible() {
+        return isDeclaredInManifest() && isVisibleToPublisher();
+    }
+
     /**
      * Return if a shortcut is immutable, in which case it cannot be modified with any of
      * {@link ShortcutManager} APIs.
@@ -1491,6 +1661,18 @@
     }
 
     /**
+     * When the system wasn't able to restore a shortcut, it'll still be registered to the system
+     * but disabled, and such shortcuts will not be visible to the publisher. They're still visible
+     * to launchers though.
+     *
+     * @hide
+     */
+    @TestApi
+    public boolean isVisibleToPublisher() {
+        return !isDisabledForRestoreIssue(mDisabledReason);
+    }
+
+    /**
      * Return whether a shortcut only contains "key" information only or not.  If true, only the
      * following fields are available.
      * <ul>
@@ -1668,6 +1850,7 @@
         mFlags = source.readInt();
         mIconResId = source.readInt();
         mLastChangedTimestamp = source.readLong();
+        mDisabledReason = source.readInt();
 
         if (source.readInt() == 0) {
             return; // key information only.
@@ -1711,6 +1894,7 @@
         dest.writeInt(mFlags);
         dest.writeInt(mIconResId);
         dest.writeLong(mLastChangedTimestamp);
+        dest.writeInt(mDisabledReason);
 
         if (hasKeyFieldsOnly()) {
             dest.writeInt(0);
@@ -1808,6 +1992,11 @@
         sb.append(", flags=0x");
         sb.append(Integer.toHexString(mFlags));
         sb.append(" [");
+        if ((mFlags & FLAG_SHADOW) != 0) {
+            // Note the shadow flag isn't actually used anywhere and it's just for dumpsys, so
+            // we don't have an isXxx for this.
+            sb.append("Sdw");
+        }
         if (!isEnabled()) {
             sb.append("Dis");
         }
@@ -1848,7 +2037,9 @@
         sb.append("packageName=");
         sb.append(mPackageName);
 
-        sb.append(", activity=");
+        addIndentOrComma(sb, indent);
+
+        sb.append("activity=");
         sb.append(mActivity);
 
         addIndentOrComma(sb, indent);
@@ -1883,6 +2074,11 @@
 
         addIndentOrComma(sb, indent);
 
+        sb.append("disabledReason=");
+        sb.append(getDisabledReasonDebugString(mDisabledReason));
+
+        addIndentOrComma(sb, indent);
+
         sb.append("categories=");
         sb.append(mCategories);
 
@@ -1953,7 +2149,7 @@
             CharSequence disabledMessage, int disabledMessageResId, String disabledMessageResName,
             Set<String> categories, Intent[] intentsWithExtras, int rank, PersistableBundle extras,
             long lastChangedTimestamp,
-            int flags, int iconResId, String iconResName, String bitmapPath) {
+            int flags, int iconResId, String iconResName, String bitmapPath, int disabledReason) {
         mUserId = userId;
         mId = id;
         mPackageName = packageName;
@@ -1978,5 +2174,6 @@
         mIconResId = iconResId;
         mIconResName = iconResName;
         mBitmapPath = bitmapPath;
+        mDisabledReason = disabledReason;
     }
 }
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index 7b7d8ae..7fc25d8 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -46,7 +46,7 @@
             @NonNull String callingPackage, long changedSince,
             @Nullable String packageName, @Nullable List<String> shortcutIds,
             @Nullable ComponentName componentName, @ShortcutQuery.QueryFlags int flags,
-            int userId);
+            int userId, int callingPid, int callingUid);
 
     public abstract boolean
             isPinnedByCaller(int launcherUserId, @NonNull String callingPackage,
@@ -58,7 +58,8 @@
 
     public abstract Intent[] createShortcutIntents(
             int launcherUserId, @NonNull String callingPackage,
-            @NonNull String packageName, @NonNull String shortcutId, int userId);
+            @NonNull String packageName, @NonNull String shortcutId, int userId,
+            int callingPid, int callingUid);
 
     public abstract void addListener(@NonNull ShortcutChangeListener listener);
 
@@ -70,7 +71,7 @@
             @NonNull String packageName, @NonNull String shortcutId, int userId);
 
     public abstract boolean hasShortcutHostPermission(int launcherUserId,
-            @NonNull String callingPackage);
+            @NonNull String callingPackage, int callingPid, int callingUid);
 
     public abstract boolean requestPinAppWidget(@NonNull String callingPackage,
             @NonNull AppWidgetProviderInfo appWidget, @Nullable Bundle extras,
diff --git a/core/java/android/content/res/FontResourcesParser.java b/core/java/android/content/res/FontResourcesParser.java
index 042eb87f..28e9fce 100644
--- a/core/java/android/content/res/FontResourcesParser.java
+++ b/core/java/android/content/res/FontResourcesParser.java
@@ -15,7 +15,6 @@
  */
 package android.content.res;
 
-import com.android.internal.R;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.Typeface;
@@ -23,6 +22,8 @@
 import android.util.Log;
 import android.util.Xml;
 
+import com.android.internal.R;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -78,12 +79,15 @@
         private final @NonNull String mFileName;
         private int mWeight;
         private int mItalic;
+        private int mTtcIndex;
         private int mResourceId;
 
-        public FontFileResourceEntry(@NonNull String fileName, int weight, int italic) {
+        public FontFileResourceEntry(@NonNull String fileName, int weight, int italic,
+                int ttcIndex) {
             mFileName = fileName;
             mWeight = weight;
             mItalic = italic;
+            mTtcIndex = ttcIndex;
         }
 
         public @NonNull String getFileName() {
@@ -97,6 +101,10 @@
         public int getItalic() {
             return mItalic;
         }
+
+        public int getTtcIndex() {
+            return mTtcIndex;
+        }
     }
 
     // A class represents file based font-family element in xml file.
@@ -203,6 +211,7 @@
                 Typeface.RESOLVE_BY_FONT_TABLE);
         int italic = array.getInt(R.styleable.FontFamilyFont_fontStyle,
                 Typeface.RESOLVE_BY_FONT_TABLE);
+        int ttcIndex = array.getInt(R.styleable.FontFamilyFont_ttcIndex, 0);
         String filename = array.getString(R.styleable.FontFamilyFont_font);
         array.recycle();
         while (parser.next() != XmlPullParser.END_TAG) {
@@ -211,7 +220,7 @@
         if (filename == null) {
             return null;
         }
-        return new FontFileResourceEntry(filename, weight, italic);
+        return new FontFileResourceEntry(filename, weight, italic, ttcIndex);
     }
 
     private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index a75372f..f84ec65fe 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -16,8 +16,7 @@
 
 package android.database;
 
-import dalvik.system.CloseGuard;
-
+import android.annotation.BytesLong;
 import android.content.res.Resources;
 import android.database.sqlite.SQLiteClosable;
 import android.database.sqlite.SQLiteException;
@@ -26,8 +25,10 @@
 import android.os.Parcelable;
 import android.os.Process;
 import android.util.Log;
-import android.util.SparseIntArray;
 import android.util.LongSparseArray;
+import android.util.SparseIntArray;
+
+import dalvik.system.CloseGuard;
 
 /**
  * A buffer containing multiple cursor rows.
@@ -94,19 +95,29 @@
      * @param name The name of the cursor window, or null if none.
      */
     public CursorWindow(String name) {
+        this(name, getCursorWindowSize());
+    }
+
+    /**
+     * Creates a new empty cursor window and gives it a name.
+     * <p>
+     * The cursor initially has no rows or columns.  Call {@link #setNumColumns(int)} to
+     * set the number of columns before adding any rows to the cursor.
+     * </p>
+     *
+     * @param name The name of the cursor window, or null if none.
+     * @param windowSizeBytes Size of cursor window in bytes.
+     * <p><strong>Note:</strong> Memory is dynamically allocated as data rows are added to the
+     * window. Depending on the amount of data stored, the actual amount of memory allocated can be
+     * lower than specified size, but cannot exceed it.
+     */
+    public CursorWindow(String name, @BytesLong long windowSizeBytes) {
         mStartPos = 0;
         mName = name != null && name.length() != 0 ? name : "<unnamed>";
-        if (sCursorWindowSize < 0) {
-            /** The cursor window size. resource xml file specifies the value in kB.
-             * convert it to bytes here by multiplying with 1024.
-             */
-            sCursorWindowSize = Resources.getSystem().getInteger(
-                com.android.internal.R.integer.config_cursorWindowSize) * 1024;
-        }
-        mWindowPtr = nativeCreate(mName, sCursorWindowSize);
+        mWindowPtr = nativeCreate(mName, (int) windowSizeBytes);
         if (mWindowPtr == 0) {
             throw new CursorWindowAllocationException("Cursor window allocation of " +
-                    (sCursorWindowSize / 1024) + " kb failed. " + printStats());
+                    windowSizeBytes + " bytes failed. " + printStats());
         }
         mCloseGuard.open("close");
         recordNewWindow(Binder.getCallingPid(), mWindowPtr);
@@ -773,6 +784,16 @@
         return "# Open Cursors=" + total + s;
     }
 
+    private static int getCursorWindowSize() {
+        if (sCursorWindowSize < 0) {
+            // The cursor window size. resource xml file specifies the value in kB.
+            // convert it to bytes here by multiplying with 1024.
+            sCursorWindowSize = Resources.getSystem().getInteger(
+                    com.android.internal.R.integer.config_cursorWindowSize) * 1024;
+        }
+        return sCursorWindowSize;
+    }
+
     @Override
     public String toString() {
         return getName() + " {" + Long.toHexString(mWindowPtr) + "}";
diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java
index 29177b6..185215a 100644
--- a/core/java/android/inputmethodservice/AbstractInputMethodService.java
+++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java
@@ -16,6 +16,7 @@
 
 package android.inputmethodservice;
 
+import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.app.Service;
 import android.content.Intent;
@@ -62,6 +63,7 @@
          * back to {@link AbstractInputMethodService#onCreateInputMethodSessionInterface()
          * AbstractInputMethodService.onCreateInputMethodSessionInterface()}.
          */
+        @MainThread
         public void createSession(SessionCallback callback) {
             callback.sessionCreated(onCreateInputMethodSessionInterface());
         }
@@ -71,6 +73,7 @@
          * {@link AbstractInputMethodSessionImpl#revokeSelf()
          * AbstractInputMethodSessionImpl.setEnabled()} method.
          */
+        @MainThread
         public void setSessionEnabled(InputMethodSession session, boolean enabled) {
             ((AbstractInputMethodSessionImpl)session).setEnabled(enabled);
         }
@@ -80,6 +83,7 @@
          * {@link AbstractInputMethodSessionImpl#revokeSelf()
          * AbstractInputMethodSessionImpl.revokeSelf()} method.
          */
+        @MainThread
         public void revokeSession(InputMethodSession session) {
             ((AbstractInputMethodSessionImpl)session).revokeSelf();
         }
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 765aff9..2468225f 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -16,14 +16,8 @@
 
 package android.inputmethodservice;
 
-import com.android.internal.os.HandlerCaller;
-import com.android.internal.os.SomeArgs;
-import com.android.internal.view.IInputContext;
-import com.android.internal.view.IInputMethod;
-import com.android.internal.view.IInputMethodSession;
-import com.android.internal.view.IInputSessionCallback;
-import com.android.internal.view.InputConnectionWrapper;
-
+import android.annotation.BinderThread;
+import android.annotation.MainThread;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Binder;
@@ -41,6 +35,14 @@
 import android.view.inputmethod.InputMethodSession;
 import android.view.inputmethod.InputMethodSubtype;
 
+import com.android.internal.os.HandlerCaller;
+import com.android.internal.os.SomeArgs;
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethod;
+import com.android.internal.view.IInputMethodSession;
+import com.android.internal.view.IInputSessionCallback;
+import com.android.internal.view.InputConnectionWrapper;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
@@ -67,17 +69,13 @@
     private static final int DO_SHOW_SOFT_INPUT = 60;
     private static final int DO_HIDE_SOFT_INPUT = 70;
     private static final int DO_CHANGE_INPUTMETHOD_SUBTYPE = 80;
-   
+
     final WeakReference<AbstractInputMethodService> mTarget;
     final Context mContext;
     final HandlerCaller mCaller;
     final WeakReference<InputMethod> mInputMethod;
     final int mTargetSdkVersion;
-    
-    static class Notifier {
-        boolean notified;
-    }
-    
+
     // NOTE: we should have a cache of these.
     static final class InputMethodSessionCallbackWrapper implements InputMethod.SessionCallback {
         final Context mContext;
@@ -108,20 +106,16 @@
             }
         }
     }
-    
-    public IInputMethodWrapper(AbstractInputMethodService context,
-            InputMethod inputMethod) {
-        mTarget = new WeakReference<AbstractInputMethodService>(context);
+
+    public IInputMethodWrapper(AbstractInputMethodService context, InputMethod inputMethod) {
+        mTarget = new WeakReference<>(context);
         mContext = context.getApplicationContext();
         mCaller = new HandlerCaller(mContext, null, this, true /*asyncHandler*/);
-        mInputMethod = new WeakReference<InputMethod>(inputMethod);
+        mInputMethod = new WeakReference<>(inputMethod);
         mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
     }
 
-    public InputMethod getInternalInputMethod() {
-        return mInputMethod.get();
-    }
-
+    @MainThread
     @Override
     public void executeMessage(Message msg) {
         InputMethod inputMethod = mInputMethod.get();
@@ -205,6 +199,7 @@
         Log.w(TAG, "Unhandled message code: " + msg.what);
     }
 
+    @BinderThread
     @Override
     protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
         AbstractInputMethodService target = mTarget.get();
@@ -232,11 +227,13 @@
         }
     }
 
+    @BinderThread
     @Override
     public void attachToken(IBinder token) {
         mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_ATTACH_TOKEN, token));
     }
 
+    @BinderThread
     @Override
     public void bindInput(InputBinding binding) {
         // This IInputContext is guaranteed to implement all the methods.
@@ -247,11 +244,13 @@
         mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SET_INPUT_CONTEXT, nu));
     }
 
+    @BinderThread
     @Override
     public void unbindInput() {
         mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_UNSET_INPUT_CONTEXT));
     }
 
+    @BinderThread
     @Override
     public void startInput(IBinder startInputToken, IInputContext inputContext,
             @InputConnectionInspector.MissingMethodFlags final int missingMethods,
@@ -260,12 +259,14 @@
                 missingMethods, restarting ? 1 : 0, startInputToken, inputContext, attribute));
     }
 
+    @BinderThread
     @Override
     public void createSession(InputChannel channel, IInputSessionCallback callback) {
         mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_CREATE_SESSION,
                 channel, callback));
     }
 
+    @BinderThread
     @Override
     public void setSessionEnabled(IInputMethodSession session, boolean enabled) {
         try {
@@ -282,6 +283,7 @@
         }
     }
 
+    @BinderThread
     @Override
     public void revokeSession(IInputMethodSession session) {
         try {
@@ -297,18 +299,21 @@
         }
     }
 
+    @BinderThread
     @Override
     public void showSoftInput(int flags, ResultReceiver resultReceiver) {
         mCaller.executeOrSendMessage(mCaller.obtainMessageIO(DO_SHOW_SOFT_INPUT,
                 flags, resultReceiver));
     }
 
+    @BinderThread
     @Override
     public void hideSoftInput(int flags, ResultReceiver resultReceiver) {
         mCaller.executeOrSendMessage(mCaller.obtainMessageIO(DO_HIDE_SOFT_INPUT,
                 flags, resultReceiver));
     }
 
+    @BinderThread
     @Override
     public void changeInputMethodSubtype(InputMethodSubtype subtype) {
         mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_CHANGE_INPUTMETHOD_SUBTYPE,
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 7a20943..223ed73 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -382,8 +382,10 @@
      */
     public class InputMethodImpl extends AbstractInputMethodImpl {
         /**
-         * Take care of attaching the given window token provided by the system.
+         * {@inheritDoc}
          */
+        @MainThread
+        @Override
         public void attachToken(IBinder token) {
             if (mToken == null) {
                 mToken = token;
@@ -392,10 +394,12 @@
         }
         
         /**
-         * Handle a new input binding, calling
-         * {@link InputMethodService#onBindInput InputMethodService.onBindInput()}
-         * when done.
+         * {@inheritDoc}
+         *
+         * <p>Calls {@link InputMethodService#onBindInput()} when done.</p>
          */
+        @MainThread
+        @Override
         public void bindInput(InputBinding binding) {
             mInputBinding = binding;
             mInputConnection = binding.getConnection();
@@ -409,8 +413,12 @@
         }
 
         /**
-         * Clear the current input binding.
+         * {@inheritDoc}
+         *
+         * <p>Calls {@link InputMethodService#onUnbindInput()} when done.</p>
          */
+        @MainThread
+        @Override
         public void unbindInput() {
             if (DEBUG) Log.v(TAG, "unbindInput(): binding=" + mInputBinding
                     + " ic=" + mInputConnection);
@@ -419,11 +427,21 @@
             mInputConnection = null;
         }
 
+        /**
+         * {@inheritDoc}
+         */
+        @MainThread
+        @Override
         public void startInput(InputConnection ic, EditorInfo attribute) {
             if (DEBUG) Log.v(TAG, "startInput(): editor=" + attribute);
             doStartInput(ic, attribute, false);
         }
 
+        /**
+         * {@inheritDoc}
+         */
+        @MainThread
+        @Override
         public void restartInput(InputConnection ic, EditorInfo attribute) {
             if (DEBUG) Log.v(TAG, "restartInput(): editor=" + attribute);
             doStartInput(ic, attribute, true);
@@ -433,6 +451,7 @@
          * {@inheritDoc}
          * @hide
          */
+        @MainThread
         @Override
         public void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
                 @NonNull EditorInfo editorInfo, boolean restarting,
@@ -447,8 +466,10 @@
         }
 
         /**
-         * Handle a request by the system to hide the soft input area.
+         * {@inheritDoc}
          */
+        @MainThread
+        @Override
         public void hideSoftInput(int flags, ResultReceiver resultReceiver) {
             if (DEBUG) Log.v(TAG, "hideSoftInput()");
             boolean wasVis = isInputViewShown();
@@ -465,8 +486,10 @@
         }
 
         /**
-         * Handle a request by the system to show the soft input area.
+         * {@inheritDoc}
          */
+        @MainThread
+        @Override
         public void showSoftInput(int flags, ResultReceiver resultReceiver) {
             if (DEBUG) Log.v(TAG, "showSoftInput()");
             boolean wasVis = isInputViewShown();
@@ -495,6 +518,11 @@
             }
         }
 
+        /**
+         * {@inheritDoc}
+         */
+        @MainThread
+        @Override
         public void changeInputMethodSubtype(InputMethodSubtype subtype) {
             onCurrentInputMethodSubtypeChanged(subtype);
         }
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index 79310e2..16b1452 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -31,7 +31,6 @@
  * RFC 4301.
  */
 public final class IpSecAlgorithm implements Parcelable {
-
     /**
      * AES-CBC Encryption/Ciphering Algorithm.
      *
@@ -68,6 +67,7 @@
      * <p>Valid truncation lengths are multiples of 8 bits from 192 to (default) 384.
      */
     public static final String AUTH_HMAC_SHA384 = "hmac(sha384)";
+
     /**
      * SHA512 HMAC Authentication/Integrity Algorithm
      *
@@ -75,8 +75,24 @@
      */
     public static final String AUTH_HMAC_SHA512 = "hmac(sha512)";
 
+    /**
+     * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm.
+     *
+     * <p>Valid lengths for this key are {128, 192, 256}.
+     *
+     * <p>Valid ICV (truncation) lengths are {64, 96, 128}.
+     */
+    public static final String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))";
+
     /** @hide */
-    @StringDef({CRYPT_AES_CBC, AUTH_HMAC_MD5, AUTH_HMAC_SHA1, AUTH_HMAC_SHA256, AUTH_HMAC_SHA512})
+    @StringDef({
+        CRYPT_AES_CBC,
+        AUTH_HMAC_MD5,
+        AUTH_HMAC_SHA1,
+        AUTH_HMAC_SHA256,
+        AUTH_HMAC_SHA512,
+        AUTH_CRYPT_AES_GCM
+    })
     @Retention(RetentionPolicy.SOURCE)
     public @interface AlgorithmName {}
 
@@ -102,7 +118,7 @@
      * @param algoName precise name of the algorithm to be used.
      * @param key non-null Key padded to a multiple of 8 bits.
      * @param truncLenBits the number of bits of output hash to use; only meaningful for
-     *     Authentication.
+     *     Authentication or Authenticated Encryption (equivalent to ICV length).
      */
     public IpSecAlgorithm(@AlgorithmName String algoName, byte[] key, int truncLenBits) {
         if (!isTruncationLengthValid(algoName, truncLenBits)) {
@@ -175,6 +191,8 @@
                 return (truncLenBits >= 192 && truncLenBits <= 384);
             case AUTH_HMAC_SHA512:
                 return (truncLenBits >= 256 && truncLenBits <= 512);
+            case AUTH_CRYPT_AES_GCM:
+                return (truncLenBits == 64 || truncLenBits == 96 || truncLenBits == 128);
             default:
                 return false;
         }
diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java
index 632b7fc..61b13a9 100644
--- a/core/java/android/net/IpSecConfig.java
+++ b/core/java/android/net/IpSecConfig.java
@@ -50,6 +50,9 @@
         // Authentication Algorithm
         private IpSecAlgorithm mAuthentication;
 
+        // Authenticated Encryption Algorithm
+        private IpSecAlgorithm mAuthenticatedEncryption;
+
         @Override
         public String toString() {
             return new StringBuilder()
@@ -59,6 +62,8 @@
                     .append(mEncryption)
                     .append(", mAuthentication=")
                     .append(mAuthentication)
+                    .append(", mAuthenticatedEncryption=")
+                    .append(mAuthenticatedEncryption)
                     .append("}")
                     .toString();
         }
@@ -118,6 +123,11 @@
         mFlow[direction].mAuthentication = authentication;
     }
 
+    /** Set the authenticated encryption algorithm for a given direction */
+    public void setAuthenticatedEncryption(int direction, IpSecAlgorithm authenticatedEncryption) {
+        mFlow[direction].mAuthenticatedEncryption = authenticatedEncryption;
+    }
+
     public void setNetwork(Network network) {
         mNetwork = network;
     }
@@ -163,6 +173,10 @@
         return mFlow[direction].mAuthentication;
     }
 
+    public IpSecAlgorithm getAuthenticatedEncryption(int direction) {
+        return mFlow[direction].mAuthenticatedEncryption;
+    }
+
     public Network getNetwork() {
         return mNetwork;
     }
@@ -199,9 +213,11 @@
         out.writeInt(mFlow[IpSecTransform.DIRECTION_IN].mSpiResourceId);
         out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mEncryption, flags);
         out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mAuthentication, flags);
+        out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mAuthenticatedEncryption, flags);
         out.writeInt(mFlow[IpSecTransform.DIRECTION_OUT].mSpiResourceId);
         out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mEncryption, flags);
         out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mAuthentication, flags);
+        out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mAuthenticatedEncryption, flags);
         out.writeInt(mEncapType);
         out.writeInt(mEncapSocketResourceId);
         out.writeInt(mEncapRemotePort);
@@ -221,11 +237,15 @@
                 (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
         mFlow[IpSecTransform.DIRECTION_IN].mAuthentication =
                 (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
+        mFlow[IpSecTransform.DIRECTION_IN].mAuthenticatedEncryption =
+                (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
         mFlow[IpSecTransform.DIRECTION_OUT].mSpiResourceId = in.readInt();
         mFlow[IpSecTransform.DIRECTION_OUT].mEncryption =
                 (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
         mFlow[IpSecTransform.DIRECTION_OUT].mAuthentication =
                 (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
+        mFlow[IpSecTransform.DIRECTION_OUT].mAuthenticatedEncryption =
+                (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
         mEncapType = in.readInt();
         mEncapSocketResourceId = in.readInt();
         mEncapRemotePort = in.readInt();
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index e15a2c6..48b5bd5 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -281,6 +281,8 @@
          * <p>If encryption is set for a given direction without also providing an SPI for that
          * direction, creation of an IpSecTransform will fail upon calling a build() method.
          *
+         * <p>Authenticated encryption is mutually exclusive with encryption and authentication.
+         *
          * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
          * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied.
          */
@@ -296,6 +298,8 @@
          * <p>If authentication is set for a given direction without also providing an SPI for that
          * direction, creation of an IpSecTransform will fail upon calling a build() method.
          *
+         * <p>Authenticated encryption is mutually exclusive with encryption and authentication.
+         *
          * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
          * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied.
          */
@@ -306,6 +310,29 @@
         }
 
         /**
+         * Add an authenticated encryption algorithm to the transform for the given direction.
+         *
+         * <p>If an authenticated encryption algorithm is set for a given direction without also
+         * providing an SPI for that direction, creation of an IpSecTransform will fail upon calling
+         * a build() method.
+         *
+         * <p>The Authenticated Encryption (AE) class of algorithms are also known as Authenticated
+         * Encryption with Associated Data (AEAD) algorithms, or Combined mode algorithms (as
+         * referred to in RFC 4301)
+         *
+         * <p>Authenticated encryption is mutually exclusive with encryption and authentication.
+         *
+         * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+         * @param algo {@link IpSecAlgorithm} specifying the authenticated encryption algorithm to
+         *     be applied.
+         */
+        public IpSecTransform.Builder setAuthenticatedEncryption(
+                @TransformDirection int direction, IpSecAlgorithm algo) {
+            mConfig.setAuthenticatedEncryption(direction, algo);
+            return this;
+        }
+
+        /**
          * Set the SPI, which uniquely identifies a particular IPsec session from others. Because
          * IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a
          * given destination address.
diff --git a/core/java/android/os/BatteryProperty.java b/core/java/android/os/BatteryProperty.java
index 84119bd..b7e7b17 100644
--- a/core/java/android/os/BatteryProperty.java
+++ b/core/java/android/os/BatteryProperty.java
@@ -43,6 +43,13 @@
         return mValueLong;
     }
 
+    /**
+     * @hide
+     */
+    public void setLong(long val) {
+        mValueLong = val;
+    }
+
     /*
      * Parcel read/write code must be kept in sync with
      * frameworks/native/services/batteryservice/BatteryProperty.cpp
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 450ced4..5995696 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -3161,71 +3161,104 @@
         final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(which);
         final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(which);
         final long powerDrainMaMs = counter.getPowerCounter().getCountLocked(which);
+        // Battery real time
+        final long totalControllerActivityTimeMs
+            = computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which) / 1000;
         long totalTxTimeMs = 0;
         for (LongCounter txState : counter.getTxTimeCounters()) {
             totalTxTimeMs += txState.getCountLocked(which);
         }
-
-        final long totalTimeMs = idleTimeMs + rxTimeMs + totalTxTimeMs;
+        final long sleepTimeMs
+            = totalControllerActivityTimeMs - (idleTimeMs + rxTimeMs + totalTxTimeMs);
 
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  ");
+        sb.append("     ");
+        sb.append(controllerName);
+        sb.append(" Sleep time:  ");
+        formatTimeMs(sb, sleepTimeMs);
+        sb.append("(");
+        sb.append(formatRatioLocked(sleepTimeMs, totalControllerActivityTimeMs));
+        sb.append(")");
+        pw.println(sb.toString());
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("     ");
         sb.append(controllerName);
         sb.append(" Idle time:   ");
         formatTimeMs(sb, idleTimeMs);
         sb.append("(");
-        sb.append(formatRatioLocked(idleTimeMs, totalTimeMs));
+        sb.append(formatRatioLocked(idleTimeMs, totalControllerActivityTimeMs));
         sb.append(")");
         pw.println(sb.toString());
 
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  ");
+        sb.append("     ");
         sb.append(controllerName);
         sb.append(" Rx time:     ");
         formatTimeMs(sb, rxTimeMs);
         sb.append("(");
-        sb.append(formatRatioLocked(rxTimeMs, totalTimeMs));
+        sb.append(formatRatioLocked(rxTimeMs, totalControllerActivityTimeMs));
         sb.append(")");
         pw.println(sb.toString());
 
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  ");
+        sb.append("     ");
         sb.append(controllerName);
         sb.append(" Tx time:     ");
-        formatTimeMs(sb, totalTxTimeMs);
-        sb.append("(");
-        sb.append(formatRatioLocked(totalTxTimeMs, totalTimeMs));
-        sb.append(")");
-        pw.println(sb.toString());
 
-        final int numTxLvls = counter.getTxTimeCounters().length;
+        String [] powerLevel;
+        switch(controllerName) {
+            case "Cellular":
+                powerLevel = new String[] {
+                    "   less than 0dBm: ",
+                    "   0dBm to 8dBm: ",
+                    "   8dBm to 15dBm: ",
+                    "   15dBm to 20dBm: ",
+                    "   above 20dBm: "};
+                break;
+            default:
+                powerLevel = new String[] {"[0]", "[1]", "[2]", "[3]", "[4]"};
+                break;
+        }
+        final int numTxLvls = Math.min(counter.getTxTimeCounters().length, powerLevel.length);
         if (numTxLvls > 1) {
+            pw.println(sb.toString());
             for (int lvl = 0; lvl < numTxLvls; lvl++) {
                 final long txLvlTimeMs = counter.getTxTimeCounters()[lvl].getCountLocked(which);
                 sb.setLength(0);
                 sb.append(prefix);
-                sb.append("    [");
-                sb.append(lvl);
-                sb.append("] ");
+                sb.append("    ");
+                sb.append(powerLevel[lvl]);
+                sb.append(" ");
                 formatTimeMs(sb, txLvlTimeMs);
                 sb.append("(");
-                sb.append(formatRatioLocked(txLvlTimeMs, totalTxTimeMs));
+                sb.append(formatRatioLocked(txLvlTimeMs, totalControllerActivityTimeMs));
                 sb.append(")");
                 pw.println(sb.toString());
             }
+        } else {
+            final long txLvlTimeMs = counter.getTxTimeCounters()[0].getCountLocked(which);
+            formatTimeMs(sb, txLvlTimeMs);
+            sb.append("(");
+            sb.append(formatRatioLocked(txLvlTimeMs, totalControllerActivityTimeMs));
+            sb.append(")");
+            pw.println(sb.toString());
         }
 
-        sb.setLength(0);
-        sb.append(prefix);
-        sb.append("  ");
-        sb.append(controllerName);
-        sb.append(" Power drain: ").append(
+        if (powerDrainMaMs > 0) {
+            sb.setLength(0);
+            sb.append(prefix);
+            sb.append("     ");
+            sb.append(controllerName);
+            sb.append(" Battery drain: ").append(
                 BatteryStatsHelper.makemAh(powerDrainMaMs / (double) (1000*60*60)));
-        sb.append("mAh");
-        pw.println(sb.toString());
+            sb.append("mAh");
+            pw.println(sb.toString());
+        }
     }
 
     /**
@@ -4297,51 +4330,50 @@
             pw.println(sb.toString());
         }
 
+        pw.println("");
         pw.print(prefix);
-                pw.print("  Mobile total received: "); pw.print(formatBytesLocked(mobileRxTotalBytes));
-                pw.print(", sent: "); pw.print(formatBytesLocked(mobileTxTotalBytes));
-                pw.print(" (packets received "); pw.print(mobileRxTotalPackets);
-                pw.print(", sent "); pw.print(mobileTxTotalPackets); pw.println(")");
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  Phone signal levels:");
-        didOne = false;
-        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
-            final long time = getPhoneSignalStrengthTime(i, rawRealtime, which);
-            if (time == 0) {
-                continue;
-            }
-            sb.append("\n    ");
-            sb.append(prefix);
-            didOne = true;
-            sb.append(SignalStrength.SIGNAL_STRENGTH_NAMES[i]);
-            sb.append(" ");
-            formatTimeMs(sb, time/1000);
-            sb.append("(");
-            sb.append(formatRatioLocked(time, whichBatteryRealtime));
-            sb.append(") ");
-            sb.append(getPhoneSignalStrengthCount(i, which));
-            sb.append("x");
-        }
-        if (!didOne) sb.append(" (no activity)");
+        sb.append("  CONNECTIVITY POWER SUMMARY START");
+        pw.println(sb.toString());
+
+        pw.print(prefix);
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  Logging duration for connectivity statistics: ");
+        formatTimeMs(sb, whichBatteryRealtime / 1000);
         pw.println(sb.toString());
 
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  Signal scanning time: ");
-        formatTimeMsNoSpace(sb, getPhoneSignalScanningTime(rawRealtime, which) / 1000);
+        sb.append("  Cellular Statistics:");
         pw.println(sb.toString());
 
+        pw.print(prefix);
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("     Cellular kernel active time: ");
+        final long mobileActiveTime = getMobileRadioActiveTime(rawRealtime, which);
+        formatTimeMs(sb, mobileActiveTime / 1000);
+        sb.append("("); sb.append(formatRatioLocked(mobileActiveTime, whichBatteryRealtime));
+        sb.append(")");
+        pw.println(sb.toString());
+
+        pw.print("     Cellular data received: "); pw.println(formatBytesLocked(mobileRxTotalBytes));
+        pw.print("     Cellular data sent: "); pw.println(formatBytesLocked(mobileTxTotalBytes));
+        pw.print("     Cellular packets received: "); pw.println(mobileRxTotalPackets);
+        pw.print("     Cellular packets sent: "); pw.println(mobileTxTotalPackets);
+
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  Radio types:");
+        sb.append("     Cellular Radio Access Technology:");
         didOne = false;
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
             final long time = getPhoneDataConnectionTime(i, rawRealtime, which);
             if (time == 0) {
                 continue;
             }
-            sb.append("\n    ");
+            sb.append("\n       ");
             sb.append(prefix);
             didOne = true;
             sb.append(DATA_CONNECTION_NAMES[i]);
@@ -4350,73 +4382,64 @@
             sb.append("(");
             sb.append(formatRatioLocked(time, whichBatteryRealtime));
             sb.append(") ");
-            sb.append(getPhoneDataConnectionCount(i, which));
-            sb.append("x");
         }
         if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
 
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  Mobile radio active time: ");
-        final long mobileActiveTime = getMobileRadioActiveTime(rawRealtime, which);
-        formatTimeMs(sb, mobileActiveTime / 1000);
-        sb.append("("); sb.append(formatRatioLocked(mobileActiveTime, whichBatteryRealtime));
-        sb.append(") "); sb.append(getMobileRadioActiveCount(which));
-        sb.append("x");
+        sb.append("     Cellular Rx signal strength (RSRP):");
+        final String[] cellularRxSignalStrengthDescription = new String[]{
+            "very poor (less than -128dBm): ",
+            "poor (-128dBm to -118dBm): ",
+            "moderate (-118dBm to -108dBm): ",
+            "good (-108dBm to -98dBm): ",
+            "great (greater than -98dBm): "};
+        didOne = false;
+        final int numCellularRxBins = Math.min(SignalStrength.NUM_SIGNAL_STRENGTH_BINS,
+            cellularRxSignalStrengthDescription.length);
+        for (int i=0; i<numCellularRxBins; i++) {
+            final long time = getPhoneSignalStrengthTime(i, rawRealtime, which);
+            if (time == 0) {
+                continue;
+            }
+            sb.append("\n       ");
+            sb.append(prefix);
+            didOne = true;
+            sb.append(cellularRxSignalStrengthDescription[i]);
+            sb.append(" ");
+            formatTimeMs(sb, time/1000);
+            sb.append("(");
+            sb.append(formatRatioLocked(time, whichBatteryRealtime));
+            sb.append(") ");
+        }
+        if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
 
-        final long mobileActiveUnknownTime = getMobileRadioActiveUnknownTime(which);
-        if (mobileActiveUnknownTime != 0) {
-            sb.setLength(0);
-            sb.append(prefix);
-            sb.append("  Mobile radio active unknown time: ");
-            formatTimeMs(sb, mobileActiveUnknownTime / 1000);
-            sb.append("(");
-            sb.append(formatRatioLocked(mobileActiveUnknownTime, whichBatteryRealtime));
-            sb.append(") "); sb.append(getMobileRadioActiveUnknownCount(which));
-            sb.append("x");
-            pw.println(sb.toString());
-        }
-
-        final long mobileActiveAdjustedTime = getMobileRadioActiveAdjustedTime(which);
-        if (mobileActiveAdjustedTime != 0) {
-            sb.setLength(0);
-            sb.append(prefix);
-            sb.append("  Mobile radio active adjusted time: ");
-            formatTimeMs(sb, mobileActiveAdjustedTime / 1000);
-            sb.append("(");
-            sb.append(formatRatioLocked(mobileActiveAdjustedTime, whichBatteryRealtime));
-            sb.append(")");
-            pw.println(sb.toString());
-        }
-
-        printControllerActivity(pw, sb, prefix, "Radio", getModemControllerActivity(), which);
+        printControllerActivity(pw, sb, prefix, "Cellular",
+            getModemControllerActivity(), which);
 
         pw.print(prefix);
-                pw.print("  Wi-Fi total received: "); pw.print(formatBytesLocked(wifiRxTotalBytes));
-                pw.print(", sent: "); pw.print(formatBytesLocked(wifiTxTotalBytes));
-                pw.print(" (packets received "); pw.print(wifiRxTotalPackets);
-                pw.print(", sent "); pw.print(wifiTxTotalPackets); pw.println(")");
         sb.setLength(0);
         sb.append(prefix);
-                sb.append("  Wifi on: "); formatTimeMs(sb, wifiOnTime / 1000);
-                sb.append("("); sb.append(formatRatioLocked(wifiOnTime, whichBatteryRealtime));
-                sb.append("), Wifi running: "); formatTimeMs(sb, wifiRunningTime / 1000);
-                sb.append("("); sb.append(formatRatioLocked(wifiRunningTime, whichBatteryRealtime));
-                sb.append(")");
+        sb.append("  Wifi Statistics:");
         pw.println(sb.toString());
 
+        pw.print("     Wifi data received: "); pw.println(formatBytesLocked(wifiRxTotalBytes));
+        pw.print("     Wifi data sent: "); pw.println(formatBytesLocked(wifiTxTotalBytes));
+        pw.print("     Wifi packets received: "); pw.println(wifiRxTotalPackets);
+        pw.print("     Wifi packets sent: "); pw.println(wifiTxTotalPackets);
+
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  Wifi states:");
+        sb.append("     Wifi states:");
         didOne = false;
         for (int i=0; i<NUM_WIFI_STATES; i++) {
             final long time = getWifiStateTime(i, rawRealtime, which);
             if (time == 0) {
                 continue;
             }
-            sb.append("\n    ");
+            sb.append("\n       ");
             didOne = true;
             sb.append(WIFI_STATE_NAMES[i]);
             sb.append(" ");
@@ -4424,22 +4447,20 @@
             sb.append("(");
             sb.append(formatRatioLocked(time, whichBatteryRealtime));
             sb.append(") ");
-            sb.append(getWifiStateCount(i, which));
-            sb.append("x");
         }
         if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
 
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  Wifi supplicant states:");
+        sb.append("     Wifi supplicant states:");
         didOne = false;
         for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
             final long time = getWifiSupplStateTime(i, rawRealtime, which);
             if (time == 0) {
                 continue;
             }
-            sb.append("\n    ");
+            sb.append("\n       ");
             didOne = true;
             sb.append(WIFI_SUPPL_STATE_NAMES[i]);
             sb.append(" ");
@@ -4447,17 +4468,23 @@
             sb.append("(");
             sb.append(formatRatioLocked(time, whichBatteryRealtime));
             sb.append(") ");
-            sb.append(getWifiSupplStateCount(i, which));
-            sb.append("x");
         }
         if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
 
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  Wifi signal levels:");
+        sb.append("     Wifi Rx signal strength (RSSI):");
+        final String[] wifiRxSignalStrengthDescription = new String[]{
+            "very poor (less than -88.75dBm): ",
+            "poor (-88.75 to -77.5dBm): ",
+            "moderate (-77.5dBm to -66.25dBm): ",
+            "good (-66.25dBm to -55dBm): ",
+            "great (greater than -55dBm): "};
         didOne = false;
-        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
+        final int numWifiRxBins = Math.min(NUM_WIFI_SIGNAL_STRENGTH_BINS,
+            wifiRxSignalStrengthDescription.length);
+        for (int i=0; i<numWifiRxBins; i++) {
             final long time = getWifiSignalStrengthTime(i, rawRealtime, which);
             if (time == 0) {
                 continue;
@@ -4465,15 +4492,12 @@
             sb.append("\n    ");
             sb.append(prefix);
             didOne = true;
-            sb.append("level(");
-            sb.append(i);
-            sb.append(") ");
+            sb.append("     ");
+            sb.append(wifiRxSignalStrengthDescription[i]);
             formatTimeMs(sb, time/1000);
             sb.append("(");
             sb.append(formatRatioLocked(time, whichBatteryRealtime));
             sb.append(") ");
-            sb.append(getWifiSignalStrengthCount(i, which));
-            sb.append("x");
         }
         if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
@@ -4481,6 +4505,13 @@
         printControllerActivity(pw, sb, prefix, "WiFi", getWifiControllerActivity(), which);
 
         pw.print(prefix);
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  CONNECTIVITY POWER SUMMARY END");
+        pw.println(sb.toString());
+        pw.println("");
+
+        pw.print(prefix);
         pw.print("  Bluetooth total received: "); pw.print(formatBytesLocked(btRxTotalBytes));
         pw.print(", sent: "); pw.println(formatBytesLocked(btTxTotalBytes));
 
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index b46c6b1..017c213 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1748,22 +1748,26 @@
     public static final int MEMINFO_SHMEM = 4;
     /** @hide */
     public static final int MEMINFO_SLAB = 5;
+     /** @hide */
+    public static final int MEMINFO_SLAB_RECLAIMABLE = 6;
+     /** @hide */
+    public static final int MEMINFO_SLAB_UNRECLAIMABLE = 7;
     /** @hide */
-    public static final int MEMINFO_SWAP_TOTAL = 6;
+    public static final int MEMINFO_SWAP_TOTAL = 8;
     /** @hide */
-    public static final int MEMINFO_SWAP_FREE = 7;
+    public static final int MEMINFO_SWAP_FREE = 9;
     /** @hide */
-    public static final int MEMINFO_ZRAM_TOTAL = 8;
+    public static final int MEMINFO_ZRAM_TOTAL = 10;
     /** @hide */
-    public static final int MEMINFO_MAPPED = 9;
+    public static final int MEMINFO_MAPPED = 11;
     /** @hide */
-    public static final int MEMINFO_VM_ALLOC_USED = 10;
+    public static final int MEMINFO_VM_ALLOC_USED = 12;
     /** @hide */
-    public static final int MEMINFO_PAGE_TABLES = 11;
+    public static final int MEMINFO_PAGE_TABLES = 13;
     /** @hide */
-    public static final int MEMINFO_KERNEL_STACK = 12;
+    public static final int MEMINFO_KERNEL_STACK = 14;
     /** @hide */
-    public static final int MEMINFO_COUNT = 13;
+    public static final int MEMINFO_COUNT = 15;
 
     /**
      * Retrieves /proc/meminfo.  outSizes is filled with fields
diff --git a/core/java/android/os/PatternMatcher.java b/core/java/android/os/PatternMatcher.java
index 1f3a1e6..76b2142 100644
--- a/core/java/android/os/PatternMatcher.java
+++ b/core/java/android/os/PatternMatcher.java
@@ -16,7 +16,7 @@
 
 package android.os;
 
-import android.util.Log;
+import android.util.proto.ProtoOutputStream;
 
 import java.util.Arrays;
 
@@ -131,7 +131,17 @@
         }
         return "PatternMatcher{" + type + mPattern + "}";
     }
-    
+
+    /** @hide */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        long token = proto.start(fieldId);
+        proto.write(PatternMatcherProto.PATTERN, mPattern);
+        proto.write(PatternMatcherProto.TYPE, mType);
+        // PatternMatcherProto.PARSED_PATTERN is too much to dump, but the field is reserved to
+        // match the current data structure.
+        proto.end(token);
+    }
+
     public int describeContents() {
         return 0;
     }
@@ -141,7 +151,7 @@
         dest.writeInt(mType);
         dest.writeIntArray(mParsedPattern);
     }
-    
+
     public PatternMatcher(Parcel src) {
         mPattern = src.readString();
         mType = src.readInt();
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index 560b4b3..4f6d322 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -84,9 +84,6 @@
     /**
      * Get the String value for the given {@code key}.
      *
-     * <b>WARNING:</b> Do not use this method if the value may not be a valid UTF string! This
-     * method will crash in native code.
-     *
      * @param key the key to lookup
      * @return an empty string if the {@code key} isn't found
      */
@@ -99,9 +96,6 @@
     /**
      * Get the String value for the given {@code key}.
      *
-     * <b>WARNING:</b> Do not use this method if the value may not be a valid UTF string! This
-     * method will crash in native code.
-     *
      * @param key the key to lookup
      * @param def the default value in case the property is not set or empty
      * @return if the {@code key} isn't found, return {@code def} if it isn't null, or an empty
@@ -163,7 +157,7 @@
      * @throws IllegalArgumentException if the {@code val} exceeds 91 characters
      */
     public static void set(@NonNull String key, @Nullable String val) {
-        if (val != null && val.length() > PROP_VALUE_MAX) {
+        if (val != null && !val.startsWith("ro.") && val.length() > PROP_VALUE_MAX) {
             throw new IllegalArgumentException("value of system property '" + key
                     + "' is longer than " + PROP_VALUE_MAX + " characters: " + val);
         }
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index ee8eed1..3d2e1d1 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -206,8 +206,7 @@
                     try {
                         mRingtone.setAudioAttributes(new AudioAttributes.Builder(mRingtone
                                 .getAudioAttributes())
-                                .setFlags(AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY |
-                                        AudioAttributes.FLAG_BYPASS_MUTE)
+                                .setFlags(AudioAttributes.FLAG_BYPASS_MUTE)
                                 .build());
                         mRingtone.play();
                     } catch (Throwable e) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a062db4..c200ae7 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -442,6 +442,18 @@
             "android.settings.ASSIST_GESTURE_SETTINGS";
 
     /**
+     * Activity Action: Show settings to enroll fingerprints, and setup PIN/Pattern/Pass if
+     * necessary.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_FINGERPRINT_ENROLL =
+            "android.settings.FINGERPRINT_ENROLL";
+
+    /**
      * Activity Action: Show settings to allow configuration of cast endpoints.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
@@ -5708,6 +5720,7 @@
          *
          * @hide
          */
+        @TestApi
         public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED =
                 "accessibility_display_magnification_enabled";
 
@@ -6792,14 +6805,6 @@
                 "lock_screen_show_notifications";
 
         /**
-         * This preference stores the last stack active task time for each user, which affects what
-         * tasks will be visible in Overview.
-         * @hide
-         */
-        public static final String OVERVIEW_LAST_STACK_ACTIVE_TIME =
-                "overview_last_stack_active_time";
-
-        /**
          * List of TV inputs that are currently hidden. This is a string
          * containing the IDs of all hidden TV inputs. Each ID is encoded by
          * {@link android.net.Uri#encode(String)} and separated by ':'.
@@ -9261,6 +9266,13 @@
          */
         public static final String DEFAULT_DNS_SERVER = "default_dns_server";
 
+        /**
+         * Whether to disable DNS over TLS (boolean)
+         *
+         * @hide
+         */
+        public static final String DNS_TLS_DISABLED = "dns_tls_disabled";
+
         /** {@hide} */
         public static final String
                 BLUETOOTH_HEADSET_PRIORITY_PREFIX = "bluetooth_headset_priority_";
@@ -9575,6 +9587,22 @@
         public static final String DEVICE_POLICY_CONSTANTS = "device_policy_constants";
 
         /**
+         * TextClassifier specific settings.
+         * This is encoded as a key=value list, separated by commas. Ex:
+         *
+         * <pre>
+         * smart_selection_dark_launch              (boolean)
+         * smart_selection_enabled_for_edit_text    (boolean)
+         * </pre>
+         *
+         * <p>
+         * Type: string
+         * @hide
+         * see also android.view.textclassifier.TextClassifierConstants
+         */
+        public static final String TEXT_CLASSIFIER_CONSTANTS = "text_classifier_constants";
+
+        /**
          * Get the key that retrieves a bluetooth headset's priority.
          * @hide
          */
diff --git a/core/java/android/security/net/config/ManifestConfigSource.java b/core/java/android/security/net/config/ManifestConfigSource.java
index 8fcd5ab..79115a5 100644
--- a/core/java/android/security/net/config/ManifestConfigSource.java
+++ b/core/java/android/security/net/config/ManifestConfigSource.java
@@ -20,6 +20,7 @@
 import android.content.pm.ApplicationInfo;
 import android.util.Log;
 import android.util.Pair;
+
 import java.util.Set;
 
 /** @hide */
@@ -29,21 +30,14 @@
 
     private final Object mLock = new Object();
     private final Context mContext;
-    private final int mApplicationInfoFlags;
-    private final int mTargetSdkVersion;
-    private final int mConfigResourceId;
-    private final int mTargetSandboxVesrsion;
+    private final ApplicationInfo mApplicationInfo;
 
     private ConfigSource mConfigSource;
 
     public ManifestConfigSource(Context context) {
         mContext = context;
-        // Cache values because ApplicationInfo is mutable and apps do modify it :(
-        ApplicationInfo info = context.getApplicationInfo();
-        mApplicationInfoFlags = info.flags;
-        mTargetSdkVersion = info.targetSdkVersion;
-        mConfigResourceId = info.networkSecurityConfigRes;
-        mTargetSandboxVesrsion = info.targetSandboxVersion;
+        // Cache the info because ApplicationInfo is mutable and apps do modify it :(
+        mApplicationInfo = new ApplicationInfo(context.getApplicationInfo());
     }
 
     @Override
@@ -61,17 +55,18 @@
             if (mConfigSource != null) {
                 return mConfigSource;
             }
-
+            int configResource = mApplicationInfo.networkSecurityConfigRes;
             ConfigSource source;
-            if (mConfigResourceId != 0) {
-                boolean debugBuild = (mApplicationInfoFlags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+            if (configResource != 0) {
+                boolean debugBuild =
+                        (mApplicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
                 if (DBG) {
                     Log.d(LOG_TAG, "Using Network Security Config from resource "
-                            + mContext.getResources().getResourceEntryName(mConfigResourceId)
+                            + mContext.getResources()
+                                .getResourceEntryName(configResource)
                             + " debugBuild: " + debugBuild);
                 }
-                source = new XmlConfigSource(mContext, mConfigResourceId, debugBuild,
-                        mTargetSdkVersion, mTargetSandboxVesrsion);
+                source = new XmlConfigSource(mContext, configResource, mApplicationInfo);
             } else {
                 if (DBG) {
                     Log.d(LOG_TAG, "No Network Security Config specified, using platform default");
@@ -79,10 +74,9 @@
                 // the legacy FLAG_USES_CLEARTEXT_TRAFFIC is not supported for Ephemeral apps, they
                 // should use the network security config.
                 boolean usesCleartextTraffic =
-                        (mApplicationInfoFlags & ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC) != 0
-                        && mTargetSandboxVesrsion < 2;
-                source = new DefaultConfigSource(usesCleartextTraffic, mTargetSdkVersion,
-                        mTargetSandboxVesrsion);
+                        (mApplicationInfo.flags & ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC) != 0
+                        && mApplicationInfo.targetSandboxVersion < 2;
+                source = new DefaultConfigSource(usesCleartextTraffic, mApplicationInfo);
             }
             mConfigSource = source;
             return mConfigSource;
@@ -93,10 +87,8 @@
 
         private final NetworkSecurityConfig mDefaultConfig;
 
-        public DefaultConfigSource(boolean usesCleartextTraffic, int targetSdkVersion,
-                int targetSandboxVesrsion) {
-            mDefaultConfig = NetworkSecurityConfig.getDefaultBuilder(targetSdkVersion,
-                    targetSandboxVesrsion)
+        DefaultConfigSource(boolean usesCleartextTraffic, ApplicationInfo info) {
+            mDefaultConfig = NetworkSecurityConfig.getDefaultBuilder(info)
                     .setCleartextTrafficPermitted(usesCleartextTraffic)
                     .build();
         }
diff --git a/core/java/android/security/net/config/NetworkSecurityConfig.java b/core/java/android/security/net/config/NetworkSecurityConfig.java
index 789fc27..b9e5505 100644
--- a/core/java/android/security/net/config/NetworkSecurityConfig.java
+++ b/core/java/android/security/net/config/NetworkSecurityConfig.java
@@ -16,9 +16,11 @@
 
 package android.security.net.config;
 
+import android.content.pm.ApplicationInfo;
 import android.os.Build;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -28,8 +30,6 @@
 import java.util.Map;
 import java.util.Set;
 
-import javax.net.ssl.X509TrustManager;
-
 /**
  * @hide
  */
@@ -170,22 +170,24 @@
      * <li>No certificate pinning is used.</li>
      * <li>The system certificate store is trusted for connections.</li>
      * <li>If the application targets API level 23 (Android M) or lower then the user certificate
-     * store is trusted by default as well.</li>
+     * store is trusted by default as well for non-privileged applications.</li>
+     * <li>Privileged applications do not trust the user certificate store on Android P and higher.
+     * </li>
      * </ol>
      *
      * @hide
      */
-    public static final Builder getDefaultBuilder(int targetSdkVersion, int targetSandboxVesrsion) {
+    public static Builder getDefaultBuilder(ApplicationInfo info) {
         Builder builder = new Builder()
                 .setHstsEnforced(DEFAULT_HSTS_ENFORCED)
                 // System certificate store, does not bypass static pins.
                 .addCertificatesEntryRef(
                         new CertificatesEntryRef(SystemCertificateSource.getInstance(), false));
-        final boolean cleartextTrafficPermitted = targetSandboxVesrsion < 2;
+        final boolean cleartextTrafficPermitted = info.targetSandboxVersion < 2;
         builder.setCleartextTrafficPermitted(cleartextTrafficPermitted);
         // Applications targeting N and above must opt in into trusting the user added certificate
         // store.
-        if (targetSdkVersion <= Build.VERSION_CODES.M) {
+        if (info.targetSdkVersion <= Build.VERSION_CODES.M && !info.isPrivilegedApp()) {
             // User certificate store, does not bypass static pins.
             builder.addCertificatesEntryRef(
                     new CertificatesEntryRef(UserCertificateSource.getInstance(), false));
diff --git a/core/java/android/security/net/config/XmlConfigSource.java b/core/java/android/security/net/config/XmlConfigSource.java
index a111fbce..02be403 100644
--- a/core/java/android/security/net/config/XmlConfigSource.java
+++ b/core/java/android/security/net/config/XmlConfigSource.java
@@ -1,13 +1,13 @@
 package android.security.net.config;
 
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
-import android.os.Build;
 import android.util.ArraySet;
 import android.util.Base64;
 import android.util.Pair;
-import com.android.internal.annotations.VisibleForTesting;
+
 import com.android.internal.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -36,37 +36,19 @@
     private final Object mLock = new Object();
     private final int mResourceId;
     private final boolean mDebugBuild;
-    private final int mTargetSdkVersion;
-    private final int mTargetSandboxVesrsion;
+    private final ApplicationInfo mApplicationInfo;
 
     private boolean mInitialized;
     private NetworkSecurityConfig mDefaultConfig;
     private Set<Pair<Domain, NetworkSecurityConfig>> mDomainMap;
     private Context mContext;
 
-    @VisibleForTesting
-    public XmlConfigSource(Context context, int resourceId) {
-        this(context, resourceId, false);
-    }
-
-    @VisibleForTesting
-    public XmlConfigSource(Context context, int resourceId, boolean debugBuild) {
-        this(context, resourceId, debugBuild, Build.VERSION_CODES.CUR_DEVELOPMENT);
-    }
-
-    @VisibleForTesting
-    public XmlConfigSource(Context context, int resourceId, boolean debugBuild,
-            int targetSdkVersion) {
-        this(context, resourceId, debugBuild, targetSdkVersion, 1 /*targetSandboxVersion*/);
-    }
-
-    public XmlConfigSource(Context context, int resourceId, boolean debugBuild,
-            int targetSdkVersion, int targetSandboxVesrsion) {
-        mResourceId = resourceId;
+    public XmlConfigSource(Context context, int resourceId, ApplicationInfo info) {
         mContext = context;
-        mDebugBuild = debugBuild;
-        mTargetSdkVersion = targetSdkVersion;
-        mTargetSandboxVesrsion = targetSandboxVesrsion;
+        mResourceId = resourceId;
+        mApplicationInfo = new ApplicationInfo(info);
+
+        mDebugBuild = (mApplicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
     }
 
     public Set<Pair<Domain, NetworkSecurityConfig>> getPerDomainConfigs() {
@@ -365,7 +347,7 @@
         // Use the platform default as the parent of the base config for any values not provided
         // there. If there is no base config use the platform default.
         NetworkSecurityConfig.Builder platformDefaultBuilder =
-                NetworkSecurityConfig.getDefaultBuilder(mTargetSdkVersion, mTargetSandboxVesrsion);
+                NetworkSecurityConfig.getDefaultBuilder(mApplicationInfo);
         addDebugAnchorsIfNeeded(debugConfigBuilder, platformDefaultBuilder);
         if (baseConfigBuilder != null) {
             baseConfigBuilder.setParent(platformDefaultBuilder);
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 9a25f5b..953501c 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -65,7 +65,7 @@
  *   <li>The service replies through {@link FillCallback#onSuccess(FillResponse)}.
  *   <li>The Android System calls {@link #onDisconnected()} and unbinds from the
  *       {@code AutofillService}.
- *   <li>The Android System displays an UI affordance with the options sent by the service.
+ *   <li>The Android System displays an autofill UI with the options sent by the service.
  *   <li>The user picks an option.
  *   <li>The proper views are autofilled.
  * </ol>
diff --git a/core/java/android/service/autofill/BatchUpdates.java b/core/java/android/service/autofill/BatchUpdates.java
new file mode 100644
index 0000000..90acc88
--- /dev/null
+++ b/core/java/android/service/autofill/BatchUpdates.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import static android.view.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Pair;
+import android.widget.RemoteViews;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+
+/**
+ * Defines actions to be applied to a {@link RemoteViews template presentation}.
+ *
+ *
+ * <p>It supports 2 types of actions:
+ *
+ * <ol>
+ *   <li>{@link RemoteViews Actions} to be applied to the template.
+ *   <li>{@link Transformation Transformations} to be applied on child views.
+ * </ol>
+ *
+ * <p>Typically used on {@link CustomDescription custom descriptions} to conditionally display
+ * differents views based on user input - see
+ * {@link CustomDescription.Builder#batchUpdate(Validator, BatchUpdates)} for more information.
+ */
+public final class BatchUpdates implements Parcelable {
+
+    private final ArrayList<Pair<Integer, InternalTransformation>> mTransformations;
+    private final RemoteViews mUpdates;
+
+    private BatchUpdates(Builder builder) {
+        mTransformations = builder.mTransformations;
+        mUpdates = builder.mUpdates;
+    }
+
+    /** @hide */
+    @Nullable
+    public ArrayList<Pair<Integer, InternalTransformation>> getTransformations() {
+        return mTransformations;
+    }
+
+    /** @hide */
+    @Nullable
+    public RemoteViews getUpdates() {
+        return mUpdates;
+    }
+
+    /**
+     * Builder for {@link BatchUpdates} objects.
+     */
+    public static class Builder {
+        private RemoteViews mUpdates;
+
+        private boolean mDestroyed;
+        private ArrayList<Pair<Integer, InternalTransformation>> mTransformations;
+
+        /**
+         * Applies the {@code updates} in the underlying presentation template.
+         *
+         * <p><b>Note:</b> The updates are applied before the
+         * {@link #transformChild(int, Transformation) transformations} are applied to the children
+         * views.
+         *
+         * @param updates a {@link RemoteViews} with the updated actions to be applied in the
+         * underlying presentation template.
+         *
+         * @return this builder
+         * @throws IllegalArgumentException if {@code condition} is not a class provided
+         * by the Android System.
+         */
+        public Builder updateTemplate(@NonNull RemoteViews updates) {
+            throwIfDestroyed();
+            mUpdates = Preconditions.checkNotNull(updates);
+            return this;
+        }
+
+        /**
+         * Adds a transformation to replace the value of a child view with the fields in the
+         * screen.
+         *
+         * <p>When multiple transformations are added for the same child view, they are applied
+         * in the same order as added.
+         *
+         * <p><b>Note:</b> The transformations are applied after the
+         * {@link #updateTemplate(RemoteViews) updates} are applied to the presentation template.
+         *
+         * @param id view id of the children view.
+         * @param transformation an implementation provided by the Android System.
+         * @return this builder.
+         * @throws IllegalArgumentException if {@code transformation} is not a class provided
+         * by the Android System.
+         */
+        public Builder transformChild(int id, @NonNull Transformation transformation) {
+            throwIfDestroyed();
+            Preconditions.checkArgument((transformation instanceof InternalTransformation),
+                    "not provided by Android System: " + transformation);
+            if (mTransformations == null) {
+                mTransformations = new ArrayList<>();
+            }
+            mTransformations.add(new Pair<>(id, (InternalTransformation) transformation));
+            return this;
+        }
+
+        /**
+         * Creates a new {@link BatchUpdates} instance.
+         *
+         * @throws IllegalStateException if {@link #build()} was already called before or no call
+         * to {@link #updateTemplate(RemoteViews)} or {@link #transformChild(int, Transformation)}
+         * has been made.
+         */
+        public BatchUpdates build() {
+            throwIfDestroyed();
+            Preconditions.checkState(mUpdates != null || mTransformations != null,
+                    "must call either updateTemplate() or transformChild() at least once");
+            mDestroyed = true;
+            return new BatchUpdates(this);
+        }
+
+        private void throwIfDestroyed() {
+            if (mDestroyed) {
+                throw new IllegalStateException("Already called #build()");
+            }
+        }
+    }
+
+    /////////////////////////////////////
+    // Object "contract" methods. //
+    /////////////////////////////////////
+    @Override
+    public String toString() {
+        if (!sDebug) return super.toString();
+
+        return new StringBuilder("BatchUpdates: [")
+                .append(", transformations=")
+                    .append(mTransformations == null ? "N/A" : mTransformations.size())
+                .append(", updates=").append(mUpdates)
+                .append("]").toString();
+    }
+
+    /////////////////////////////////////
+    // Parcelable "contract" methods. //
+    /////////////////////////////////////
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        if (mTransformations == null) {
+            dest.writeIntArray(null);
+        } else {
+            final int size = mTransformations.size();
+            final int[] ids = new int[size];
+            final InternalTransformation[] values = new InternalTransformation[size];
+            for (int i = 0; i < size; i++) {
+                final Pair<Integer, InternalTransformation> pair = mTransformations.get(i);
+                ids[i] = pair.first;
+                values[i] = pair.second;
+            }
+            dest.writeIntArray(ids);
+            dest.writeParcelableArray(values, flags);
+        }
+        dest.writeParcelable(mUpdates, flags);
+    }
+    public static final Parcelable.Creator<BatchUpdates> CREATOR =
+            new Parcelable.Creator<BatchUpdates>() {
+        @Override
+        public BatchUpdates createFromParcel(Parcel parcel) {
+            // Always go through the builder to ensure the data ingested by
+            // the system obeys the contract of the builder to avoid attacks
+            // using specially crafted parcels.
+            final Builder builder = new Builder();
+            final int[] ids = parcel.createIntArray();
+            if (ids != null) {
+                final InternalTransformation[] values =
+                    parcel.readParcelableArray(null, InternalTransformation.class);
+                final int size = ids.length;
+                for (int i = 0; i < size; i++) {
+                    builder.transformChild(ids[i], values[i]);
+                }
+            }
+            final RemoteViews updates = parcel.readParcelable(null);
+            if (updates != null) {
+                builder.updateTemplate(updates);
+            }
+            return builder.build();
+        }
+
+        @Override
+        public BatchUpdates[] newArray(int size) {
+            return new BatchUpdates[size];
+        }
+    };
+}
diff --git a/core/java/android/service/autofill/CustomDescription.java b/core/java/android/service/autofill/CustomDescription.java
index 9a4cbc4..fd30857 100644
--- a/core/java/android/service/autofill/CustomDescription.java
+++ b/core/java/android/service/autofill/CustomDescription.java
@@ -19,11 +19,11 @@
 import static android.view.autofill.Helper.sDebug;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.Log;
 import android.util.Pair;
 import android.widget.RemoteViews;
 
@@ -67,18 +67,18 @@
  * // Image child - different logo for each bank, based on credit card prefix
  * builder.addChild(R.id.templateccLogo,
  *   new ImageTransformation.Builder(ccNumberId)
- *     .addOption(Pattern.compile(""^4815.*$"), R.drawable.ic_credit_card_logo1)
- *     .addOption(Pattern.compile(""^1623.*$"), R.drawable.ic_credit_card_logo2)
- *     .addOption(Pattern.compile(""^42.*$"), R.drawable.ic_credit_card_logo3)
+ *     .addOption(Pattern.compile("^4815.*$"), R.drawable.ic_credit_card_logo1)
+ *     .addOption(Pattern.compile("^1623.*$"), R.drawable.ic_credit_card_logo2)
+ *     .addOption(Pattern.compile("^42.*$"), R.drawable.ic_credit_card_logo3)
  *     .build();
  * // Masked credit card number (as .....LAST_4_DIGITS)
  * builder.addChild(R.id.templateCcNumber, new CharSequenceTransformation
- *     .Builder(ccNumberId, Pattern.compile(""^.*(\\d\\d\\d\\d)$"), "...$1")
+ *     .Builder(ccNumberId, Pattern.compile("^.*(\\d\\d\\d\\d)$"), "...$1")
  *     .build();
  * // Expiration date as MM / YYYY:
  * builder.addChild(R.id.templateExpDate, new CharSequenceTransformation
- *     .Builder(ccExpMonthId, Pattern.compile(""^(\\d\\d)$"), "Exp: $1")
- *     .addField(ccExpYearId, Pattern.compile(""^(\\d\\d)$"), "/$1")
+ *     .Builder(ccExpMonthId, Pattern.compile("^(\\d\\d)$"), "Exp: $1")
+ *     .addField(ccExpYearId, Pattern.compile("^(\\d\\d)$"), "/$1")
  *     .build();
  * </pre>
  *
@@ -87,47 +87,43 @@
  */
 public final class CustomDescription implements Parcelable {
 
-    private static final String TAG = "CustomDescription";
-
     private final RemoteViews mPresentation;
     private final ArrayList<Pair<Integer, InternalTransformation>> mTransformations;
+    private final ArrayList<Pair<InternalValidator, BatchUpdates>> mUpdates;
 
     private CustomDescription(Builder builder) {
         mPresentation = builder.mPresentation;
         mTransformations = builder.mTransformations;
+        mUpdates = builder.mUpdates;
     }
 
     /** @hide */
-    public RemoteViews getPresentation(ValueFinder finder) {
-        if (mTransformations != null) {
-            final int size = mTransformations.size();
-            if (sDebug) Log.d(TAG, "getPresentation(): applying " + size + " transformations");
-            for (int i = 0; i < size; i++) {
-                final Pair<Integer, InternalTransformation> pair = mTransformations.get(i);
-                final int id = pair.first;
-                final InternalTransformation transformation = pair.second;
-                if (sDebug) Log.d(TAG, "#" + i + ": " + transformation);
-
-                try {
-                    transformation.apply(finder, mPresentation, id);
-                } catch (Exception e) {
-                    // Do not log full exception to avoid PII leaking
-                    Log.e(TAG, "Could not apply transformation " + transformation + ": "
-                            + e.getClass());
-                    return null;
-                }
-            }
-        }
+    @Nullable
+    public RemoteViews getPresentation() {
         return mPresentation;
     }
 
+    /** @hide */
+    @Nullable
+    public ArrayList<Pair<Integer, InternalTransformation>> getTransformations() {
+        return mTransformations;
+    }
+
+    /** @hide */
+    @Nullable
+    public ArrayList<Pair<InternalValidator, BatchUpdates>> getUpdates() {
+        return mUpdates;
+    }
+
     /**
      * Builder for {@link CustomDescription} objects.
      */
     public static class Builder {
         private final RemoteViews mPresentation;
 
+        private boolean mDestroyed;
         private ArrayList<Pair<Integer, InternalTransformation>> mTransformations;
+        private ArrayList<Pair<InternalValidator, BatchUpdates>> mUpdates;
 
         /**
          * Default constructor.
@@ -145,9 +141,11 @@
          * </ul>
          *
          * @param parentPresentation template presentation with (optional) children views.
+         * @throws NullPointerException if {@code parentPresentation} is null (on Android
+         * {@link android.os.Build.VERSION_CODES#P} or higher).
          */
-        public Builder(RemoteViews parentPresentation) {
-            mPresentation = parentPresentation;
+        public Builder(@NonNull RemoteViews parentPresentation) {
+            mPresentation = Preconditions.checkNotNull(parentPresentation);
         }
 
         /**
@@ -164,6 +162,7 @@
          * by the Android System.
          */
         public Builder addChild(int id, @NonNull Transformation transformation) {
+            throwIfDestroyed();
             Preconditions.checkArgument((transformation instanceof InternalTransformation),
                     "not provided by Android System: " + transformation);
             if (mTransformations == null) {
@@ -174,11 +173,109 @@
         }
 
         /**
+         * Updates the {@link RemoteViews presentation template} when a condition is satisfied.
+         *
+         * <p>The updates are applied in the sequence they are added, after the
+         * {@link #addChild(int, Transformation) transformations} are applied to the children
+         * views.
+         *
+         * <p>For example, to make children views visible when fields are not empty:
+         *
+         * <pre class="prettyprint">
+         * RemoteViews template = new RemoteViews(pgkName, R.layout.my_full_template);
+         *
+         * Pattern notEmptyPattern = Pattern.compile(".+");
+         * Validator hasAddress = new RegexValidator(addressAutofillId, notEmptyPattern);
+         * Validator hasCcNumber = new RegexValidator(ccNumberAutofillId, notEmptyPattern);
+         *
+         * RemoteViews addressUpdates = new RemoteViews(pgkName, R.layout.my_full_template)
+         * addressUpdates.setViewVisibility(R.id.address, View.VISIBLE);
+         *
+         * // Make address visible
+         * BatchUpdates addressBatchUpdates = new BatchUpdates.Builder()
+         *     .updateTemplate(addressUpdates)
+         *     .build();
+         *
+         * RemoteViews ccUpdates = new RemoteViews(pgkName, R.layout.my_full_template)
+         * ccUpdates.setViewVisibility(R.id.cc_number, View.VISIBLE);
+         *
+         * // Mask credit card number (as .....LAST_4_DIGITS) and make it visible
+         * BatchUpdates ccBatchUpdates = new BatchUpdates.Builder()
+         *     .updateTemplate(ccUpdates)
+         *     .transformChild(R.id.templateCcNumber, new CharSequenceTransformation
+         *                     .Builder(ccNumberId, Pattern.compile("^.*(\\d\\d\\d\\d)$"), "...$1")
+         *                     .build())
+         *     .build();
+         *
+         * CustomDescription customDescription = new CustomDescription.Builder(template)
+         *     .batchUpdate(hasAddress, addressBatchUpdates)
+         *     .batchUpdate(hasCcNumber, ccBatchUpdates)
+         *     .build();
+         * </pre>
+         *
+         * <p>Another approach is to add a child first, then apply the transformations. Example:
+         *
+         * <pre class="prettyprint">
+         * RemoteViews template = new RemoteViews(pgkName, R.layout.my_base_template);
+         *
+         * RemoteViews addressPresentation = new RemoteViews(pgkName, R.layout.address)
+         * RemoteViews addressUpdates = new RemoteViews(pgkName, R.layout.my_template)
+         * addressUpdates.addView(R.id.parentId, addressPresentation);
+         * BatchUpdates addressBatchUpdates = new BatchUpdates.Builder()
+         *     .updateTemplate(addressUpdates)
+         *     .build();
+         *
+         * RemoteViews ccPresentation = new RemoteViews(pgkName, R.layout.cc)
+         * RemoteViews ccUpdates = new RemoteViews(pgkName, R.layout.my_template)
+         * ccUpdates.addView(R.id.parentId, ccPresentation);
+         * BatchUpdates ccBatchUpdates = new BatchUpdates.Builder()
+         *     .updateTemplate(ccUpdates)
+         *     .transformChild(R.id.templateCcNumber, new CharSequenceTransformation
+         *                     .Builder(ccNumberId, Pattern.compile("^.*(\\d\\d\\d\\d)$"), "...$1")
+         *                     .build())
+         *     .build();
+         *
+         * CustomDescription customDescription = new CustomDescription.Builder(template)
+         *     .batchUpdate(hasAddress, addressBatchUpdates)
+         *     .batchUpdate(hasCcNumber, ccBatchUpdates)
+         *     .build();
+         * </pre>
+         *
+         * @param condition condition used to trigger the updates.
+         * @param updates actions to be applied to the
+         * {@link #CustomDescription.Builder(RemoteViews) template presentation} when the condition
+         * is satisfied.
+         *
+         * @return this builder
+         * @throws IllegalArgumentException if {@code condition} is not a class provided
+         * by the Android System.
+         */
+        public Builder batchUpdate(@NonNull Validator condition, @NonNull BatchUpdates updates) {
+            throwIfDestroyed();
+            Preconditions.checkArgument((condition instanceof InternalValidator),
+                    "not provided by Android System: " + condition);
+            Preconditions.checkNotNull(updates);
+            if (mUpdates == null) {
+                mUpdates = new ArrayList<>();
+            }
+            mUpdates.add(new Pair<>((InternalValidator) condition, updates));
+            return this;
+        }
+
+        /**
          * Creates a new {@link CustomDescription} instance.
          */
         public CustomDescription build() {
+            throwIfDestroyed();
+            mDestroyed = true;
             return new CustomDescription(this);
         }
+
+        private void throwIfDestroyed() {
+            if (mDestroyed) {
+                throw new IllegalStateException("Already called #build()");
+            }
+        }
     }
 
     /////////////////////////////////////
@@ -190,7 +287,10 @@
 
         return new StringBuilder("CustomDescription: [presentation=")
                 .append(mPresentation)
-                .append(", transformations=").append(mTransformations)
+                .append(", transformations=")
+                    .append(mTransformations == null ? "N/A" : mTransformations.size())
+                .append(", updates=")
+                    .append(mUpdates == null ? "N/A" : mUpdates.size())
                 .append("]").toString();
     }
 
@@ -205,6 +305,8 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeParcelable(mPresentation, flags);
+        if (mPresentation == null) return;
+
         if (mTransformations == null) {
             dest.writeIntArray(null);
         } else {
@@ -219,6 +321,21 @@
             dest.writeIntArray(ids);
             dest.writeParcelableArray(values, flags);
         }
+        if (mUpdates == null) {
+            dest.writeParcelableArray(null, flags);
+        } else {
+            final int size = mUpdates.size();
+            final InternalValidator[] conditions = new InternalValidator[size];
+            final BatchUpdates[] updates = new BatchUpdates[size];
+
+            for (int i = 0; i < size; i++) {
+                final Pair<InternalValidator, BatchUpdates> pair = mUpdates.get(i);
+                conditions[i] = pair.first;
+                updates[i] = pair.second;
+            }
+            dest.writeParcelableArray(conditions, flags);
+            dest.writeParcelableArray(updates, flags);
+        }
     }
     public static final Parcelable.Creator<CustomDescription> CREATOR =
             new Parcelable.Creator<CustomDescription>() {
@@ -227,7 +344,10 @@
             // Always go through the builder to ensure the data ingested by
             // the system obeys the contract of the builder to avoid attacks
             // using specially crafted parcels.
-            final Builder builder = new Builder(parcel.readParcelable(null));
+            final RemoteViews parentPresentation = parcel.readParcelable(null);
+            if (parentPresentation == null) return null;
+
+            final Builder builder = new Builder(parentPresentation);
             final int[] ids = parcel.createIntArray();
             if (ids != null) {
                 final InternalTransformation[] values =
@@ -237,6 +357,15 @@
                     builder.addChild(ids[i], values[i]);
                 }
             }
+            final InternalValidator[] conditions =
+                    parcel.readParcelableArray(null, InternalValidator.class);
+            if (conditions != null) {
+                final BatchUpdates[] updates = parcel.readParcelableArray(null, BatchUpdates.class);
+                final int size = conditions.length;
+                for (int i = 0; i < size; i++) {
+                    builder.batchUpdate(conditions[i], updates[i]);
+                }
+            }
             return builder.build();
         }
 
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index ef9598a..b2cdef2 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -201,7 +201,8 @@
          * Creates a new builder for a dataset where each field will be visualized independently.
          *
          * <p>When using this constructor, fields must be set through
-         * {@link #setValue(AutofillId, AutofillValue, RemoteViews)}.
+         * {@link #setValue(AutofillId, AutofillValue, RemoteViews)} or
+         * {@link #setValue(AutofillId, AutofillValue, Pattern, RemoteViews)}.
          */
         public Builder() {
         }
@@ -280,19 +281,24 @@
         /**
          * Sets the value of a field.
          *
+         * <b>Note:</b> Prior to Android {@link android.os.Build.VERSION_CODES#P}, this method would
+         * throw an {@link IllegalStateException} if this builder was constructed without a
+         * {@link RemoteViews presentation}. Android {@link android.os.Build.VERSION_CODES#P} and
+         * higher removed this restriction because datasets used as an
+         * {@link android.view.autofill.AutofillManager#EXTRA_AUTHENTICATION_RESULT
+         * authentication result} do not need a presentation. But if you don't set the presentation
+         * in the constructor in a dataset that is meant to be shown to the user, the autofill UI
+         * for this field will not be displayed.
+         *
          * @param id id returned by {@link
          *         android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
          * @param value value to be autofilled. Pass {@code null} if you do not have the value
          *        but the target view is a logical part of the dataset. For example, if
          *        the dataset needs authentication and you have no access to the value.
          * @return this builder.
-         * @throws IllegalStateException if the builder was constructed without a
-         * {@link RemoteViews presentation}.
          */
         public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value) {
             throwIfDestroyed();
-            Preconditions.checkState(mPresentation != null,
-                    "Dataset presentation not set on constructor");
             setLifeTheUniverseAndEverything(id, value, null, null);
             return this;
         }
@@ -334,7 +340,7 @@
          *
          * @return this builder.
          * @throws IllegalStateException if the builder was constructed without a
-         * {@link RemoteViews presentation}.
+         *         {@link RemoteViews presentation}.
          */
         public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value,
                 @NonNull Pattern filter) {
diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java
index 3b719ac..d6c0dbf 100644
--- a/core/java/android/service/autofill/FillEventHistory.java
+++ b/core/java/android/service/autofill/FillEventHistory.java
@@ -17,19 +17,27 @@
 package android.service.autofill;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.IntentSender;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * Describes what happened after the last
@@ -136,9 +144,21 @@
             int numEvents = mEvents.size();
             for (int i = 0; i < numEvents; i++) {
                 Event event = mEvents.get(i);
-                dest.writeInt(event.getType());
-                dest.writeString(event.getDatasetId());
-                dest.writeBundle(event.getClientState());
+                dest.writeInt(event.mEventType);
+                dest.writeString(event.mDatasetId);
+                dest.writeBundle(event.mClientState);
+                dest.writeStringList(event.mSelectedDatasetIds);
+                dest.writeArraySet(event.mIgnoredDatasetIds);
+                dest.writeTypedList(event.mChangedFieldIds);
+                dest.writeStringList(event.mChangedDatasetIds);
+
+                dest.writeTypedList(event.mManuallyFilledFieldIds);
+                if (event.mManuallyFilledFieldIds != null) {
+                    final int size = event.mManuallyFilledFieldIds.size();
+                    for (int j = 0; j < size; j++) {
+                        dest.writeStringList(event.mManuallyFilledDatasetIds.get(j));
+                    }
+                }
             }
         }
     }
@@ -176,12 +196,40 @@
         /** A save UI was shown. */
         public static final int TYPE_SAVE_SHOWN = 3;
 
+        /**
+         * A committed autofill context for which the autofill service provided datasets.
+         *
+         * <p>This event is useful to track:
+         * <ul>
+         *   <li>Which datasets (if any) were selected by the user
+         *       ({@link #getSelectedDatasetIds()}).
+         *   <li>Which datasets (if any) were NOT selected by the user
+         *       ({@link #getIgnoredDatasetIds()}).
+         *   <li>Which fields in the selected datasets were changed by the user after the dataset
+         *       was selected ({@link #getChangedFields()}.
+         * </ul>
+         *
+         * <p><b>Note: </b>This event is only generated when:
+         * <ul>
+         *   <li>The autofill context is committed.
+         *   <li>The service provides at least one dataset in the
+         *       {@link FillResponse fill responses} associated with the context.
+         *   <li>The last {@link FillResponse fill responses} associated with the context has the
+         *       {@link FillResponse#FLAG_TRACK_CONTEXT_COMMITED} flag.
+         * </ul>
+         *
+         * <p>See {@link android.view.autofill.AutofillManager} for more information about autofill
+         * contexts.
+         */
+        public static final int TYPE_CONTEXT_COMMITTED = 4;
+
         /** @hide */
         @IntDef(
                 value = {TYPE_DATASET_SELECTED,
                         TYPE_DATASET_AUTHENTICATION_SELECTED,
                         TYPE_AUTHENTICATION_SELECTED,
-                        TYPE_SAVE_SHOWN})
+                        TYPE_SAVE_SHOWN,
+                        TYPE_CONTEXT_COMMITTED})
         @Retention(RetentionPolicy.SOURCE)
         @interface EventIds{}
 
@@ -189,6 +237,17 @@
         @Nullable private final String mDatasetId;
         @Nullable private final Bundle mClientState;
 
+        // Note: mSelectedDatasetIds is stored as List<> instead of Set because Session already
+        // stores it as List
+        @Nullable private final List<String> mSelectedDatasetIds;
+        @Nullable private final ArraySet<String> mIgnoredDatasetIds;
+
+        @Nullable private final ArrayList<AutofillId> mChangedFieldIds;
+        @Nullable private final ArrayList<String> mChangedDatasetIds;
+
+        @Nullable private final ArrayList<AutofillId> mManuallyFilledFieldIds;
+        @Nullable private final ArrayList<ArrayList<String>> mManuallyFilledDatasetIds;
+
         /**
          * Returns the type of the event.
          *
@@ -220,25 +279,202 @@
         }
 
         /**
+         * Returns which datasets were selected by the user.
+         *
+         * <p><b>Note: </b>Only set on events of type {@link #TYPE_CONTEXT_COMMITTED}.
+         */
+        @NonNull public Set<String> getSelectedDatasetIds() {
+            return mSelectedDatasetIds == null ? Collections.emptySet()
+                    : new ArraySet<>(mSelectedDatasetIds);
+        }
+
+        /**
+         * Returns which datasets were NOT selected by the user.
+         *
+         * <p><b>Note: </b>Only set on events of type {@link #TYPE_CONTEXT_COMMITTED}.
+         */
+        @NonNull public Set<String> getIgnoredDatasetIds() {
+            return mIgnoredDatasetIds == null ? Collections.emptySet() : mIgnoredDatasetIds;
+        }
+
+        /**
+         * Returns which fields in the selected datasets were changed by the user after the dataset
+         * was selected.
+         *
+         * <p>For example, server provides:
+         *
+         * <pre class="prettyprint">
+         *  FillResponse response = new FillResponse.Builder()
+         *      .addDataset(new Dataset.Builder(presentation1)
+         *          .setId("4815")
+         *          .setValue(usernameId, AutofillValue.forText("MrPlow"))
+         *          .build())
+         *      .addDataset(new Dataset.Builder(presentation2)
+         *          .setId("162342")
+         *          .setValue(passwordId, AutofillValue.forText("D'OH"))
+         *          .build())
+         *      .build();
+         * </pre>
+         *
+         * <p>User select both datasets (for username and password) but after the fields are
+         * autofilled, user changes them to:
+         *
+         * <pre class="prettyprint">
+         *   username = "ElBarto";
+         *   password = "AyCaramba";
+         * </pre>
+         *
+         * <p>Then the result is the following map:
+         *
+         * <pre class="prettyprint">
+         *   usernameId => "4815"
+         *   passwordId => "162342"
+         * </pre>
+         *
+         * <p><b>Note: </b>Only set on events of type {@link #TYPE_CONTEXT_COMMITTED}.
+         *
+         * @return map map whose key is the id of the change fields, and value is the id of
+         * dataset that has that field and was selected by the user.
+         */
+        @NonNull public Map<AutofillId, String> getChangedFields() {
+            if (mChangedFieldIds == null || mChangedDatasetIds == null) {
+                return Collections.emptyMap();
+            }
+
+            final int size = mChangedFieldIds.size();
+            final ArrayMap<AutofillId, String> changedFields = new ArrayMap<>(size);
+            for (int i = 0; i < size; i++) {
+                changedFields.put(mChangedFieldIds.get(i), mChangedDatasetIds.get(i));
+            }
+            return changedFields;
+        }
+
+        /**
+         * Returns which fields were available on datasets provided by the service but manually
+         * entered by the user.
+         *
+         * <p>For example, server provides:
+         *
+         * <pre class="prettyprint">
+         *  FillResponse response = new FillResponse.Builder()
+         *      .addDataset(new Dataset.Builder(presentation1)
+         *          .setId("4815")
+         *          .setValue(usernameId, AutofillValue.forText("MrPlow"))
+         *          .setValue(passwordId, AutofillValue.forText("AyCaramba"))
+         *          .build())
+         *      .addDataset(new Dataset.Builder(presentation2)
+         *          .setId("162342")
+         *          .setValue(usernameId, AutofillValue.forText("ElBarto"))
+         *          .setValue(passwordId, AutofillValue.forText("D'OH"))
+         *          .build())
+         *      .addDataset(new Dataset.Builder(presentation3)
+         *          .setId("108")
+         *          .setValue(usernameId, AutofillValue.forText("MrPlow"))
+         *          .setValue(passwordId, AutofillValue.forText("D'OH"))
+         *          .build())
+         *      .build();
+         * </pre>
+         *
+         * <p>User doesn't select a dataset but manually enters:
+         *
+         * <pre class="prettyprint">
+         *   username = "MrPlow";
+         *   password = "D'OH";
+         * </pre>
+         *
+         * <p>Then the result is the following map:
+         *
+         * <pre class="prettyprint">
+         *   usernameId => { "4815", "108"}
+         *   passwordId => { "162342", "108" }
+         * </pre>
+         *
+         * <p><b>Note: </b>Only set on events of type {@link #TYPE_CONTEXT_COMMITTED}.
+         *
+         * @return map map whose key is the id of the manually-entered field, and value is the
+         * ids of the datasets that have that value but were not selected by the user.
+         */
+        @Nullable public Map<AutofillId, Set<String>> getManuallyEnteredField() {
+            if (mManuallyFilledFieldIds == null || mManuallyFilledDatasetIds == null) {
+                return Collections.emptyMap();
+            }
+
+            final int size = mManuallyFilledFieldIds.size();
+            final Map<AutofillId, Set<String>> manuallyFilledFields = new ArrayMap<>(size);
+            for (int i = 0; i < size; i++) {
+                final AutofillId fieldId = mManuallyFilledFieldIds.get(i);
+                final ArrayList<String> datasetIds = mManuallyFilledDatasetIds.get(i);
+                manuallyFilledFields.put(fieldId, new ArraySet<>(datasetIds));
+            }
+            return manuallyFilledFields;
+        }
+
+        /**
          * Creates a new event.
          *
          * @param eventType The type of the event
          * @param datasetId The dataset the event was on, or {@code null} if the event was on the
          *                  whole response.
          * @param clientState The client state associated with the event.
+         * @param selectedDatasetIds The ids of datasets selected by the user.
+         * @param ignoredDatasetIds The ids of datasets NOT select by the user.
+         * @param changedFieldIds The ids of fields changed by the user.
+         * @param changedDatasetIds The ids of the datasets that havd values matching the
+         * respective entry on {@code changedFieldIds}.
+         * @param manuallyFilledFieldIds The ids of fields that were manually entered by the user
+         * and belonged to datasets.
+         * @param manuallyFilledDatasetIds The ids of datasets that had values matching the
+         * respective entry on {@code manuallyFilledFieldIds}.
+         *
+         * @throws IllegalArgumentException If the length of {@code changedFieldIds} and
+         * {@code changedDatasetIds} doesn't match.
+         * @throws IllegalArgumentException If the length of {@code manuallyFilledFieldIds} and
+         * {@code manuallyFilledDatasetIds} doesn't match.
          *
          * @hide
          */
-        public Event(int eventType, @Nullable String datasetId, @Nullable Bundle clientState) {
-            mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_SAVE_SHOWN,
+        public Event(int eventType, @Nullable String datasetId, @Nullable Bundle clientState,
+                @Nullable List<String> selectedDatasetIds,
+                @Nullable ArraySet<String> ignoredDatasetIds,
+                @Nullable ArrayList<AutofillId> changedFieldIds,
+                @Nullable ArrayList<String> changedDatasetIds,
+                @Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
+                @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds) {
+            mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_CONTEXT_COMMITTED,
                     "eventType");
             mDatasetId = datasetId;
             mClientState = clientState;
+            mSelectedDatasetIds = selectedDatasetIds;
+            mIgnoredDatasetIds = ignoredDatasetIds;
+            if (changedFieldIds != null) {
+                Preconditions.checkArgument(!ArrayUtils.isEmpty(changedFieldIds)
+                        && changedDatasetIds != null
+                        && changedFieldIds.size() == changedDatasetIds.size(),
+                        "changed ids must have same length and not be empty");
+            }
+            mChangedFieldIds = changedFieldIds;
+            mChangedDatasetIds = changedDatasetIds;
+            if (manuallyFilledFieldIds != null) {
+                Preconditions.checkArgument(!ArrayUtils.isEmpty(manuallyFilledFieldIds)
+                        && manuallyFilledDatasetIds != null
+                        && manuallyFilledFieldIds.size() == manuallyFilledDatasetIds.size(),
+                        "manually filled ids must have same length and not be empty");
+            }
+            mManuallyFilledFieldIds = manuallyFilledFieldIds;
+            mManuallyFilledDatasetIds = manuallyFilledDatasetIds;
         }
 
         @Override
         public String toString() {
-            return "FillEvent [datasetId=" + mDatasetId + ", type=" + mEventType + "]";
+            return "FillEvent [datasetId=" + mDatasetId
+                    + ", type=" + mEventType
+                    + ", selectedDatasets=" + mSelectedDatasetIds
+                    + ", ignoredDatasetIds=" + mIgnoredDatasetIds
+                    + ", changedFieldIds=" + mChangedFieldIds
+                    + ", changedDatasetsIds=" + mChangedDatasetIds
+                    + ", manuallyFilledFieldIds=" + mManuallyFilledFieldIds
+                    + ", manuallyFilledDatasetIds=" + mManuallyFilledDatasetIds
+                    + "]";
         }
     }
 
@@ -248,12 +484,37 @@
                 public FillEventHistory createFromParcel(Parcel parcel) {
                     FillEventHistory selection = new FillEventHistory(0, 0, parcel.readBundle());
 
-                    int numEvents = parcel.readInt();
+                    final int numEvents = parcel.readInt();
                     for (int i = 0; i < numEvents; i++) {
-                        selection.addEvent(new Event(parcel.readInt(), parcel.readString(),
-                                parcel.readBundle()));
-                    }
+                        final int eventType = parcel.readInt();
+                        final String datasetId = parcel.readString();
+                        final Bundle clientState = parcel.readBundle();
+                        final ArrayList<String> selectedDatasetIds = parcel.createStringArrayList();
+                        @SuppressWarnings("unchecked")
+                        final ArraySet<String> ignoredDatasets =
+                                (ArraySet<String>) parcel.readArraySet(null);
+                        final ArrayList<AutofillId> changedFieldIds =
+                                parcel.createTypedArrayList(AutofillId.CREATOR);
+                        final ArrayList<String> changedDatasetIds = parcel.createStringArrayList();
 
+                        final ArrayList<AutofillId> manuallyFilledFieldIds =
+                                parcel.createTypedArrayList(AutofillId.CREATOR);
+                        final ArrayList<ArrayList<String>> manuallyFilledDatasetIds;
+                        if (manuallyFilledFieldIds != null) {
+                            final int size = manuallyFilledFieldIds.size();
+                            manuallyFilledDatasetIds = new ArrayList<>(size);
+                            for (int j = 0; j < size; j++) {
+                                manuallyFilledDatasetIds.add(parcel.createStringArrayList());
+                            }
+                        } else {
+                            manuallyFilledDatasetIds = null;
+                        }
+
+                        selection.addEvent(new Event(eventType, datasetId, clientState,
+                                selectedDatasetIds, ignoredDatasets,
+                                changedFieldIds, changedDatasetIds,
+                                manuallyFilledFieldIds, manuallyFilledDatasetIds));
+                    }
                     return selection;
                 }
 
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index 6d8a959..d91cebb 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -19,6 +19,7 @@
 import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
 import static android.view.autofill.Helper.sDebug;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Activity;
@@ -30,6 +31,8 @@
 import android.view.autofill.AutofillId;
 import android.widget.RemoteViews;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -42,6 +45,19 @@
  */
 public final class FillResponse implements Parcelable {
 
+    /**
+     * Must be set in the last response to generate
+     * {@link FillEventHistory.Event#TYPE_CONTEXT_COMMITTED} events.
+     */
+    public static final int FLAG_TRACK_CONTEXT_COMMITED = 0x1;
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            FLAG_TRACK_CONTEXT_COMMITED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface FillResponseFlags {}
+
     private final @Nullable ParceledListSlice<Dataset> mDatasets;
     private final @Nullable SaveInfo mSaveInfo;
     private final @Nullable Bundle mClientState;
@@ -49,6 +65,7 @@
     private final @Nullable IntentSender mAuthentication;
     private final @Nullable AutofillId[] mAuthenticationIds;
     private final @Nullable AutofillId[] mIgnoredIds;
+    private final int mFlags;
     private int mRequestId;
 
     private FillResponse(@NonNull Builder builder) {
@@ -59,6 +76,7 @@
         mAuthentication = builder.mAuthentication;
         mAuthenticationIds = builder.mAuthenticationIds;
         mIgnoredIds = builder.mIgnoredIds;
+        mFlags = builder.mFlags;
         mRequestId = INVALID_REQUEST_ID;
     }
 
@@ -97,6 +115,11 @@
         return mIgnoredIds;
     }
 
+    /** @hide */
+    public int getFlags() {
+        return mFlags;
+    }
+
     /**
      * Associates a {@link FillResponse} to a request.
      *
@@ -127,6 +150,7 @@
         private IntentSender mAuthentication;
         private AutofillId[] mAuthenticationIds;
         private AutofillId[] mIgnoredIds;
+        private int mFlags;
         private boolean mDestroyed;
 
         /**
@@ -269,6 +293,19 @@
         }
 
         /**
+         * Sets flags changing the response behavior.
+         *
+         * @param flags {@link #FLAG_TRACK_CONTEXT_COMMITED}, or {@code 0}.
+         *
+         * @return This builder.
+         */
+        public Builder setFlags(@FillResponseFlags int flags) {
+            throwIfDestroyed();
+            mFlags = flags;
+            return this;
+        }
+
+        /**
          * Builds a new {@link FillResponse} instance.
          *
          * <p>You must provide at least one dataset or some savable ids or an authentication with a
@@ -311,6 +348,7 @@
                 .append(", hasAuthentication=").append(mAuthentication != null)
                 .append(", authenticationIds=").append(Arrays.toString(mAuthenticationIds))
                 .append(", ignoredIds=").append(Arrays.toString(mIgnoredIds))
+                .append(", flags=").append(mFlags)
                 .append("]")
                 .toString();
     }
@@ -333,6 +371,7 @@
         parcel.writeParcelable(mAuthentication, flags);
         parcel.writeParcelable(mPresentation, flags);
         parcel.writeParcelableArray(mIgnoredIds, flags);
+        parcel.writeInt(mFlags);
         parcel.writeInt(mRequestId);
     }
 
@@ -363,8 +402,9 @@
             }
 
             builder.setIgnoredIds(parcel.readParcelableArray(null, AutofillId.class));
-            final FillResponse response = builder.build();
+            builder.setFlags(parcel.readInt());
 
+            final FillResponse response = builder.build();
             response.setRequestId(parcel.readInt());
 
             return response;
diff --git a/core/java/android/service/autofill/InternalTransformation.java b/core/java/android/service/autofill/InternalTransformation.java
index 974397b..c9864a0 100644
--- a/core/java/android/service/autofill/InternalTransformation.java
+++ b/core/java/android/service/autofill/InternalTransformation.java
@@ -15,17 +15,27 @@
  */
 package android.service.autofill;
 
+import static android.view.autofill.Helper.sDebug;
+
 import android.annotation.NonNull;
+import android.annotation.TestApi;
 import android.os.Parcelable;
+import android.util.Log;
+import android.util.Pair;
 import android.widget.RemoteViews;
 
+import java.util.ArrayList;
+
 /**
  * Superclass of all transformation the system understands. As this is not public all
  * subclasses have to implement {@link Transformation} again.
  *
  * @hide
  */
-abstract class InternalTransformation implements Transformation, Parcelable {
+@TestApi
+public abstract class InternalTransformation implements Transformation, Parcelable {
+
+    private static final String TAG = "InternalTransformation";
 
     /**
      * Applies this transformation to a child view of a {@link android.widget.RemoteViews
@@ -39,4 +49,37 @@
      */
     abstract void apply(@NonNull ValueFinder finder, @NonNull RemoteViews template,
             int childViewId) throws Exception;
+
+    /**
+     * Applies multiple transformations to the children views of a
+     * {@link android.widget.RemoteViews presentation template}.
+     *
+     * @param finder object used to find the value of a field in the screen.
+     * @param template the {@link RemoteViews presentation template}.
+     * @param transformations map of resource id of the child view inside the template to
+     * transformation.
+     *
+     * @hide
+     */
+    public static boolean batchApply(@NonNull ValueFinder finder, @NonNull RemoteViews template,
+            @NonNull ArrayList<Pair<Integer, InternalTransformation>> transformations) {
+        final int size = transformations.size();
+        if (sDebug) Log.d(TAG, "getPresentation(): applying " + size + " transformations");
+        for (int i = 0; i < size; i++) {
+            final Pair<Integer, InternalTransformation> pair = transformations.get(i);
+            final int id = pair.first;
+            final InternalTransformation transformation = pair.second;
+            if (sDebug) Log.d(TAG, "#" + i + ": " + transformation);
+
+            try {
+                transformation.apply(finder, template, id);
+            } catch (Exception e) {
+                // Do not log full exception to avoid PII leaking
+                Log.e(TAG, "Could not apply transformation " + transformation + ": "
+                        + e.getClass());
+                return false;
+            }
+        }
+        return true;
+    }
 }
diff --git a/core/java/android/service/autofill/InternalValidator.java b/core/java/android/service/autofill/InternalValidator.java
index e11cf6a..e08bb6c 100644
--- a/core/java/android/service/autofill/InternalValidator.java
+++ b/core/java/android/service/autofill/InternalValidator.java
@@ -16,6 +16,7 @@
 package android.service.autofill;
 
 import android.annotation.NonNull;
+import android.annotation.TestApi;
 import android.os.Parcelable;
 
 /**
@@ -24,6 +25,7 @@
  *
  * @hide
  */
+@TestApi
 public abstract class InternalValidator implements Validator, Parcelable {
 
     /**
@@ -34,5 +36,6 @@
      *
      * @hide
      */
+    @TestApi
     public abstract boolean isValid(@NonNull ValueFinder finder);
 }
diff --git a/core/java/android/service/autofill/LuhnChecksumValidator.java b/core/java/android/service/autofill/LuhnChecksumValidator.java
index 0b5930d..c56ae84 100644
--- a/core/java/android/service/autofill/LuhnChecksumValidator.java
+++ b/core/java/android/service/autofill/LuhnChecksumValidator.java
@@ -27,6 +27,8 @@
 
 import com.android.internal.util.Preconditions;
 
+import java.util.Arrays;
+
 /**
  * Validator that returns {@code true} if the number created by concatenating all given fields
  * pass a Luhn algorithm checksum. All non-digits are ignored.
@@ -86,17 +88,27 @@
     public boolean isValid(@NonNull ValueFinder finder) {
         if (mIds == null || mIds.length == 0) return false;
 
-        final StringBuilder number = new StringBuilder();
+        final StringBuilder builder = new StringBuilder();
         for (AutofillId id : mIds) {
             final String partialNumber = finder.findByAutofillId(id);
             if (partialNumber == null) {
                 if (sDebug) Log.d(TAG, "No partial number for id " + id);
                 return false;
             }
-            number.append(partialNumber);
+            builder.append(partialNumber);
         }
 
-        return isLuhnChecksumValid(number.toString());
+        final String number = builder.toString();
+        boolean valid = isLuhnChecksumValid(number);
+        if (sDebug) Log.d(TAG, "isValid(" + number.length() + " chars): " + valid);
+        return valid;
+    }
+
+    @Override
+    public String toString() {
+        if (!sDebug) return super.toString();
+
+        return "LuhnChecksumValidator: [ids=" + Arrays.toString(mIds) + "]";
     }
 
     /////////////////////////////////////
diff --git a/core/java/android/service/autofill/OptionalValidators.java b/core/java/android/service/autofill/OptionalValidators.java
index f7edd6e..7aec59f 100644
--- a/core/java/android/service/autofill/OptionalValidators.java
+++ b/core/java/android/service/autofill/OptionalValidators.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.Log;
 
 import com.android.internal.util.Preconditions;
 
@@ -34,6 +35,8 @@
  */
 final class OptionalValidators extends InternalValidator {
 
+    private static final String TAG = "OptionalValidators";
+
     @NonNull private final InternalValidator[] mValidators;
 
     OptionalValidators(@NonNull InternalValidator[] validators) {
@@ -44,6 +47,7 @@
     public boolean isValid(@NonNull ValueFinder finder) {
         for (InternalValidator validator : mValidators) {
             final boolean valid = validator.isValid(finder);
+            if (sDebug) Log.d(TAG, "isValid(" + validator + "): " + valid);
             if (valid) return true;
         }
 
diff --git a/core/java/android/service/autofill/RequiredValidators.java b/core/java/android/service/autofill/RequiredValidators.java
index ac85c28..9e1db2b 100644
--- a/core/java/android/service/autofill/RequiredValidators.java
+++ b/core/java/android/service/autofill/RequiredValidators.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.Log;
 
 import com.android.internal.util.Preconditions;
 
@@ -34,6 +35,8 @@
  */
 final class RequiredValidators extends InternalValidator {
 
+    private static final String TAG = "RequiredValidators";
+
     @NonNull private final InternalValidator[] mValidators;
 
     RequiredValidators(@NonNull InternalValidator[] validators) {
@@ -44,6 +47,7 @@
     public boolean isValid(@NonNull ValueFinder finder) {
         for (InternalValidator validator : mValidators) {
             final boolean valid = validator.isValid(finder);
+            if (sDebug) Log.d(TAG, "isValid(" + validator + "): " + valid);
             if (!valid) return false;
         }
         return true;
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 1b9240c..fde2416 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -68,7 +68,7 @@
  *       .build();
  * </pre>
  *
- * <p>The save type flags are used to display the appropriate strings in the save UI affordance.
+ * <p>The save type flags are used to display the appropriate strings in the autofill save UI.
  * You can pass multiple values, but try to keep it short if possible. In the above example, just
  * {@code SaveInfo.SAVE_DATA_TYPE_PASSWORD} would be enough.
  *
@@ -103,13 +103,17 @@
  *       .build();
  * </pre>
  *
+ * <a name="TriggeringSaveRequest"></a>
+ * <h3>Triggering a save request</h3>
+ *
  * <p>The {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)} can be triggered after
  * any of the following events:
  * <ul>
  *   <li>The {@link Activity} finishes.
- *   <li>The app explicitly called {@link AutofillManager#commit()}.
- *   <li>All required views became invisible (if the {@link SaveInfo} was created with the
+ *   <li>The app explicitly calls {@link AutofillManager#commit()}.
+ *   <li>All required views become invisible (if the {@link SaveInfo} was created with the
  *       {@link #FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE} flag).
+ *   <li>The user clicks a specific view (defined by {@link Builder#setTriggerId(AutofillId)}.
  * </ul>
  *
  * <p>But it is only triggered when all conditions below are met:
@@ -123,10 +127,13 @@
  *   <li>There is no {@link Dataset} in the last {@link FillResponse} that completely matches the
  *       screen state (i.e., all required and optional fields in the dataset have the same value as
  *       the fields in the screen).
- *   <li>The user explicitly tapped the UI affordance asking to save data for autofill.
+ *   <li>The user explicitly tapped the autofill save UI asking to save data for autofill.
  * </ul>
  *
- * <p>The service can also customize some aspects of the save UI affordance:
+ * <a name="CustomizingSaveUI"></a>
+ * <h3>Customizing the autofill save UI</h3>
+ *
+ * <p>The service can also customize some aspects of the autofill save UI:
  * <ul>
  *   <li>Add a simple subtitle by calling {@link Builder#setDescription(CharSequence)}.
  *   <li>Add a customized subtitle by calling
@@ -212,16 +219,25 @@
     @interface SaveDataType{}
 
     /**
-     * Usually {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)}
-     * is called once the {@link Activity} finishes. If this flag is set it is called once all
-     * saved views become invisible.
+     * Usually, a save request is only automatically <a href="#TriggeringSaveRequest">triggered</a>
+     * once the {@link Activity} finishes. If this flag is set, it is triggered once all saved views
+     * become invisible.
      */
     public static final int FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE = 0x1;
 
+    /**
+     * By default, a save request is automatically <a href="#TriggeringSaveRequest">triggered</a>
+     * once the {@link Activity} finishes. If this flag is set, finishing the activity doesn't
+     * trigger a save request.
+     *
+     * <p>This flag is typically used in conjunction with {@link Builder#setTriggerId(AutofillId)}.
+     */
+    public static final int FLAG_DONT_SAVE_ON_FINISH = 0x2;
+
     /** @hide */
     @IntDef(
             flag = true,
-            value = {FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE})
+            value = {FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE, FLAG_DONT_SAVE_ON_FINISH})
     @Retention(RetentionPolicy.SOURCE)
     @interface SaveInfoFlags{}
 
@@ -236,6 +252,7 @@
     private final InternalValidator mValidator;
     private final InternalSanitizer[] mSanitizerKeys;
     private final AutofillId[][] mSanitizerValues;
+    private final AutofillId mTriggerId;
 
     private SaveInfo(Builder builder) {
         mType = builder.mType;
@@ -259,6 +276,7 @@
                 mSanitizerValues[i] = builder.mSanitizers.valueAt(i);
             }
         }
+        mTriggerId = builder.mTriggerId;
     }
 
     /** @hide */
@@ -320,6 +338,12 @@
         return mSanitizerValues;
     }
 
+    /** @hide */
+    @Nullable
+    public AutofillId getTriggerId() {
+        return mTriggerId;
+    }
+
     /**
      * A builder for {@link SaveInfo} objects.
      */
@@ -338,6 +362,7 @@
         private ArrayMap<InternalSanitizer, AutofillId[]> mSanitizers;
         // Set used to validate against duplicate ids.
         private ArraySet<AutofillId> mSanitizerIds;
+        private AutofillId mTriggerId;
 
         /**
          * Creates a new builder.
@@ -394,13 +419,15 @@
         /**
          * Sets flags changing the save behavior.
          *
-         * @param flags {@link #FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE} or {@code 0}.
+         * @param flags {@link #FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE},
+         * {@link #FLAG_DONT_SAVE_ON_FINISH}, or {@code 0}.
          * @return This builder.
          */
         public @NonNull Builder setFlags(@SaveInfoFlags int flags) {
             throwIfDestroyed();
 
-            mFlags = Preconditions.checkFlagsArgument(flags, FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE);
+            mFlags = Preconditions.checkFlagsArgument(flags,
+                    FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE | FLAG_DONT_SAVE_ON_FINISH);
             return this;
         }
 
@@ -493,8 +520,8 @@
         }
 
         /**
-         * Sets an object used to validate the user input - if the input is not valid, the Save UI
-         * affordance is not shown.
+         * Sets an object used to validate the user input - if the input is not valid, the
+         * autofill save UI is not shown.
          *
          * <p>Typically used to validate credit card numbers. Examples:
          *
@@ -520,7 +547,7 @@
          *   );
          * </pre>
          *
-         * <p><b>NOTE: </b>the example above is just for illustrative purposes; the same validator
+         * <p><b>Note:</b> the example above is just for illustrative purposes; the same validator
          * could be created using a single regex for the {@code OR} part:
          *
          * <pre class="prettyprint">
@@ -615,6 +642,27 @@
             return this;
         }
 
+       /**
+         * Explicitly defines the view that should commit the autofill context when clicked.
+         *
+         * <p>Usually, the save request is only automatically
+         * <a href="#TriggeringSaveRequest">triggered</a> after the activity is
+         * finished or all relevant views become invisible, but there are scenarios where the
+         * autofill context is automatically commited too late
+         * &mdash;for example, when the activity manually clears the autofillable views when a
+         * button is tapped. This method can be used to trigger the autofill save UI earlier in
+         * these scenarios.
+         *
+         * <p><b>Note:</b> This method should only be used in scenarios where the automatic workflow
+         * is not enough, otherwise it could trigger the autofill save UI when it should not&mdash;
+         * for example, when the user entered invalid credentials for the autofillable views.
+         */
+        public @NonNull Builder setTriggerId(@NonNull AutofillId id) {
+            throwIfDestroyed();
+            mTriggerId = Preconditions.checkNotNull(id);
+            return this;
+        }
+
         /**
          * Builds a new {@link SaveInfo} instance.
          *
@@ -652,13 +700,14 @@
                 .append(", description=").append(mDescription)
                 .append(DebugUtils.flagsToString(SaveInfo.class, "NEGATIVE_BUTTON_STYLE_",
                         mNegativeButtonStyle))
-                .append(", mFlags=").append(mFlags)
-                .append(", mCustomDescription=").append(mCustomDescription)
-                .append(", validation=").append(mValidator)
+                .append(", flags=").append(mFlags)
+                .append(", customDescription=").append(mCustomDescription)
+                .append(", validator=").append(mValidator)
                 .append(", sanitizerKeys=")
                     .append(mSanitizerKeys == null ? "N/A:" : mSanitizerKeys.length)
                 .append(", sanitizerValues=")
                     .append(mSanitizerValues == null ? "N/A:" : mSanitizerValues.length)
+                .append(", triggerId=").append(mTriggerId)
                 .append("]").toString();
     }
 
@@ -687,6 +736,7 @@
                 parcel.writeParcelableArray(mSanitizerValues[i], flags);
             }
         }
+        parcel.writeParcelable(mTriggerId, flags);
         parcel.writeInt(mFlags);
     }
 
@@ -727,6 +777,10 @@
                     builder.addSanitizer(sanitizers[i], autofillIds);
                 }
             }
+            final AutofillId triggerId = parcel.readParcelable(null);
+            if (triggerId != null) {
+                builder.setTriggerId(triggerId);
+            }
             builder.setFlags(parcel.readInt());
             return builder.build();
         }
diff --git a/core/java/android/service/autofill/SaveRequest.java b/core/java/android/service/autofill/SaveRequest.java
index 65fdb5c..f53967b 100644
--- a/core/java/android/service/autofill/SaveRequest.java
+++ b/core/java/android/service/autofill/SaveRequest.java
@@ -19,7 +19,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Bundle;
-import android.os.CancellationSignal;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -60,9 +59,14 @@
     }
 
     /**
-     * Gets the extra client state returned from the last {@link
-     * AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback)}
-     * fill request}.
+     * Gets the latest client state extra returned from the service.
+     *
+     * <p><b>Note:</b> Prior to Android {@link android.os.Build.VERSION_CODES#P}, only client state
+     * bundles set by {@link FillResponse.Builder#setClientState(Bundle)} where considered. On
+     * Android {@link android.os.Build.VERSION_CODES#P} and higher, bundles set in the result of
+     * an authenticated request through the
+     * {@link android.view.autofill.AutofillManager#EXTRA_CLIENT_STATE} extra are
+     * also considered (and take precedence when set).
      *
      * @return The client state.
      */
diff --git a/core/java/android/service/autofill/Validator.java b/core/java/android/service/autofill/Validator.java
index 854aa1e..a4036f2 100644
--- a/core/java/android/service/autofill/Validator.java
+++ b/core/java/android/service/autofill/Validator.java
@@ -16,9 +16,9 @@
 package android.service.autofill;
 
 /**
- * Helper class used to define whether the contents of a screen are valid.
+ * Class used to define whether a condition is satisfied.
  *
- * <p>Typically used to avoid displaying the Save UI affordance when the user input is invalid.
+ * <p>Typically used to avoid displaying the save UI when the user input is invalid.
  */
 public interface Validator {
 }
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 7bec898..735b822 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -76,10 +76,13 @@
     private static final int DAY_MINUTES = 24 * 60;
     private static final int ZERO_VALUE_MS = 10 * SECONDS_MS;
 
-    private static final boolean DEFAULT_ALLOW_CALLS = true;
+    // Default allow categories set in readXml() from default_zen_mode_config.xml, fallback values:
+    private static final boolean DEFAULT_ALLOW_ALARMS = true;
+    private static final boolean DEFAULT_ALLOW_MEDIA_SYSTEM_OTHER = true;
+    private static final boolean DEFAULT_ALLOW_CALLS = false;
     private static final boolean DEFAULT_ALLOW_MESSAGES = false;
-    private static final boolean DEFAULT_ALLOW_REMINDERS = true;
-    private static final boolean DEFAULT_ALLOW_EVENTS = true;
+    private static final boolean DEFAULT_ALLOW_REMINDERS = false;
+    private static final boolean DEFAULT_ALLOW_EVENTS = false;
     private static final boolean DEFAULT_ALLOW_REPEAT_CALLERS = false;
     private static final boolean DEFAULT_ALLOW_SCREEN_OFF = true;
     private static final boolean DEFAULT_ALLOW_SCREEN_ON = true;
@@ -89,6 +92,8 @@
     private static final String ZEN_ATT_VERSION = "version";
     private static final String ZEN_ATT_USER = "user";
     private static final String ALLOW_TAG = "allow";
+    private static final String ALLOW_ATT_ALARMS = "alarms";
+    private static final String ALLOW_ATT_MEDIA_SYSTEM_OTHER = "media_system_other";
     private static final String ALLOW_ATT_CALLS = "calls";
     private static final String ALLOW_ATT_REPEAT_CALLERS = "repeatCallers";
     private static final String ALLOW_ATT_MESSAGES = "messages";
@@ -100,8 +105,6 @@
     private static final String ALLOW_ATT_SCREEN_OFF = "visualScreenOff";
     private static final String ALLOW_ATT_SCREEN_ON = "visualScreenOn";
 
-    private static final String CONDITION_TAG = "condition";
-    private static final String CONDITION_ATT_COMPONENT = "component";
     private static final String CONDITION_ATT_ID = "id";
     private static final String CONDITION_ATT_SUMMARY = "summary";
     private static final String CONDITION_ATT_LINE1 = "line1";
@@ -123,6 +126,8 @@
     private static final String RULE_ATT_CREATION_TIME = "creationTime";
     private static final String RULE_ATT_ENABLER = "enabler";
 
+    public boolean allowAlarms = DEFAULT_ALLOW_ALARMS;
+    public boolean allowMediaSystemOther = DEFAULT_ALLOW_MEDIA_SYSTEM_OTHER;
     public boolean allowCalls = DEFAULT_ALLOW_CALLS;
     public boolean allowRepeatCallers = DEFAULT_ALLOW_REPEAT_CALLERS;
     public boolean allowMessages = DEFAULT_ALLOW_MESSAGES;
@@ -161,6 +166,8 @@
         }
         allowWhenScreenOff = source.readInt() == 1;
         allowWhenScreenOn = source.readInt() == 1;
+        allowAlarms = source.readInt() == 1;
+        allowMediaSystemOther = source.readInt() == 1;
     }
 
     @Override
@@ -190,19 +197,23 @@
         }
         dest.writeInt(allowWhenScreenOff ? 1 : 0);
         dest.writeInt(allowWhenScreenOn ? 1 : 0);
+        dest.writeInt(allowAlarms ? 1 : 0);
+        dest.writeInt(allowMediaSystemOther ? 1 : 0);
     }
 
     @Override
     public String toString() {
         return new StringBuilder(ZenModeConfig.class.getSimpleName()).append('[')
                 .append("user=").append(user)
+                .append(",allowAlarms=").append(allowAlarms)
+                .append(",allowMediaSystemOther=").append(allowMediaSystemOther)
+                .append(",allowReminders=").append(allowReminders)
+                .append(",allowEvents=").append(allowEvents)
                 .append(",allowCalls=").append(allowCalls)
                 .append(",allowRepeatCallers=").append(allowRepeatCallers)
                 .append(",allowMessages=").append(allowMessages)
                 .append(",allowCallsFrom=").append(sourceToString(allowCallsFrom))
                 .append(",allowMessagesFrom=").append(sourceToString(allowMessagesFrom))
-                .append(",allowReminders=").append(allowReminders)
-                .append(",allowEvents=").append(allowEvents)
                 .append(",allowWhenScreenOff=").append(allowWhenScreenOff)
                 .append(",allowWhenScreenOn=").append(allowWhenScreenOn)
                 .append(",automaticRules=").append(automaticRules)
@@ -218,9 +229,21 @@
         if (user != to.user) {
             d.addLine("user", user, to.user);
         }
+        if (allowAlarms != to.allowAlarms) {
+            d.addLine("allowAlarms", allowAlarms, to.allowAlarms);
+        }
+        if (allowMediaSystemOther != to.allowMediaSystemOther) {
+            d.addLine("allowMediaSystemOther", allowMediaSystemOther, to.allowMediaSystemOther);
+        }
         if (allowCalls != to.allowCalls) {
             d.addLine("allowCalls", allowCalls, to.allowCalls);
         }
+        if (allowReminders != to.allowReminders) {
+            d.addLine("allowReminders", allowReminders, to.allowReminders);
+        }
+        if (allowEvents != to.allowEvents) {
+            d.addLine("allowEvents", allowEvents, to.allowEvents);
+        }
         if (allowRepeatCallers != to.allowRepeatCallers) {
             d.addLine("allowRepeatCallers", allowRepeatCallers, to.allowRepeatCallers);
         }
@@ -233,12 +256,6 @@
         if (allowMessagesFrom != to.allowMessagesFrom) {
             d.addLine("allowMessagesFrom", allowMessagesFrom, to.allowMessagesFrom);
         }
-        if (allowReminders != to.allowReminders) {
-            d.addLine("allowReminders", allowReminders, to.allowReminders);
-        }
-        if (allowEvents != to.allowEvents) {
-            d.addLine("allowEvents", allowEvents, to.allowEvents);
-        }
         if (allowWhenScreenOff != to.allowWhenScreenOff) {
             d.addLine("allowWhenScreenOff", allowWhenScreenOff, to.allowWhenScreenOff);
         }
@@ -335,7 +352,9 @@
         if (!(o instanceof ZenModeConfig)) return false;
         if (o == this) return true;
         final ZenModeConfig other = (ZenModeConfig) o;
-        return other.allowCalls == allowCalls
+        return other.allowAlarms == allowAlarms
+                && other.allowMediaSystemOther == allowMediaSystemOther
+                && other.allowCalls == allowCalls
                 && other.allowRepeatCallers == allowRepeatCallers
                 && other.allowMessages == allowMessages
                 && other.allowCallsFrom == allowCallsFrom
@@ -351,10 +370,10 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(allowCalls, allowRepeatCallers, allowMessages, allowCallsFrom,
-                allowMessagesFrom, allowReminders, allowEvents, allowWhenScreenOff,
-                allowWhenScreenOn,
-                user, automaticRules, manualRule);
+        return Objects.hash(allowAlarms, allowMediaSystemOther, allowCalls,
+                allowRepeatCallers, allowMessages,
+                allowCallsFrom, allowMessagesFrom, allowReminders, allowEvents,
+                allowWhenScreenOff, allowWhenScreenOn, user, automaticRules, manualRule);
     }
 
     private static String toDayList(int[] days) {
@@ -413,10 +432,12 @@
             }
             if (type == XmlPullParser.START_TAG) {
                 if (ALLOW_TAG.equals(tag)) {
-                    rt.allowCalls = safeBoolean(parser, ALLOW_ATT_CALLS, false);
+                    rt.allowCalls = safeBoolean(parser, ALLOW_ATT_CALLS,
+                            DEFAULT_ALLOW_CALLS);
                     rt.allowRepeatCallers = safeBoolean(parser, ALLOW_ATT_REPEAT_CALLERS,
                             DEFAULT_ALLOW_REPEAT_CALLERS);
-                    rt.allowMessages = safeBoolean(parser, ALLOW_ATT_MESSAGES, false);
+                    rt.allowMessages = safeBoolean(parser, ALLOW_ATT_MESSAGES,
+                            DEFAULT_ALLOW_MESSAGES);
                     rt.allowReminders = safeBoolean(parser, ALLOW_ATT_REMINDERS,
                             DEFAULT_ALLOW_REMINDERS);
                     rt.allowEvents = safeBoolean(parser, ALLOW_ATT_EVENTS, DEFAULT_ALLOW_EVENTS);
@@ -438,6 +459,9 @@
                             safeBoolean(parser, ALLOW_ATT_SCREEN_OFF, DEFAULT_ALLOW_SCREEN_OFF);
                     rt.allowWhenScreenOn =
                             safeBoolean(parser, ALLOW_ATT_SCREEN_ON, DEFAULT_ALLOW_SCREEN_ON);
+                    rt.allowAlarms = safeBoolean(parser, ALLOW_ATT_ALARMS, DEFAULT_ALLOW_ALARMS);
+                    rt.allowMediaSystemOther = safeBoolean(parser, ALLOW_ATT_MEDIA_SYSTEM_OTHER,
+                            DEFAULT_ALLOW_MEDIA_SYSTEM_OTHER);
                 } else if (MANUAL_TAG.equals(tag)) {
                     rt.manualRule = readRuleXml(parser);
                 } else if (AUTOMATIC_TAG.equals(tag)) {
@@ -468,6 +492,8 @@
         out.attribute(null, ALLOW_ATT_MESSAGES_FROM, Integer.toString(allowMessagesFrom));
         out.attribute(null, ALLOW_ATT_SCREEN_OFF, Boolean.toString(allowWhenScreenOff));
         out.attribute(null, ALLOW_ATT_SCREEN_ON, Boolean.toString(allowWhenScreenOn));
+        out.attribute(null, ALLOW_ATT_ALARMS, Boolean.toString(allowAlarms));
+        out.attribute(null, ALLOW_ATT_MEDIA_SYSTEM_OTHER, Boolean.toString(allowMediaSystemOther));
         out.endTag(null, ALLOW_TAG);
 
         if (manualRule != null) {
@@ -654,6 +680,12 @@
         if (!allowWhenScreenOn) {
             suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_SCREEN_ON;
         }
+        if (allowAlarms) {
+            priorityCategories |= Policy.PRIORITY_CATEGORY_ALARMS;
+        }
+        if (allowMediaSystemOther) {
+            priorityCategories |= Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER;
+        }
         priorityCallSenders = sourceToPrioritySenders(allowCallsFrom, priorityCallSenders);
         priorityMessageSenders = sourceToPrioritySenders(allowMessagesFrom, priorityMessageSenders);
         return new Policy(priorityCategories, priorityCallSenders, priorityMessageSenders,
@@ -680,10 +712,13 @@
 
     public void applyNotificationPolicy(Policy policy) {
         if (policy == null) return;
-        allowCalls = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_CALLS) != 0;
-        allowMessages = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_MESSAGES) != 0;
+        allowAlarms = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_ALARMS) != 0;
+        allowMediaSystemOther = (policy.priorityCategories
+                & Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER) != 0;
         allowEvents = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_EVENTS) != 0;
         allowReminders = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_REMINDERS) != 0;
+        allowCalls = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_CALLS) != 0;
+        allowMessages = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_MESSAGES) != 0;
         allowRepeatCallers = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_REPEAT_CALLERS)
                 != 0;
         allowCallsFrom = prioritySendersToSource(policy.priorityCallSenders, allowCallsFrom);
diff --git a/core/java/android/service/settings/suggestions/ISuggestionService.aidl b/core/java/android/service/settings/suggestions/ISuggestionService.aidl
index 423c507..8dfa9c3 100644
--- a/core/java/android/service/settings/suggestions/ISuggestionService.aidl
+++ b/core/java/android/service/settings/suggestions/ISuggestionService.aidl
@@ -17,4 +17,10 @@
      * calls.
      */
     void dismissSuggestion(in Suggestion suggestion) = 2;
+
+    /**
+     * This is the opposite signal to {@link #dismissSuggestion}, indicating a suggestion has been
+     * launched.
+     */
+    void launchSuggestion(in Suggestion suggestion) = 3;
 }
\ No newline at end of file
diff --git a/core/java/android/service/settings/suggestions/SuggestionService.java b/core/java/android/service/settings/suggestions/SuggestionService.java
index 2a4c84c..ce9501d 100644
--- a/core/java/android/service/settings/suggestions/SuggestionService.java
+++ b/core/java/android/service/settings/suggestions/SuggestionService.java
@@ -48,12 +48,20 @@
             }
 
             @Override
-            public  void dismissSuggestion(Suggestion suggestion) {
+            public void dismissSuggestion(Suggestion suggestion) {
                 if (DEBUG) {
                     Log.d(TAG, "dismissSuggestion() " + getPackageName());
                 }
                 onSuggestionDismissed(suggestion);
             }
+
+            @Override
+            public void launchSuggestion(Suggestion suggestion) {
+                if (DEBUG) {
+                    Log.d(TAG, "launchSuggestion() " + getPackageName());
+                }
+                onSuggestionLaunched(suggestion);
+            }
         };
     }
 
@@ -65,7 +73,12 @@
     /**
      * Dismiss a suggestion. The suggestion will not be included in future
      * {@link #onGetSuggestions()} calls.
-     * @param suggestion
      */
     public abstract void onSuggestionDismissed(Suggestion suggestion);
+
+    /**
+     * This is the opposite signal to {@link #onSuggestionDismissed}, indicating a suggestion has
+     * been launched.
+     */
+    public abstract void onSuggestionLaunched(Suggestion suggestion);
 }
diff --git a/core/java/android/slice/Slice.java b/core/java/android/slice/Slice.java
deleted file mode 100644
index 5768654..0000000
--- a/core/java/android/slice/Slice.java
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.slice;
-
-import static android.slice.SliceItem.TYPE_ACTION;
-import static android.slice.SliceItem.TYPE_COLOR;
-import static android.slice.SliceItem.TYPE_IMAGE;
-import static android.slice.SliceItem.TYPE_REMOTE_INPUT;
-import static android.slice.SliceItem.TYPE_REMOTE_VIEW;
-import static android.slice.SliceItem.TYPE_SLICE;
-import static android.slice.SliceItem.TYPE_TEXT;
-import static android.slice.SliceItem.TYPE_TIMESTAMP;
-
-import android.annotation.NonNull;
-import android.annotation.StringDef;
-import android.app.PendingIntent;
-import android.app.RemoteInput;
-import android.graphics.drawable.Icon;
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.widget.RemoteViews;
-
-import com.android.internal.util.ArrayUtils;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-
-/**
- * A slice is a piece of app content and actions that can be surfaced outside of the app.
- *
- * <p>They are constructed using {@link Builder} in a tree structure
- * that provides the OS some information about how the content should be displayed.
- * @hide
- */
-public final class Slice implements Parcelable {
-
-    /**
-     * @hide
-     */
-    @StringDef({HINT_TITLE, HINT_LIST, HINT_LIST_ITEM, HINT_LARGE, HINT_ACTIONS, HINT_SELECTED,
-            HINT_SOURCE, HINT_MESSAGE, HINT_HORIZONTAL, HINT_NO_TINT})
-    public @interface SliceHint{ }
-
-    /**
-     * Hint that this content is a title of other content in the slice.
-     */
-    public static final String HINT_TITLE       = "title";
-    /**
-     * Hint that all sub-items/sub-slices within this content should be considered
-     * to have {@link #HINT_LIST_ITEM}.
-     */
-    public static final String HINT_LIST        = "list";
-    /**
-     * Hint that this item is part of a list and should be formatted as if is part
-     * of a list.
-     */
-    public static final String HINT_LIST_ITEM   = "list_item";
-    /**
-     * Hint that this content is important and should be larger when displayed if
-     * possible.
-     */
-    public static final String HINT_LARGE       = "large";
-    /**
-     * Hint that this slice contains a number of actions that can be grouped together
-     * in a sort of controls area of the UI.
-     */
-    public static final String HINT_ACTIONS     = "actions";
-    /**
-     * Hint indicating that this item (and its sub-items) are the current selection.
-     */
-    public static final String HINT_SELECTED    = "selected";
-    /**
-     * Hint to indicate that this is a message as part of a communication
-     * sequence in this slice.
-     */
-    public static final String HINT_MESSAGE     = "message";
-    /**
-     * Hint to tag the source (i.e. sender) of a {@link #HINT_MESSAGE}.
-     */
-    public static final String HINT_SOURCE      = "source";
-    /**
-     * Hint that list items within this slice or subslice would appear better
-     * if organized horizontally.
-     */
-    public static final String HINT_HORIZONTAL  = "horizontal";
-    /**
-     * Hint to indicate that this content should not be tinted.
-     */
-    public static final String HINT_NO_TINT     = "no_tint";
-
-    // These two are coming over from prototyping, but we probably don't want in
-    // public API, at least not right now.
-    /**
-     * @hide
-     */
-    public static final String HINT_ALT         = "alt";
-    /**
-     * @hide
-     */
-    public static final String HINT_PARTIAL     = "partial";
-
-    private final SliceItem[] mItems;
-    private final @SliceHint String[] mHints;
-    private Uri mUri;
-
-    /**
-     * @hide
-     */
-    public Slice(ArrayList<SliceItem> items, @SliceHint String[] hints, Uri uri) {
-        mHints = hints;
-        mItems = items.toArray(new SliceItem[items.size()]);
-        mUri = uri;
-    }
-
-    protected Slice(Parcel in) {
-        mHints = in.readStringArray();
-        int n = in.readInt();
-        mItems = new SliceItem[n];
-        for (int i = 0; i < n; i++) {
-            mItems[i] = SliceItem.CREATOR.createFromParcel(in);
-        }
-        mUri = Uri.CREATOR.createFromParcel(in);
-    }
-
-    /**
-     * @return The Uri that this Slice represents.
-     */
-    public Uri getUri() {
-        return mUri;
-    }
-
-    /**
-     * @return All child {@link SliceItem}s that this Slice contains.
-     */
-    public SliceItem[] getItems() {
-        return mItems;
-    }
-
-    /**
-     * @return All hints associated with this Slice.
-     */
-    public @SliceHint String[] getHints() {
-        return mHints;
-    }
-
-    /**
-     * @hide
-     */
-    public SliceItem getPrimaryIcon() {
-        for (SliceItem item : getItems()) {
-            if (item.getType() == TYPE_IMAGE) {
-                return item;
-            }
-            if (!(item.getType() == TYPE_SLICE && item.hasHint(Slice.HINT_LIST))
-                    && !item.hasHint(Slice.HINT_ACTIONS)
-                    && !item.hasHint(Slice.HINT_LIST_ITEM)
-                    && (item.getType() != TYPE_ACTION)) {
-                SliceItem icon = SliceQuery.find(item, TYPE_IMAGE);
-                if (icon != null) return icon;
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeStringArray(mHints);
-        dest.writeInt(mItems.length);
-        for (int i = 0; i < mItems.length; i++) {
-            mItems[i].writeToParcel(dest, flags);
-        }
-        mUri.writeToParcel(dest, 0);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    /**
-     * @hide
-     */
-    public boolean hasHint(@SliceHint String hint) {
-        return ArrayUtils.contains(mHints, hint);
-    }
-
-    /**
-     * A Builder used to construct {@link Slice}s
-     */
-    public static class Builder {
-
-        private final Uri mUri;
-        private ArrayList<SliceItem> mItems = new ArrayList<>();
-        private @SliceHint ArrayList<String> mHints = new ArrayList<>();
-
-        /**
-         * Create a builder which will construct a {@link Slice} for the Given Uri.
-         * @param uri Uri to tag for this slice.
-         */
-        public Builder(@NonNull Uri uri) {
-            mUri = uri;
-        }
-
-        /**
-         * Create a builder for a {@link Slice} that is a sub-slice of the slice
-         * being constructed by the provided builder.
-         * @param parent The builder constructing the parent slice
-         */
-        public Builder(@NonNull Slice.Builder parent) {
-            mUri = parent.mUri.buildUpon().appendPath("_gen")
-                    .appendPath(String.valueOf(mItems.size())).build();
-        }
-
-        /**
-         * Add hints to the Slice being constructed
-         */
-        public Builder addHints(@SliceHint String... hints) {
-            mHints.addAll(Arrays.asList(hints));
-            return this;
-        }
-
-        /**
-         * Add a sub-slice to the slice being constructed
-         */
-        public Builder addSubSlice(@NonNull Slice slice) {
-            mItems.add(new SliceItem(slice, TYPE_SLICE, slice.getHints()));
-            return this;
-        }
-
-        /**
-         * Add an action to the slice being constructed
-         */
-        public Slice.Builder addAction(@NonNull PendingIntent action, @NonNull Slice s) {
-            mItems.add(new SliceItem(action, s, TYPE_ACTION, new String[0]));
-            return this;
-        }
-
-        /**
-         * Add text to the slice being constructed
-         */
-        public Builder addText(CharSequence text, @SliceHint String... hints) {
-            mItems.add(new SliceItem(text, TYPE_TEXT, hints));
-            return this;
-        }
-
-        /**
-         * Add an image to the slice being constructed
-         */
-        public Builder addIcon(Icon icon, @SliceHint String... hints) {
-            mItems.add(new SliceItem(icon, TYPE_IMAGE, hints));
-            return this;
-        }
-
-        /**
-         * @hide This isn't final
-         */
-        public Builder addRemoteView(RemoteViews remoteView, @SliceHint String... hints) {
-            mItems.add(new SliceItem(remoteView, TYPE_REMOTE_VIEW, hints));
-            return this;
-        }
-
-        /**
-         * Add remote input to the slice being constructed
-         */
-        public Slice.Builder addRemoteInput(RemoteInput remoteInput, @SliceHint String... hints) {
-            mItems.add(new SliceItem(remoteInput, TYPE_REMOTE_INPUT, hints));
-            return this;
-        }
-
-        /**
-         * Add a color to the slice being constructed
-         */
-        public Builder addColor(int color, @SliceHint String... hints) {
-            mItems.add(new SliceItem(color, TYPE_COLOR, hints));
-            return this;
-        }
-
-        /**
-         * Add a timestamp to the slice being constructed
-         */
-        public Slice.Builder addTimestamp(long time, @SliceHint String... hints) {
-            mItems.add(new SliceItem(time, TYPE_TIMESTAMP, hints));
-            return this;
-        }
-
-        /**
-         * Construct the slice.
-         */
-        public Slice build() {
-            return new Slice(mItems, mHints.toArray(new String[mHints.size()]), mUri);
-        }
-    }
-
-    public static final Creator<Slice> CREATOR = new Creator<Slice>() {
-        @Override
-        public Slice createFromParcel(Parcel in) {
-            return new Slice(in);
-        }
-
-        @Override
-        public Slice[] newArray(int size) {
-            return new Slice[size];
-        }
-    };
-
-    /**
-     * @hide
-     * @return A string representation of this slice.
-     */
-    public String getString() {
-        return getString("");
-    }
-
-    private String getString(String indent) {
-        StringBuilder sb = new StringBuilder();
-        for (int i = 0; i < mItems.length; i++) {
-            sb.append(indent);
-            if (mItems[i].getType() == TYPE_SLICE) {
-                sb.append("slice:\n");
-                sb.append(mItems[i].getSlice().getString(indent + "   "));
-            } else if (mItems[i].getType() == TYPE_TEXT) {
-                sb.append("text: ");
-                sb.append(mItems[i].getText());
-                sb.append("\n");
-            } else {
-                sb.append(SliceItem.typeToString(mItems[i].getType()));
-                sb.append("\n");
-            }
-        }
-        return sb.toString();
-    }
-}
diff --git a/core/java/android/slice/SliceItem.java b/core/java/android/slice/SliceItem.java
deleted file mode 100644
index 2827ab9..0000000
--- a/core/java/android/slice/SliceItem.java
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.slice;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.app.PendingIntent;
-import android.app.RemoteInput;
-import android.graphics.drawable.Icon;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.slice.Slice.SliceHint;
-import android.text.TextUtils;
-import android.util.Pair;
-import android.widget.RemoteViews;
-
-import com.android.internal.util.ArrayUtils;
-
-
-/**
- * A SliceItem is a single unit in the tree structure of a {@link Slice}.
- *
- * A SliceItem a piece of content and some hints about what that content
- * means or how it should be displayed. The types of content can be:
- * <li>{@link #TYPE_SLICE}</li>
- * <li>{@link #TYPE_TEXT}</li>
- * <li>{@link #TYPE_IMAGE}</li>
- * <li>{@link #TYPE_ACTION}</li>
- * <li>{@link #TYPE_COLOR}</li>
- * <li>{@link #TYPE_TIMESTAMP}</li>
- * <li>{@link #TYPE_REMOTE_INPUT}</li>
- *
- * The hints that a {@link SliceItem} are a set of strings which annotate
- * the content. The hints that are guaranteed to be understood by the system
- * are defined on {@link Slice}.
- * @hide
- */
-public final class SliceItem implements Parcelable {
-
-    /**
-     * @hide
-     */
-    @IntDef({TYPE_SLICE, TYPE_TEXT, TYPE_IMAGE, TYPE_ACTION, TYPE_COLOR,
-            TYPE_TIMESTAMP, TYPE_REMOTE_INPUT})
-    public @interface SliceType {}
-
-    /**
-     * A {@link SliceItem} that contains a {@link Slice}
-     */
-    public static final int TYPE_SLICE        = 1;
-    /**
-     * A {@link SliceItem} that contains a {@link CharSequence}
-     */
-    public static final int TYPE_TEXT         = 2;
-    /**
-     * A {@link SliceItem} that contains an {@link Icon}
-     */
-    public static final int TYPE_IMAGE        = 3;
-    /**
-     * A {@link SliceItem} that contains a {@link PendingIntent}
-     *
-     * Note: Actions contain 2 pieces of data, In addition to the pending intent, the
-     * item contains a {@link Slice} that the action applies to.
-     */
-    public static final int TYPE_ACTION       = 4;
-    /**
-     * @hide This isn't final
-     */
-    public static final int TYPE_REMOTE_VIEW  = 5;
-    /**
-     * A {@link SliceItem} that contains a Color int.
-     */
-    public static final int TYPE_COLOR        = 6;
-    /**
-     * A {@link SliceItem} that contains a timestamp.
-     */
-    public static final int TYPE_TIMESTAMP    = 8;
-    /**
-     * A {@link SliceItem} that contains a {@link RemoteInput}.
-     */
-    public static final int TYPE_REMOTE_INPUT = 9;
-
-    /**
-     * @hide
-     */
-    protected @SliceHint String[] mHints;
-    private final int mType;
-    private final Object mObj;
-
-    /**
-     * @hide
-     */
-    public SliceItem(Object obj, @SliceType int type, @SliceHint String[] hints) {
-        mHints = hints;
-        mType = type;
-        mObj = obj;
-    }
-
-    /**
-     * @hide
-     */
-    public SliceItem(PendingIntent intent, Slice slice, int type, @SliceHint String[] hints) {
-        this(new Pair<>(intent, slice), type, hints);
-    }
-
-    /**
-     * Gets all hints associated with this SliceItem.
-     * @return Array of hints.
-     */
-    public @NonNull @SliceHint String[] getHints() {
-        return mHints;
-    }
-
-    /**
-     * @hide
-     */
-    public void addHint(@SliceHint String hint) {
-        mHints = ArrayUtils.appendElement(String.class, mHints, hint);
-    }
-
-    /**
-     * @hide
-     */
-    public void removeHint(String hint) {
-        ArrayUtils.removeElement(String.class, mHints, hint);
-    }
-
-    public @SliceType int getType() {
-        return mType;
-    }
-
-    /**
-     * @return The text held by this {@link #TYPE_TEXT} SliceItem
-     */
-    public CharSequence getText() {
-        return (CharSequence) mObj;
-    }
-
-    /**
-     * @return The icon held by this {@link #TYPE_IMAGE} SliceItem
-     */
-    public Icon getIcon() {
-        return (Icon) mObj;
-    }
-
-    /**
-     * @return The pending intent held by this {@link #TYPE_ACTION} SliceItem
-     */
-    public PendingIntent getAction() {
-        return ((Pair<PendingIntent, Slice>) mObj).first;
-    }
-
-    /**
-     * @hide This isn't final
-     */
-    public RemoteViews getRemoteView() {
-        return (RemoteViews) mObj;
-    }
-
-    /**
-     * @return The remote input held by this {@link #TYPE_REMOTE_INPUT} SliceItem
-     */
-    public RemoteInput getRemoteInput() {
-        return (RemoteInput) mObj;
-    }
-
-    /**
-     * @return The color held by this {@link #TYPE_COLOR} SliceItem
-     */
-    public int getColor() {
-        return (Integer) mObj;
-    }
-
-    /**
-     * @return The slice held by this {@link #TYPE_ACTION} or {@link #TYPE_SLICE} SliceItem
-     */
-    public Slice getSlice() {
-        if (getType() == TYPE_ACTION) {
-            return ((Pair<PendingIntent, Slice>) mObj).second;
-        }
-        return (Slice) mObj;
-    }
-
-    /**
-     * @return The timestamp held by this {@link #TYPE_TIMESTAMP} SliceItem
-     */
-    public long getTimestamp() {
-        return (Long) mObj;
-    }
-
-    /**
-     * @param hint The hint to check for
-     * @return true if this item contains the given hint
-     */
-    public boolean hasHint(@SliceHint String hint) {
-        return ArrayUtils.contains(mHints, hint);
-    }
-
-    /**
-     * @hide
-     */
-    public SliceItem(Parcel in) {
-        mHints = in.readStringArray();
-        mType = in.readInt();
-        mObj = readObj(mType, in);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeStringArray(mHints);
-        dest.writeInt(mType);
-        writeObj(dest, flags, mObj, mType);
-    }
-
-    /**
-     * @hide
-     */
-    public boolean hasHints(@SliceHint String[] hints) {
-        if (hints == null) return true;
-        for (String hint : hints) {
-            if (!TextUtils.isEmpty(hint) && !ArrayUtils.contains(mHints, hint)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * @hide
-     */
-    public boolean hasAnyHints(@SliceHint String[] hints) {
-        if (hints == null) return false;
-        for (String hint : hints) {
-            if (ArrayUtils.contains(mHints, hint)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private void writeObj(Parcel dest, int flags, Object obj, int type) {
-        switch (type) {
-            case TYPE_SLICE:
-            case TYPE_REMOTE_VIEW:
-            case TYPE_IMAGE:
-            case TYPE_REMOTE_INPUT:
-                ((Parcelable) obj).writeToParcel(dest, flags);
-                break;
-            case TYPE_ACTION:
-                ((Pair<PendingIntent, Slice>) obj).first.writeToParcel(dest, flags);
-                ((Pair<PendingIntent, Slice>) obj).second.writeToParcel(dest, flags);
-                break;
-            case TYPE_TEXT:
-                TextUtils.writeToParcel((CharSequence) mObj, dest, flags);
-                break;
-            case TYPE_COLOR:
-                dest.writeInt((Integer) mObj);
-                break;
-            case TYPE_TIMESTAMP:
-                dest.writeLong((Long) mObj);
-                break;
-        }
-    }
-
-    private static Object readObj(int type, Parcel in) {
-        switch (type) {
-            case TYPE_SLICE:
-                return Slice.CREATOR.createFromParcel(in);
-            case TYPE_TEXT:
-                return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-            case TYPE_IMAGE:
-                return Icon.CREATOR.createFromParcel(in);
-            case TYPE_ACTION:
-                return new Pair<PendingIntent, Slice>(
-                        PendingIntent.CREATOR.createFromParcel(in),
-                        Slice.CREATOR.createFromParcel(in));
-            case TYPE_REMOTE_VIEW:
-                return RemoteViews.CREATOR.createFromParcel(in);
-            case TYPE_COLOR:
-                return in.readInt();
-            case TYPE_TIMESTAMP:
-                return in.readLong();
-            case TYPE_REMOTE_INPUT:
-                return RemoteInput.CREATOR.createFromParcel(in);
-        }
-        throw new RuntimeException("Unsupported type " + type);
-    }
-
-    public static final Creator<SliceItem> CREATOR = new Creator<SliceItem>() {
-        @Override
-        public SliceItem createFromParcel(Parcel in) {
-            return new SliceItem(in);
-        }
-
-        @Override
-        public SliceItem[] newArray(int size) {
-            return new SliceItem[size];
-        }
-    };
-
-    /**
-     * @hide
-     */
-    public static String typeToString(int type) {
-        switch (type) {
-            case TYPE_SLICE:
-                return "Slice";
-            case TYPE_TEXT:
-                return "Text";
-            case TYPE_IMAGE:
-                return "Image";
-            case TYPE_ACTION:
-                return "Action";
-            case TYPE_REMOTE_VIEW:
-                return "RemoteView";
-            case TYPE_COLOR:
-                return "Color";
-            case TYPE_TIMESTAMP:
-                return "Timestamp";
-            case TYPE_REMOTE_INPUT:
-                return "RemoteInput";
-        }
-        return "Unrecognized type: " + type;
-    }
-}
diff --git a/core/java/android/slice/SliceProvider.java b/core/java/android/slice/SliceProvider.java
deleted file mode 100644
index 4e21371..0000000
--- a/core/java/android/slice/SliceProvider.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.slice;
-
-import android.Manifest.permission;
-import android.content.ContentProvider;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.CancellationSignal;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Log;
-
-import java.util.concurrent.CountDownLatch;
-
-/**
- * A SliceProvider allows app to provide content to be displayed in system
- * spaces. This content is templated and can contain actions, and the behavior
- * of how it is surfaced is specific to the system surface.
- *
- * <p>Slices are not currently live content. They are bound once and shown to the
- * user. If the content changes due to a callback from user interaction, then
- * {@link ContentResolver#notifyChange(Uri, ContentObserver)}
- * should be used to notify the system.</p>
- *
- * <p>The provider needs to be declared in the manifest to provide the authority
- * for the app. The authority for most slices is expected to match the package
- * of the application.</p>
- * <pre class="prettyprint">
- * {@literal
- * <provider
- *     android:name="com.android.mypkg.MySliceProvider"
- *     android:authorities="com.android.mypkg" />}
- * </pre>
- *
- * @see Slice
- * @hide
- */
-public abstract class SliceProvider extends ContentProvider {
-
-    private static final String TAG = "SliceProvider";
-    /**
-     * @hide
-     */
-    public static final String EXTRA_BIND_URI = "slice_uri";
-    /**
-     * @hide
-     */
-    public static final String METHOD_SLICE = "bind_slice";
-    /**
-     * @hide
-     */
-    public static final String EXTRA_SLICE = "slice";
-
-    private static final boolean DEBUG = false;
-
-    /**
-     * Implemented to create a slice. Will be called on the main thread.
-     * @see {@link Slice}.
-     */
-    public abstract Slice onBindSlice(Uri sliceUri);
-
-    @Override
-    public final int update(Uri uri, ContentValues values, String selection,
-            String[] selectionArgs) {
-        if (DEBUG) Log.d(TAG, "update " + uri);
-        return 0;
-    }
-
-    @Override
-    public final int delete(Uri uri, String selection, String[] selectionArgs) {
-        if (DEBUG) Log.d(TAG, "delete " + uri);
-        return 0;
-    }
-
-    @Override
-    public final Cursor query(Uri uri, String[] projection, String selection,
-            String[] selectionArgs, String sortOrder) {
-        if (DEBUG) Log.d(TAG, "query " + uri);
-        return null;
-    }
-
-    @Override
-    public final Cursor query(Uri uri, String[] projection, String selection, String[]
-            selectionArgs, String sortOrder, CancellationSignal cancellationSignal) {
-        if (DEBUG) Log.d(TAG, "query " + uri);
-        return null;
-    }
-
-    @Override
-    public final Cursor query(Uri uri, String[] projection, Bundle queryArgs,
-            CancellationSignal cancellationSignal) {
-        if (DEBUG) Log.d(TAG, "query " + uri);
-        return null;
-    }
-
-    @Override
-    public final Uri insert(Uri uri, ContentValues values) {
-        if (DEBUG) Log.d(TAG, "insert " + uri);
-        return null;
-    }
-
-    @Override
-    public final String getType(Uri uri) {
-        if (DEBUG) Log.d(TAG, "getType " + uri);
-        return null;
-    }
-
-    @Override
-    public final Bundle call(String method, String arg, Bundle extras) {
-        if (method.equals(METHOD_SLICE)) {
-            getContext().enforceCallingPermission(permission.BIND_SLICE,
-                    "Slice binding requires the permission BIND_SLICE");
-            Uri uri = extras.getParcelable(EXTRA_BIND_URI);
-
-            Slice s = handleBindSlice(uri);
-            Bundle b = new Bundle();
-            b.putParcelable(EXTRA_SLICE, s);
-            return b;
-        }
-        return super.call(method, arg, extras);
-    }
-
-    private Slice handleBindSlice(Uri sliceUri) {
-        Slice[] output = new Slice[1];
-        CountDownLatch latch = new CountDownLatch(1);
-        Handler mainHandler = new Handler(Looper.getMainLooper());
-        mainHandler.post(() -> {
-            output[0] = onBindSlice(sliceUri);
-            latch.countDown();
-        });
-        try {
-            latch.await();
-            return output[0];
-        } catch (InterruptedException e) {
-            throw new RuntimeException(e);
-        }
-    }
-}
diff --git a/core/java/android/slice/SliceQuery.java b/core/java/android/slice/SliceQuery.java
deleted file mode 100644
index d99b26a..0000000
--- a/core/java/android/slice/SliceQuery.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.slice;
-
-import static android.slice.SliceItem.TYPE_ACTION;
-import static android.slice.SliceItem.TYPE_SLICE;
-
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Queue;
-import java.util.Spliterators;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
-
-/**
- * A bunch of utilities for searching the contents of a slice.
- * @hide
- */
-public class SliceQuery {
-    private static final String TAG = "SliceQuery";
-
-    /**
-     * @hide
-     */
-    public static SliceItem findNotContaining(SliceItem container, List<SliceItem> list) {
-        SliceItem ret = null;
-        while (ret == null && list.size() != 0) {
-            SliceItem remove = list.remove(0);
-            if (!contains(container, remove)) {
-                ret = remove;
-            }
-        }
-        return ret;
-    }
-
-    /**
-     * @hide
-     */
-    private static boolean contains(SliceItem container, SliceItem item) {
-        if (container == null || item == null) return false;
-        return stream(container).filter(s -> (s == item)).findAny().isPresent();
-    }
-
-    /**
-     * @hide
-     */
-    public static List<SliceItem> findAll(SliceItem s, int type) {
-        return findAll(s, type, (String[]) null, null);
-    }
-
-    /**
-     * @hide
-     */
-    public static List<SliceItem> findAll(SliceItem s, int type, String hints, String nonHints) {
-        return findAll(s, type, new String[]{ hints }, new String[]{ nonHints });
-    }
-
-    /**
-     * @hide
-     */
-    public static List<SliceItem> findAll(SliceItem s, int type, String[] hints,
-            String[] nonHints) {
-        return stream(s).filter(item -> (type == -1 || item.getType() == type)
-                && (item.hasHints(hints) && !item.hasAnyHints(nonHints)))
-                .collect(Collectors.toList());
-    }
-
-    /**
-     * @hide
-     */
-    public static SliceItem find(Slice s, int type, String hints, String nonHints) {
-        return find(s, type, new String[]{ hints }, new String[]{ nonHints });
-    }
-
-    /**
-     * @hide
-     */
-    public static SliceItem find(Slice s, int type) {
-        return find(s, type, (String[]) null, null);
-    }
-
-    /**
-     * @hide
-     */
-    public static SliceItem find(SliceItem s, int type) {
-        return find(s, type, (String[]) null, null);
-    }
-
-    /**
-     * @hide
-     */
-    public static SliceItem find(SliceItem s, int type, String hints, String nonHints) {
-        return find(s, type, new String[]{ hints }, new String[]{ nonHints });
-    }
-
-    /**
-     * @hide
-     */
-    public static SliceItem find(Slice s, int type, String[] hints, String[] nonHints) {
-        return find(new SliceItem(s, TYPE_SLICE, s.getHints()), type, hints, nonHints);
-    }
-
-    /**
-     * @hide
-     */
-    public static SliceItem find(SliceItem s, int type, String[] hints, String[] nonHints) {
-        return stream(s).filter(item -> (item.getType() == type || type == -1)
-                && (item.hasHints(hints) && !item.hasAnyHints(nonHints))).findFirst().orElse(null);
-    }
-
-    /**
-     * @hide
-     */
-    public static Stream<SliceItem> stream(SliceItem slice) {
-        Queue<SliceItem> items = new LinkedList();
-        items.add(slice);
-        Iterator<SliceItem> iterator = new Iterator<SliceItem>() {
-            @Override
-            public boolean hasNext() {
-                return items.size() != 0;
-            }
-
-            @Override
-            public SliceItem next() {
-                SliceItem item = items.poll();
-                if (item.getType() == TYPE_SLICE || item.getType() == TYPE_ACTION) {
-                    items.addAll(Arrays.asList(item.getSlice().getItems()));
-                }
-                return item;
-            }
-        };
-        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);
-    }
-}
diff --git a/core/java/android/slice/views/ActionRow.java b/core/java/android/slice/views/ActionRow.java
deleted file mode 100644
index 93e9c03..0000000
--- a/core/java/android/slice/views/ActionRow.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.slice.views;
-
-import android.app.PendingIntent;
-import android.app.PendingIntent.CanceledException;
-import android.app.RemoteInput;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.Color;
-import android.graphics.drawable.Icon;
-import android.os.AsyncTask;
-import android.slice.Slice;
-import android.slice.SliceItem;
-import android.slice.SliceQuery;
-import android.util.TypedValue;
-import android.view.View;
-import android.view.ViewParent;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.ImageView.ScaleType;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-/**
- * @hide
- */
-public class ActionRow extends FrameLayout {
-
-    private static final int MAX_ACTIONS = 5;
-    private final int mSize;
-    private final int mIconPadding;
-    private final LinearLayout mActionsGroup;
-    private final boolean mFullActions;
-    private int mColor = Color.BLACK;
-
-    public ActionRow(Context context, boolean fullActions) {
-        super(context);
-        mFullActions = fullActions;
-        mSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48,
-                context.getResources().getDisplayMetrics());
-        mIconPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 12,
-                context.getResources().getDisplayMetrics());
-        mActionsGroup = new LinearLayout(context);
-        mActionsGroup.setOrientation(LinearLayout.HORIZONTAL);
-        mActionsGroup.setLayoutParams(
-                new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
-        addView(mActionsGroup);
-    }
-
-    private void setColor(int color) {
-        mColor = color;
-        for (int i = 0; i < mActionsGroup.getChildCount(); i++) {
-            View view = mActionsGroup.getChildAt(i);
-            SliceItem item = (SliceItem) view.getTag();
-            boolean tint = !item.hasHint(Slice.HINT_NO_TINT);
-            if (tint) {
-                ((ImageView) view).setImageTintList(ColorStateList.valueOf(mColor));
-            }
-        }
-    }
-
-    private ImageView addAction(Icon icon, boolean allowTint, SliceItem image) {
-        ImageView imageView = new ImageView(getContext());
-        imageView.setPadding(mIconPadding, mIconPadding, mIconPadding, mIconPadding);
-        imageView.setScaleType(ScaleType.FIT_CENTER);
-        imageView.setImageIcon(icon);
-        if (allowTint) {
-            imageView.setImageTintList(ColorStateList.valueOf(mColor));
-        }
-        imageView.setBackground(SliceViewUtil.getDrawable(getContext(),
-                android.R.attr.selectableItemBackground));
-        imageView.setTag(image);
-        addAction(imageView);
-        return imageView;
-    }
-
-    /**
-     * Set the actions and color for this action row.
-     */
-    public void setActions(SliceItem actionRow, SliceItem defColor) {
-        removeAllViews();
-        mActionsGroup.removeAllViews();
-        addView(mActionsGroup);
-
-        SliceItem color = SliceQuery.find(actionRow, SliceItem.TYPE_COLOR);
-        if (color == null) {
-            color = defColor;
-        }
-        if (color != null) {
-            setColor(color.getColor());
-        }
-        SliceQuery.findAll(actionRow, SliceItem.TYPE_ACTION).forEach(action -> {
-            if (mActionsGroup.getChildCount() >= MAX_ACTIONS) {
-                return;
-            }
-            SliceItem image = SliceQuery.find(action, SliceItem.TYPE_IMAGE);
-            if (image == null) {
-                return;
-            }
-            boolean tint = !image.hasHint(Slice.HINT_NO_TINT);
-            SliceItem input = SliceQuery.find(action, SliceItem.TYPE_REMOTE_INPUT);
-            if (input != null && input.getRemoteInput().getAllowFreeFormInput()) {
-                addAction(image.getIcon(), tint, image).setOnClickListener(
-                        v -> handleRemoteInputClick(v, action.getAction(), input.getRemoteInput()));
-                createRemoteInputView(mColor, getContext());
-            } else {
-                addAction(image.getIcon(), tint, image).setOnClickListener(v -> AsyncTask.execute(
-                        () -> {
-                            try {
-                                action.getAction().send();
-                            } catch (CanceledException e) {
-                                e.printStackTrace();
-                            }
-                        }));
-            }
-        });
-        setVisibility(getChildCount() != 0 ? View.VISIBLE : View.GONE);
-    }
-
-    private void addAction(View child) {
-        mActionsGroup.addView(child, new LinearLayout.LayoutParams(mSize, mSize, 1));
-    }
-
-    private void createRemoteInputView(int color, Context context) {
-        View riv = RemoteInputView.inflate(context, this);
-        riv.setVisibility(View.INVISIBLE);
-        addView(riv, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
-        riv.setBackgroundColor(color);
-    }
-
-    private boolean handleRemoteInputClick(View view, PendingIntent pendingIntent,
-            RemoteInput input) {
-        if (input == null) {
-            return false;
-        }
-
-        ViewParent p = view.getParent().getParent();
-        RemoteInputView riv = null;
-        while (p != null) {
-            if (p instanceof View) {
-                View pv = (View) p;
-                riv = findRemoteInputView(pv);
-                if (riv != null) {
-                    break;
-                }
-            }
-            p = p.getParent();
-        }
-        if (riv == null) {
-            return false;
-        }
-
-        int width = view.getWidth();
-        if (view instanceof TextView) {
-            // Center the reveal on the text which might be off-center from the TextView
-            TextView tv = (TextView) view;
-            if (tv.getLayout() != null) {
-                int innerWidth = (int) tv.getLayout().getLineWidth(0);
-                innerWidth += tv.getCompoundPaddingLeft() + tv.getCompoundPaddingRight();
-                width = Math.min(width, innerWidth);
-            }
-        }
-        int cx = view.getLeft() + width / 2;
-        int cy = view.getTop() + view.getHeight() / 2;
-        int w = riv.getWidth();
-        int h = riv.getHeight();
-        int r = Math.max(
-                Math.max(cx + cy, cx + (h - cy)),
-                Math.max((w - cx) + cy, (w - cx) + (h - cy)));
-
-        riv.setRevealParameters(cx, cy, r);
-        riv.setPendingIntent(pendingIntent);
-        riv.setRemoteInput(new RemoteInput[] {
-                input
-        }, input);
-        riv.focusAnimated();
-        return true;
-    }
-
-    private RemoteInputView findRemoteInputView(View v) {
-        if (v == null) {
-            return null;
-        }
-        return (RemoteInputView) v.findViewWithTag(RemoteInputView.VIEW_TAG);
-    }
-}
diff --git a/core/java/android/slice/views/GridView.java b/core/java/android/slice/views/GridView.java
deleted file mode 100644
index 18a90f7..0000000
--- a/core/java/android/slice/views/GridView.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.slice.views;
-
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-
-import android.content.Context;
-import android.graphics.Color;
-import android.slice.Slice;
-import android.slice.SliceItem;
-import android.slice.views.LargeSliceAdapter.SliceListView;
-import android.util.AttributeSet;
-import android.util.TypedValue;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.ImageView.ScaleType;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.android.internal.R;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-
-/**
- * @hide
- */
-public class GridView extends LinearLayout implements SliceListView {
-
-    private static final String TAG = "GridView";
-
-    private static final int MAX_IMAGES = 3;
-    private static final int MAX_ALL = 5;
-    private boolean mIsAllImages;
-
-    public GridView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        if (mIsAllImages) {
-            int width = MeasureSpec.getSize(widthMeasureSpec);
-            int height = width / getChildCount();
-            heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.EXACTLY,
-                    height);
-            getLayoutParams().height = height;
-            for (int i = 0; i < getChildCount(); i++) {
-                getChildAt(i).getLayoutParams().height = height;
-            }
-        }
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-    }
-
-    @Override
-    public void setSliceItem(SliceItem slice) {
-        mIsAllImages = true;
-        removeAllViews();
-        int total = 1;
-        if (slice.getType() == SliceItem.TYPE_SLICE) {
-            SliceItem[] items = slice.getSlice().getItems();
-            total = items.length;
-            for (int i = 0; i < total; i++) {
-                SliceItem item = items[i];
-                if (isFull()) {
-                    continue;
-                }
-                if (!addItem(item)) {
-                    mIsAllImages = false;
-                }
-            }
-        } else {
-            if (!isFull()) {
-                if (!addItem(slice)) {
-                    mIsAllImages = false;
-                }
-            }
-        }
-        if (total > getChildCount() && mIsAllImages) {
-            addExtraCount(total - getChildCount());
-        }
-    }
-
-    private void addExtraCount(int numExtra) {
-        View last = getChildAt(getChildCount() - 1);
-        FrameLayout frame = new FrameLayout(getContext());
-        frame.setLayoutParams(last.getLayoutParams());
-
-        removeView(last);
-        frame.addView(last, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
-
-        TextView v = new TextView(getContext());
-        v.setTextColor(Color.WHITE);
-        v.setBackgroundColor(0x4d000000);
-        v.setText(getResources().getString(R.string.slice_more_content, numExtra));
-        v.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
-        v.setGravity(Gravity.CENTER);
-        frame.addView(v, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
-
-        addView(frame);
-    }
-
-    private boolean isFull() {
-        return getChildCount() >= (mIsAllImages ? MAX_IMAGES : MAX_ALL);
-    }
-
-    /**
-     * Returns true if this item is just an image.
-     */
-    private boolean addItem(SliceItem item) {
-        if (item.getType() == SliceItem.TYPE_IMAGE) {
-            ImageView v = new ImageView(getContext());
-            v.setImageIcon(item.getIcon());
-            v.setScaleType(ScaleType.CENTER_CROP);
-            addView(v, new LayoutParams(0, MATCH_PARENT, 1));
-            return true;
-        } else {
-            LinearLayout v = new LinearLayout(getContext());
-            int s = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-                    12, getContext().getResources().getDisplayMetrics());
-            v.setPadding(0, s, 0, 0);
-            v.setOrientation(LinearLayout.VERTICAL);
-            v.setGravity(Gravity.CENTER_HORIZONTAL);
-            // TODO: Unify sporadic inflates that happen throughout the code.
-            ArrayList<SliceItem> items = new ArrayList<>();
-            if (item.getType() == SliceItem.TYPE_SLICE) {
-                items.addAll(Arrays.asList(item.getSlice().getItems()));
-            }
-            items.forEach(i -> {
-                Context context = getContext();
-                switch (i.getType()) {
-                    case SliceItem.TYPE_TEXT:
-                        boolean title = false;
-                        if ((item.hasAnyHints(new String[] {
-                                Slice.HINT_LARGE, Slice.HINT_TITLE
-                        }))) {
-                            title = true;
-                        }
-                        TextView tv = (TextView) LayoutInflater.from(context).inflate(
-                                title ? R.layout.slice_title : R.layout.slice_secondary_text, null);
-                        tv.setText(i.getText());
-                        v.addView(tv);
-                        break;
-                    case SliceItem.TYPE_IMAGE:
-                        ImageView iv = new ImageView(context);
-                        iv.setImageIcon(i.getIcon());
-                        if (item.hasHint(Slice.HINT_LARGE)) {
-                            iv.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
-                        } else {
-                            int size = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-                                    48, context.getResources().getDisplayMetrics());
-                            iv.setLayoutParams(new LayoutParams(size, size));
-                        }
-                        v.addView(iv);
-                        break;
-                    case SliceItem.TYPE_REMOTE_VIEW:
-                        v.addView(i.getRemoteView().apply(context, v));
-                        break;
-                    case SliceItem.TYPE_COLOR:
-                        // TODO: Support color to tint stuff here.
-                        break;
-                }
-            });
-            addView(v, new LayoutParams(0, WRAP_CONTENT, 1));
-            return false;
-        }
-    }
-}
diff --git a/core/java/android/slice/views/LargeSliceAdapter.java b/core/java/android/slice/views/LargeSliceAdapter.java
deleted file mode 100644
index e77a1b2..0000000
--- a/core/java/android/slice/views/LargeSliceAdapter.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.slice.views;
-
-import android.content.Context;
-import android.slice.Slice;
-import android.slice.SliceItem;
-import android.slice.SliceQuery;
-import android.slice.views.LargeSliceAdapter.SliceViewHolder;
-import android.util.ArrayMap;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
-import android.widget.FrameLayout;
-
-import com.android.internal.R;
-import com.android.internal.widget.RecyclerView;
-import com.android.internal.widget.RecyclerView.ViewHolder;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * @hide
- */
-public class LargeSliceAdapter extends RecyclerView.Adapter<SliceViewHolder> {
-
-    public static final int TYPE_DEFAULT       = 1;
-    public static final int TYPE_HEADER        = 2;
-    public static final int TYPE_GRID          = 3;
-    public static final int TYPE_MESSAGE       = 4;
-    public static final int TYPE_MESSAGE_LOCAL = 5;
-    public static final int TYPE_REMOTE_VIEWS  = 6;
-
-    private final IdGenerator mIdGen = new IdGenerator();
-    private final Context mContext;
-    private List<SliceWrapper> mSlices = new ArrayList<>();
-    private SliceItem mColor;
-
-    public LargeSliceAdapter(Context context) {
-        mContext = context;
-        setHasStableIds(true);
-    }
-
-    /**
-     * Set the {@link SliceItem}'s to be displayed in the adapter and the accent color.
-     */
-    public void setSliceItems(List<SliceItem> slices, SliceItem color) {
-        mColor = color;
-        mIdGen.resetUsage();
-        mSlices = slices.stream().map(s -> new SliceWrapper(s, mIdGen))
-                .collect(Collectors.toList());
-        notifyDataSetChanged();
-    }
-
-    @Override
-    public SliceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-        View v = inflateforType(viewType);
-        v.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
-        return new SliceViewHolder(v);
-    }
-
-    @Override
-    public int getItemViewType(int position) {
-        return mSlices.get(position).mType;
-    }
-
-    @Override
-    public long getItemId(int position) {
-        return mSlices.get(position).mId;
-    }
-
-    @Override
-    public int getItemCount() {
-        return mSlices.size();
-    }
-
-    @Override
-    public void onBindViewHolder(SliceViewHolder holder, int position) {
-        SliceWrapper slice = mSlices.get(position);
-        if (holder.mSliceView != null) {
-            holder.mSliceView.setColor(mColor);
-            holder.mSliceView.setSliceItem(slice.mItem);
-        } else if (slice.mType == TYPE_REMOTE_VIEWS) {
-            FrameLayout frame = (FrameLayout) holder.itemView;
-            frame.removeAllViews();
-            frame.addView(slice.mItem.getRemoteView().apply(mContext, frame));
-        }
-    }
-
-    private View inflateforType(int viewType) {
-        switch (viewType) {
-            case TYPE_REMOTE_VIEWS:
-                return new FrameLayout(mContext);
-            case TYPE_GRID:
-                return LayoutInflater.from(mContext).inflate(R.layout.slice_grid, null);
-            case TYPE_MESSAGE:
-                return LayoutInflater.from(mContext).inflate(R.layout.slice_message, null);
-            case TYPE_MESSAGE_LOCAL:
-                return LayoutInflater.from(mContext).inflate(R.layout.slice_message_local, null);
-        }
-        return new SmallTemplateView(mContext);
-    }
-
-    protected static class SliceWrapper {
-        private final SliceItem mItem;
-        private final int mType;
-        private final long mId;
-
-        public SliceWrapper(SliceItem item, IdGenerator idGen) {
-            mItem = item;
-            mType = getType(item);
-            mId = idGen.getId(item);
-        }
-
-        public static int getType(SliceItem item) {
-            if (item.getType() == SliceItem.TYPE_REMOTE_VIEW) {
-                return TYPE_REMOTE_VIEWS;
-            }
-            if (item.hasHint(Slice.HINT_MESSAGE)) {
-                // TODO: Better way to determine me or not? Something more like Messaging style.
-                if (SliceQuery.find(item, -1, Slice.HINT_SOURCE, null) != null) {
-                    return TYPE_MESSAGE;
-                } else {
-                    return TYPE_MESSAGE_LOCAL;
-                }
-            }
-            if (item.hasHint(Slice.HINT_HORIZONTAL)) {
-                return TYPE_GRID;
-            }
-            return TYPE_DEFAULT;
-        }
-    }
-
-    /**
-     * A {@link ViewHolder} for presenting slices in {@link LargeSliceAdapter}.
-     */
-    public static class SliceViewHolder extends ViewHolder {
-        public final SliceListView mSliceView;
-
-        public SliceViewHolder(View itemView) {
-            super(itemView);
-            mSliceView = itemView instanceof SliceListView ? (SliceListView) itemView : null;
-        }
-    }
-
-    /**
-     * View slices being displayed in {@link LargeSliceAdapter}.
-     */
-    public interface SliceListView {
-        /**
-         * Set the slice item for this view.
-         */
-        void setSliceItem(SliceItem slice);
-
-        /**
-         * Set the color for the items in this view.
-         */
-        default void setColor(SliceItem color) {
-
-        }
-    }
-
-    private static class IdGenerator {
-        private long mNextLong = 0;
-        private final ArrayMap<String, Long> mCurrentIds = new ArrayMap<>();
-        private final ArrayMap<String, Integer> mUsedIds = new ArrayMap<>();
-
-        public long getId(SliceItem item) {
-            String str = genString(item);
-            if (!mCurrentIds.containsKey(str)) {
-                mCurrentIds.put(str, mNextLong++);
-            }
-            long id = mCurrentIds.get(str);
-            int index = mUsedIds.getOrDefault(str, 0);
-            mUsedIds.put(str, index + 1);
-            return id + index * 10000;
-        }
-
-        private String genString(SliceItem item) {
-            StringBuilder builder = new StringBuilder();
-            SliceQuery.stream(item).forEach(i -> {
-                builder.append(i.getType());
-                i.removeHint(Slice.HINT_SELECTED);
-                builder.append(i.getHints());
-                switch (i.getType()) {
-                    case SliceItem.TYPE_REMOTE_VIEW:
-                        builder.append(i.getRemoteView());
-                        break;
-                    case SliceItem.TYPE_IMAGE:
-                        builder.append(i.getIcon());
-                        break;
-                    case SliceItem.TYPE_TEXT:
-                        builder.append(i.getText());
-                        break;
-                    case SliceItem.TYPE_COLOR:
-                        builder.append(i.getColor());
-                        break;
-                }
-            });
-            return builder.toString();
-        }
-
-        public void resetUsage() {
-            mUsedIds.clear();
-        }
-    }
-}
diff --git a/core/java/android/slice/views/LargeTemplateView.java b/core/java/android/slice/views/LargeTemplateView.java
deleted file mode 100644
index d53e8fc..0000000
--- a/core/java/android/slice/views/LargeTemplateView.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.slice.views;
-
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-
-import android.content.Context;
-import android.slice.Slice;
-import android.slice.SliceItem;
-import android.slice.SliceQuery;
-import android.slice.views.SliceView.SliceModeView;
-import android.util.TypedValue;
-
-import com.android.internal.widget.LinearLayoutManager;
-import com.android.internal.widget.RecyclerView;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * @hide
- */
-public class LargeTemplateView extends SliceModeView {
-    private final LargeSliceAdapter mAdapter;
-    private final RecyclerView mRecyclerView;
-    private final int mDefaultHeight;
-    private final int mMaxHeight;
-    private Slice mSlice;
-
-    public LargeTemplateView(Context context) {
-        super(context);
-
-        mRecyclerView = new RecyclerView(getContext());
-        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
-        mAdapter = new LargeSliceAdapter(context);
-        mRecyclerView.setAdapter(mAdapter);
-        addView(mRecyclerView);
-        int width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 300,
-                getResources().getDisplayMetrics());
-        setLayoutParams(new LayoutParams(width, WRAP_CONTENT));
-        mDefaultHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200,
-                getResources().getDisplayMetrics());
-        mMaxHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200,
-                getResources().getDisplayMetrics());
-    }
-
-    @Override
-    public String getMode() {
-        return SliceView.MODE_LARGE;
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        mRecyclerView.getLayoutParams().height = WRAP_CONTENT;
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        if (mRecyclerView.getMeasuredHeight() > mMaxHeight
-                || mSlice.hasHint(Slice.HINT_PARTIAL)) {
-            mRecyclerView.getLayoutParams().height = mDefaultHeight;
-        } else {
-            mRecyclerView.getLayoutParams().height = mRecyclerView.getMeasuredHeight();
-        }
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-    }
-
-    @Override
-    public void setSlice(Slice slice) {
-        SliceItem color = SliceQuery.find(slice, SliceItem.TYPE_COLOR);
-        mSlice = slice;
-        List<SliceItem> items = new ArrayList<>();
-        boolean[] hasHeader = new boolean[1];
-        if (slice.hasHint(Slice.HINT_LIST)) {
-            addList(slice, items);
-        } else {
-            Arrays.asList(slice.getItems()).forEach(item -> {
-                if (item.hasHint(Slice.HINT_ACTIONS)) {
-                    return;
-                } else if (item.getType() == SliceItem.TYPE_COLOR) {
-                    return;
-                } else if (item.getType() == SliceItem.TYPE_SLICE
-                        && item.hasHint(Slice.HINT_LIST)) {
-                    addList(item.getSlice(), items);
-                } else if (item.hasHint(Slice.HINT_LIST_ITEM)) {
-                    items.add(item);
-                } else if (!hasHeader[0]) {
-                    hasHeader[0] = true;
-                    items.add(0, item);
-                } else {
-                    item.addHint(Slice.HINT_LIST_ITEM);
-                    items.add(item);
-                }
-            });
-        }
-        mAdapter.setSliceItems(items, color);
-    }
-
-    private void addList(Slice slice, List<SliceItem> items) {
-        List<SliceItem> sliceItems = Arrays.asList(slice.getItems());
-        sliceItems.forEach(i -> i.addHint(Slice.HINT_LIST_ITEM));
-        items.addAll(sliceItems);
-    }
-}
diff --git a/core/java/android/slice/views/MessageView.java b/core/java/android/slice/views/MessageView.java
deleted file mode 100644
index 7b03e0b..0000000
--- a/core/java/android/slice/views/MessageView.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.slice.views;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.slice.Slice;
-import android.slice.SliceItem;
-import android.slice.SliceQuery;
-import android.slice.views.LargeSliceAdapter.SliceListView;
-import android.text.SpannableStringBuilder;
-import android.util.AttributeSet;
-import android.util.TypedValue;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-/**
- * @hide
- */
-public class MessageView extends LinearLayout implements SliceListView {
-
-    private TextView mDetails;
-    private ImageView mIcon;
-
-    public MessageView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mDetails = findViewById(android.R.id.summary);
-        mIcon = findViewById(android.R.id.icon);
-    }
-
-    @Override
-    public void setSliceItem(SliceItem slice) {
-        SliceItem source = SliceQuery.find(slice, SliceItem.TYPE_IMAGE, Slice.HINT_SOURCE, null);
-        if (source != null) {
-            final int iconSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-                    24, getContext().getResources().getDisplayMetrics());
-            // TODO try and turn this into a drawable
-            Bitmap iconBm = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
-            Canvas iconCanvas = new Canvas(iconBm);
-            Drawable d = source.getIcon().loadDrawable(getContext());
-            d.setBounds(0, 0, iconSize, iconSize);
-            d.draw(iconCanvas);
-            mIcon.setImageBitmap(SliceViewUtil.getCircularBitmap(iconBm));
-        }
-        SpannableStringBuilder builder = new SpannableStringBuilder();
-        SliceQuery.findAll(slice, SliceItem.TYPE_TEXT).forEach(text -> {
-            if (builder.length() != 0) {
-                builder.append('\n');
-            }
-            builder.append(text.getText());
-        });
-        mDetails.setText(builder.toString());
-    }
-
-}
diff --git a/core/java/android/slice/views/RemoteInputView.java b/core/java/android/slice/views/RemoteInputView.java
deleted file mode 100644
index a29bb5c..0000000
--- a/core/java/android/slice/views/RemoteInputView.java
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.slice.views;
-
-import android.animation.Animator;
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.RemoteInput;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ShortcutManager;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewAnimationUtils;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.inputmethod.CompletionInfo;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.ImageButton;
-import android.widget.LinearLayout;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.android.internal.R;
-
-/**
- * Host for the remote input.
- *
- * @hide
- */
-// TODO this should be unified with SystemUI RemoteInputView (b/67527720)
-public class RemoteInputView extends LinearLayout implements View.OnClickListener, TextWatcher {
-
-    private static final String TAG = "RemoteInput";
-
-    /**
-     * A marker object that let's us easily find views of this class.
-     */
-    public static final Object VIEW_TAG = new Object();
-
-    private RemoteEditText mEditText;
-    private ImageButton mSendButton;
-    private ProgressBar mProgressBar;
-    private PendingIntent mPendingIntent;
-    private RemoteInput[] mRemoteInputs;
-    private RemoteInput mRemoteInput;
-
-    private int mRevealCx;
-    private int mRevealCy;
-    private int mRevealR;
-    private boolean mResetting;
-
-    public RemoteInputView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        mProgressBar = findViewById(R.id.remote_input_progress);
-        mSendButton = findViewById(R.id.remote_input_send);
-        mSendButton.setOnClickListener(this);
-
-        mEditText = (RemoteEditText) getChildAt(0);
-        mEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
-            @Override
-            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
-                final boolean isSoftImeEvent = event == null
-                        && (actionId == EditorInfo.IME_ACTION_DONE
-                                || actionId == EditorInfo.IME_ACTION_NEXT
-                                || actionId == EditorInfo.IME_ACTION_SEND);
-                final boolean isKeyboardEnterKey = event != null
-                        && KeyEvent.isConfirmKey(event.getKeyCode())
-                        && event.getAction() == KeyEvent.ACTION_DOWN;
-
-                if (isSoftImeEvent || isKeyboardEnterKey) {
-                    if (mEditText.length() > 0) {
-                        sendRemoteInput();
-                    }
-                    // Consume action to prevent IME from closing.
-                    return true;
-                }
-                return false;
-            }
-        });
-        mEditText.addTextChangedListener(this);
-        mEditText.setInnerFocusable(false);
-        mEditText.mRemoteInputView = this;
-    }
-
-    private void sendRemoteInput() {
-        Bundle results = new Bundle();
-        results.putString(mRemoteInput.getResultKey(), mEditText.getText().toString());
-        Intent fillInIntent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-        RemoteInput.addResultsToIntent(mRemoteInputs, fillInIntent,
-                results);
-
-        mEditText.setEnabled(false);
-        mSendButton.setVisibility(INVISIBLE);
-        mProgressBar.setVisibility(VISIBLE);
-        mEditText.mShowImeOnInputConnection = false;
-
-        // Tell ShortcutManager that this package has been "activated".  ShortcutManager
-        // will reset the throttling for this package.
-        // Strictly speaking, the intent receiver may be different from the intent creator,
-        // but that's an edge case, and also because we can't always know which package will receive
-        // an intent, so we just reset for the creator.
-        getContext().getSystemService(ShortcutManager.class).onApplicationActive(
-                mPendingIntent.getCreatorPackage(),
-                getContext().getUserId());
-
-        try {
-            mPendingIntent.send(mContext, 0, fillInIntent);
-            reset();
-        } catch (PendingIntent.CanceledException e) {
-            Log.i(TAG, "Unable to send remote input result", e);
-            Toast.makeText(mContext, "Failure sending pending intent for inline reply :(",
-                    Toast.LENGTH_SHORT).show();
-            reset();
-        }
-    }
-
-    /**
-     * Creates a remote input view.
-     */
-    public static RemoteInputView inflate(Context context, ViewGroup root) {
-        RemoteInputView v = (RemoteInputView) LayoutInflater.from(context).inflate(
-                R.layout.slice_remote_input, root, false);
-        v.setTag(VIEW_TAG);
-        return v;
-    }
-
-    @Override
-    public void onClick(View v) {
-        if (v == mSendButton) {
-            sendRemoteInput();
-        }
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        super.onTouchEvent(event);
-
-        // We never want for a touch to escape to an outer view or one we covered.
-        return true;
-    }
-
-    private void onDefocus() {
-        setVisibility(INVISIBLE);
-    }
-
-    /**
-     * Set the pending intent for remote input.
-     */
-    public void setPendingIntent(PendingIntent pendingIntent) {
-        mPendingIntent = pendingIntent;
-    }
-
-    /**
-     * Set the remote inputs for this view.
-     */
-    public void setRemoteInput(RemoteInput[] remoteInputs, RemoteInput remoteInput) {
-        mRemoteInputs = remoteInputs;
-        mRemoteInput = remoteInput;
-        mEditText.setHint(mRemoteInput.getLabel());
-    }
-
-    /**
-     * Focuses the remote input view.
-     */
-    public void focusAnimated() {
-        if (getVisibility() != VISIBLE) {
-            Animator animator = ViewAnimationUtils.createCircularReveal(
-                    this, mRevealCx, mRevealCy, 0, mRevealR);
-            animator.setDuration(200);
-            animator.start();
-        }
-        focus();
-    }
-
-    private void focus() {
-        setVisibility(VISIBLE);
-        mEditText.setInnerFocusable(true);
-        mEditText.mShowImeOnInputConnection = true;
-        mEditText.setSelection(mEditText.getText().length());
-        mEditText.requestFocus();
-        updateSendButton();
-    }
-
-    private void reset() {
-        mResetting = true;
-
-        mEditText.getText().clear();
-        mEditText.setEnabled(true);
-        mSendButton.setVisibility(VISIBLE);
-        mProgressBar.setVisibility(INVISIBLE);
-        updateSendButton();
-        onDefocus();
-
-        mResetting = false;
-    }
-
-    @Override
-    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
-        if (mResetting && child == mEditText) {
-            // Suppress text events if it happens during resetting. Ideally this would be
-            // suppressed by the text view not being shown, but that doesn't work here because it
-            // needs to stay visible for the animation.
-            return false;
-        }
-        return super.onRequestSendAccessibilityEvent(child, event);
-    }
-
-    private void updateSendButton() {
-        mSendButton.setEnabled(mEditText.getText().length() != 0);
-    }
-
-    @Override
-    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-    }
-
-    @Override
-    public void onTextChanged(CharSequence s, int start, int before, int count) {
-    }
-
-    @Override
-    public void afterTextChanged(Editable s) {
-        updateSendButton();
-    }
-
-    /**
-     * Tries to find an action that matches the current pending intent of this view and updates its
-     * state to that of the found action
-     *
-     * @return true if a matching action was found, false otherwise
-     */
-    public boolean updatePendingIntentFromActions(Notification.Action[] actions) {
-        if (mPendingIntent == null || actions == null) {
-            return false;
-        }
-        Intent current = mPendingIntent.getIntent();
-        if (current == null) {
-            return false;
-        }
-
-        for (Notification.Action a : actions) {
-            RemoteInput[] inputs = a.getRemoteInputs();
-            if (a.actionIntent == null || inputs == null) {
-                continue;
-            }
-            Intent candidate = a.actionIntent.getIntent();
-            if (!current.filterEquals(candidate)) {
-                continue;
-            }
-
-            RemoteInput input = null;
-            for (RemoteInput i : inputs) {
-                if (i.getAllowFreeFormInput()) {
-                    input = i;
-                }
-            }
-            if (input == null) {
-                continue;
-            }
-            setPendingIntent(a.actionIntent);
-            setRemoteInput(inputs, input);
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * @hide
-     */
-    public void setRevealParameters(int cx, int cy, int r) {
-        mRevealCx = cx;
-        mRevealCy = cy;
-        mRevealR = r;
-    }
-
-    @Override
-    public void dispatchStartTemporaryDetach() {
-        super.dispatchStartTemporaryDetach();
-        // Detach the EditText temporarily such that it doesn't get onDetachedFromWindow and
-        // won't lose IME focus.
-        detachViewFromParent(mEditText);
-    }
-
-    @Override
-    public void dispatchFinishTemporaryDetach() {
-        if (isAttachedToWindow()) {
-            attachViewToParent(mEditText, 0, mEditText.getLayoutParams());
-        } else {
-            removeDetachedView(mEditText, false /* animate */);
-        }
-        super.dispatchFinishTemporaryDetach();
-    }
-
-    /**
-     * An EditText that changes appearance based on whether it's focusable and becomes un-focusable
-     * whenever the user navigates away from it or it becomes invisible.
-     */
-    public static class RemoteEditText extends EditText {
-
-        private final Drawable mBackground;
-        private RemoteInputView mRemoteInputView;
-        boolean mShowImeOnInputConnection;
-
-        public RemoteEditText(Context context, AttributeSet attrs) {
-            super(context, attrs);
-            mBackground = getBackground();
-        }
-
-        private void defocusIfNeeded(boolean animate) {
-            if (mRemoteInputView != null || isTemporarilyDetached()) {
-                if (isTemporarilyDetached()) {
-                    // We might get reattached but then the other one of HUN / expanded might steal
-                    // our focus, so we'll need to save our text here.
-                }
-                return;
-            }
-            if (isFocusable() && isEnabled()) {
-                setInnerFocusable(false);
-                if (mRemoteInputView != null) {
-                    mRemoteInputView.onDefocus();
-                }
-                mShowImeOnInputConnection = false;
-            }
-        }
-
-        @Override
-        protected void onVisibilityChanged(View changedView, int visibility) {
-            super.onVisibilityChanged(changedView, visibility);
-
-            if (!isShown()) {
-                defocusIfNeeded(false /* animate */);
-            }
-        }
-
-        @Override
-        protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
-            super.onFocusChanged(focused, direction, previouslyFocusedRect);
-            if (!focused) {
-                defocusIfNeeded(true /* animate */);
-            }
-        }
-
-        @Override
-        public void getFocusedRect(Rect r) {
-            super.getFocusedRect(r);
-            r.top = mScrollY;
-            r.bottom = mScrollY + (mBottom - mTop);
-        }
-
-        @Override
-        public boolean onKeyDown(int keyCode, KeyEvent event) {
-            if (keyCode == KeyEvent.KEYCODE_BACK) {
-                // Eat the DOWN event here to prevent any default behavior.
-                return true;
-            }
-            return super.onKeyDown(keyCode, event);
-        }
-
-        @Override
-        public boolean onKeyUp(int keyCode, KeyEvent event) {
-            if (keyCode == KeyEvent.KEYCODE_BACK) {
-                defocusIfNeeded(true /* animate */);
-                return true;
-            }
-            return super.onKeyUp(keyCode, event);
-        }
-
-        @Override
-        public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
-            final InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
-
-            if (mShowImeOnInputConnection && inputConnection != null) {
-                final InputMethodManager imm = InputMethodManager.getInstance();
-                if (imm != null) {
-                    // onCreateInputConnection is called by InputMethodManager in the middle of
-                    // setting up the connection to the IME; wait with requesting the IME until that
-                    // work has completed.
-                    post(new Runnable() {
-                        @Override
-                        public void run() {
-                            imm.viewClicked(RemoteEditText.this);
-                            imm.showSoftInput(RemoteEditText.this, 0);
-                        }
-                    });
-                }
-            }
-
-            return inputConnection;
-        }
-
-        @Override
-        public void onCommitCompletion(CompletionInfo text) {
-            clearComposingText();
-            setText(text.getText());
-            setSelection(getText().length());
-        }
-
-        void setInnerFocusable(boolean focusable) {
-            setFocusableInTouchMode(focusable);
-            setFocusable(focusable);
-            setCursorVisible(focusable);
-
-            if (focusable) {
-                requestFocus();
-                setBackground(mBackground);
-            } else {
-                setBackground(null);
-            }
-
-        }
-    }
-}
diff --git a/core/java/android/slice/views/ShortcutView.java b/core/java/android/slice/views/ShortcutView.java
deleted file mode 100644
index 8fe2f1a..0000000
--- a/core/java/android/slice/views/ShortcutView.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.slice.views;
-
-import android.app.PendingIntent;
-import android.app.PendingIntent.CanceledException;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Color;
-import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.OvalShape;
-import android.net.Uri;
-import android.slice.Slice;
-import android.slice.SliceItem;
-import android.slice.SliceQuery;
-import android.slice.views.SliceView.SliceModeView;
-import android.view.ViewGroup;
-
-import com.android.internal.R;
-
-/**
- * @hide
- */
-public class ShortcutView extends SliceModeView {
-
-    private static final String TAG = "ShortcutView";
-
-    private PendingIntent mAction;
-    private Uri mUri;
-    private int mLargeIconSize;
-    private int mSmallIconSize;
-
-    public ShortcutView(Context context) {
-        super(context);
-        mLargeIconSize = getContext().getResources()
-                .getDimensionPixelSize(R.dimen.slice_shortcut_size);
-        mSmallIconSize = getContext().getResources().getDimensionPixelSize(R.dimen.slice_icon_size);
-        setLayoutParams(new ViewGroup.LayoutParams(mLargeIconSize, mLargeIconSize));
-    }
-
-    @Override
-    public void setSlice(Slice slice) {
-        removeAllViews();
-        SliceItem sliceItem = SliceQuery.find(slice, SliceItem.TYPE_ACTION);
-        SliceItem iconItem = slice.getPrimaryIcon();
-        SliceItem textItem = sliceItem != null
-                ? SliceQuery.find(sliceItem, SliceItem.TYPE_TEXT)
-                : SliceQuery.find(slice, SliceItem.TYPE_TEXT);
-        SliceItem colorItem = sliceItem != null
-                ? SliceQuery.find(sliceItem, SliceItem.TYPE_COLOR)
-                : SliceQuery.find(slice, SliceItem.TYPE_COLOR);
-        if (colorItem == null) {
-            colorItem = SliceQuery.find(slice, SliceItem.TYPE_COLOR);
-        }
-        // TODO: pick better default colour
-        final int color = colorItem != null ? colorItem.getColor() : Color.GRAY;
-        ShapeDrawable circle = new ShapeDrawable(new OvalShape());
-        circle.setTint(color);
-        setBackground(circle);
-        if (iconItem != null) {
-            final boolean isLarge = iconItem.hasHint(Slice.HINT_LARGE);
-            final int iconSize = isLarge ? mLargeIconSize : mSmallIconSize;
-            SliceViewUtil.createCircledIcon(getContext(), color, iconSize, iconItem.getIcon(),
-                    isLarge, this /* parent */);
-            mAction = sliceItem != null ? sliceItem.getAction()
-                    : null;
-            mUri = slice.getUri();
-            setClickable(true);
-        } else {
-            setClickable(false);
-        }
-    }
-
-    @Override
-    public String getMode() {
-        return SliceView.MODE_SHORTCUT;
-    }
-
-    @Override
-    public boolean performClick() {
-        if (!callOnClick()) {
-            try {
-                if (mAction != null) {
-                    mAction.send();
-                } else {
-                    Intent intent = new Intent(Intent.ACTION_VIEW).setData(mUri);
-                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    getContext().startActivity(intent);
-                }
-            } catch (CanceledException e) {
-                e.printStackTrace();
-            }
-        }
-        return true;
-    }
-}
diff --git a/core/java/android/slice/views/SliceView.java b/core/java/android/slice/views/SliceView.java
deleted file mode 100644
index f379248..0000000
--- a/core/java/android/slice/views/SliceView.java
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.slice.views;
-
-import android.annotation.StringDef;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.drawable.ColorDrawable;
-import android.net.Uri;
-import android.slice.Slice;
-import android.slice.SliceItem;
-import android.slice.SliceQuery;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-
-/**
- * A view that can display a {@link Slice} in different {@link SliceMode}'s.
- *
- * @hide
- */
-public class SliceView extends LinearLayout {
-
-    private static final String TAG = "SliceView";
-
-    /**
-     * @hide
-     */
-    public abstract static class SliceModeView extends FrameLayout {
-
-        public SliceModeView(Context context) {
-            super(context);
-        }
-
-        /**
-         * @return the {@link SliceMode} of the slice being presented.
-         */
-        public abstract String getMode();
-
-        /**
-         * @param slice the slice to show in this view.
-         */
-        public abstract void setSlice(Slice slice);
-    }
-
-    /**
-     * @hide
-     */
-    @StringDef({
-            MODE_SMALL, MODE_LARGE, MODE_SHORTCUT
-    })
-    public @interface SliceMode {}
-
-    /**
-     * Mode indicating this slice should be presented in small template format.
-     */
-    public static final String MODE_SMALL       = "SLICE_SMALL";
-    /**
-     * Mode indicating this slice should be presented in large template format.
-     */
-    public static final String MODE_LARGE       = "SLICE_LARGE";
-    /**
-     * Mode indicating this slice should be presented as an icon.
-     */
-    public static final String MODE_SHORTCUT    = "SLICE_ICON";
-
-    /**
-     * Will select the type of slice binding based on size of the View. TODO: Put in some info about
-     * that selection.
-     */
-    private static final String MODE_AUTO = "auto";
-
-    private String mMode = MODE_AUTO;
-    private SliceModeView mCurrentView;
-    private final ActionRow mActions;
-    private Slice mCurrentSlice;
-    private boolean mShowActions = true;
-
-    /**
-     * Simple constructor to create a slice view from code.
-     *
-     * @param context The context the view is running in.
-     */
-    public SliceView(Context context) {
-        super(context);
-        setOrientation(LinearLayout.VERTICAL);
-        mActions = new ActionRow(mContext, true);
-        mActions.setBackground(new ColorDrawable(0xffeeeeee));
-        mCurrentView = new LargeTemplateView(mContext);
-        addView(mCurrentView);
-        addView(mActions);
-    }
-
-    /**
-     * @hide
-     */
-    public void bindSlice(Intent intent) {
-        // TODO
-    }
-
-    /**
-     * Binds this view to the {@link Slice} associated with the provided {@link Uri}.
-     */
-    public void bindSlice(Uri sliceUri) {
-        validate(sliceUri);
-        Slice s = mContext.getContentResolver().bindSlice(sliceUri);
-        bindSlice(s);
-    }
-
-    /**
-     * Binds this view to the provided {@link Slice}.
-     */
-    public void bindSlice(Slice slice) {
-        mCurrentSlice = slice;
-        if (mCurrentSlice != null) {
-            reinflate();
-        }
-    }
-
-    /**
-     * Call to clean up the view.
-     */
-    public void unbindSlice() {
-        mCurrentSlice = null;
-    }
-
-    /**
-     * Set the {@link SliceMode} this view should present in.
-     */
-    public void setMode(@SliceMode String mode) {
-        setMode(mode, false /* animate */);
-    }
-
-    /**
-     * @hide
-     */
-    public void setMode(@SliceMode String mode, boolean animate) {
-        if (animate) {
-            Log.e(TAG, "Animation not supported yet");
-        }
-        mMode = mode;
-        reinflate();
-    }
-
-    /**
-     * @return the {@link SliceMode} this view is presenting in.
-     */
-    public @SliceMode String getMode() {
-        if (mMode.equals(MODE_AUTO)) {
-            return MODE_LARGE;
-        }
-        return mMode;
-    }
-
-    /**
-     * @hide
-     *
-     * Whether this view should show a row of actions with it.
-     */
-    public void setShowActionRow(boolean show) {
-        mShowActions = show;
-        reinflate();
-    }
-
-    private SliceModeView createView(String mode) {
-        switch (mode) {
-            case MODE_SHORTCUT:
-                return new ShortcutView(getContext());
-            case MODE_SMALL:
-                return new SmallTemplateView(getContext());
-        }
-        return new LargeTemplateView(getContext());
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        unbindSlice();
-    }
-
-    private void reinflate() {
-        if (mCurrentSlice == null) {
-            return;
-        }
-        // TODO: Smarter mapping here from one state to the next.
-        SliceItem color = SliceQuery.find(mCurrentSlice, SliceItem.TYPE_COLOR);
-        SliceItem[] items = mCurrentSlice.getItems();
-        SliceItem actionRow = SliceQuery.find(mCurrentSlice, SliceItem.TYPE_SLICE,
-                Slice.HINT_ACTIONS,
-                Slice.HINT_ALT);
-        String mode = getMode();
-        if (!mode.equals(mCurrentView.getMode())) {
-            removeAllViews();
-            mCurrentView = createView(mode);
-            addView(mCurrentView);
-            addView(mActions);
-        }
-        if (items.length > 1 || (items.length != 0 && items[0] != actionRow)) {
-            mCurrentView.setVisibility(View.VISIBLE);
-            mCurrentView.setSlice(mCurrentSlice);
-        } else {
-            mCurrentView.setVisibility(View.GONE);
-        }
-
-        boolean showActions = mShowActions && actionRow != null
-                && !mode.equals(MODE_SHORTCUT);
-        if (showActions) {
-            mActions.setActions(actionRow, color);
-            mActions.setVisibility(View.VISIBLE);
-        } else {
-            mActions.setVisibility(View.GONE);
-        }
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        // TODO -- may need to rethink for AGSA
-        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
-            requestDisallowInterceptTouchEvent(true);
-        }
-        return super.onInterceptTouchEvent(ev);
-    }
-
-    private static void validate(Uri sliceUri) {
-        if (!ContentResolver.SCHEME_SLICE.equals(sliceUri.getScheme())) {
-            throw new RuntimeException("Invalid uri " + sliceUri);
-        }
-        if (sliceUri.getPathSegments().size() == 0) {
-            throw new RuntimeException("Invalid uri " + sliceUri);
-        }
-    }
-}
diff --git a/core/java/android/slice/views/SliceViewUtil.java b/core/java/android/slice/views/SliceViewUtil.java
deleted file mode 100644
index 1b5a6d1..0000000
--- a/core/java/android/slice/views/SliceViewUtil.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.slice.views;
-
-import android.annotation.ColorInt;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-import android.view.Gravity;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-
-/**
- * A bunch of utilities for slice UI.
- *
- * @hide
- */
-public class SliceViewUtil {
-
-    /**
-     * @hide
-     */
-    @ColorInt
-    public static int getColorAccent(Context context) {
-        return getColorAttr(context, android.R.attr.colorAccent);
-    }
-
-    /**
-     * @hide
-     */
-    @ColorInt
-    public static int getColorError(Context context) {
-        return getColorAttr(context, android.R.attr.colorError);
-    }
-
-    /**
-     * @hide
-     */
-    @ColorInt
-    public static int getDefaultColor(Context context, int resId) {
-        final ColorStateList list = context.getResources().getColorStateList(resId,
-                context.getTheme());
-
-        return list.getDefaultColor();
-    }
-
-    /**
-     * @hide
-     */
-    @ColorInt
-    public static int getDisabled(Context context, int inputColor) {
-        return applyAlphaAttr(context, android.R.attr.disabledAlpha, inputColor);
-    }
-
-    /**
-     * @hide
-     */
-    @ColorInt
-    public static int applyAlphaAttr(Context context, int attr, int inputColor) {
-        TypedArray ta = context.obtainStyledAttributes(new int[] {
-                attr
-        });
-        float alpha = ta.getFloat(0, 0);
-        ta.recycle();
-        return applyAlpha(alpha, inputColor);
-    }
-
-    /**
-     * @hide
-     */
-    @ColorInt
-    public static int applyAlpha(float alpha, int inputColor) {
-        alpha *= Color.alpha(inputColor);
-        return Color.argb((int) (alpha), Color.red(inputColor), Color.green(inputColor),
-                Color.blue(inputColor));
-    }
-
-    /**
-     * @hide
-     */
-    @ColorInt
-    public static int getColorAttr(Context context, int attr) {
-        TypedArray ta = context.obtainStyledAttributes(new int[] {
-                attr
-        });
-        @ColorInt
-        int colorAccent = ta.getColor(0, 0);
-        ta.recycle();
-        return colorAccent;
-    }
-
-    /**
-     * @hide
-     */
-    public static int getThemeAttr(Context context, int attr) {
-        TypedArray ta = context.obtainStyledAttributes(new int[] {
-                attr
-        });
-        int theme = ta.getResourceId(0, 0);
-        ta.recycle();
-        return theme;
-    }
-
-    /**
-     * @hide
-     */
-    public static Drawable getDrawable(Context context, int attr) {
-        TypedArray ta = context.obtainStyledAttributes(new int[] {
-                attr
-        });
-        Drawable drawable = ta.getDrawable(0);
-        ta.recycle();
-        return drawable;
-    }
-
-    /**
-     * @hide
-     */
-    public static void createCircledIcon(Context context, int color, int iconSize, Icon icon,
-            boolean isLarge, ViewGroup parent) {
-        ImageView v = new ImageView(context);
-        v.setImageIcon(icon);
-        parent.addView(v);
-        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) v.getLayoutParams();
-        if (isLarge) {
-            // XXX better way to convert from icon -> bitmap or crop an icon (?)
-            Bitmap iconBm = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
-            Canvas iconCanvas = new Canvas(iconBm);
-            v.layout(0, 0, iconSize, iconSize);
-            v.draw(iconCanvas);
-            v.setImageBitmap(getCircularBitmap(iconBm));
-        } else {
-            v.setColorFilter(Color.WHITE);
-        }
-        lp.width = iconSize;
-        lp.height = iconSize;
-        lp.gravity = Gravity.CENTER;
-    }
-
-    /**
-     * @hide
-     */
-    public static Bitmap getCircularBitmap(Bitmap bitmap) {
-        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
-                bitmap.getHeight(), Config.ARGB_8888);
-        Canvas canvas = new Canvas(output);
-        final Paint paint = new Paint();
-        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
-        paint.setAntiAlias(true);
-        canvas.drawARGB(0, 0, 0, 0);
-        canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2,
-                bitmap.getWidth() / 2, paint);
-        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
-        canvas.drawBitmap(bitmap, rect, rect, paint);
-        return output;
-    }
-}
diff --git a/core/java/android/slice/views/SmallTemplateView.java b/core/java/android/slice/views/SmallTemplateView.java
deleted file mode 100644
index b0b181e..0000000
--- a/core/java/android/slice/views/SmallTemplateView.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.slice.views;
-
-import android.app.PendingIntent.CanceledException;
-import android.content.Context;
-import android.os.AsyncTask;
-import android.slice.Slice;
-import android.slice.SliceItem;
-import android.slice.SliceQuery;
-import android.slice.views.LargeSliceAdapter.SliceListView;
-import android.slice.views.SliceView.SliceModeView;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.android.internal.R;
-
-import java.text.Format;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
-
-/**
- * Small template is also used to construct list items for use with {@link LargeTemplateView}.
- *
- * @hide
- */
-public class SmallTemplateView extends SliceModeView implements SliceListView {
-
-    private static final String TAG = "SmallTemplateView";
-
-    private int mIconSize;
-    private int mPadding;
-
-    private LinearLayout mStartContainer;
-    private TextView mTitleText;
-    private TextView mSecondaryText;
-    private LinearLayout mEndContainer;
-
-    public SmallTemplateView(Context context) {
-        super(context);
-        inflate(context, R.layout.slice_small_template, this);
-        mIconSize = getContext().getResources().getDimensionPixelSize(R.dimen.slice_icon_size);
-        mPadding = getContext().getResources().getDimensionPixelSize(R.dimen.slice_padding);
-
-        mStartContainer = (LinearLayout) findViewById(android.R.id.icon_frame);
-        mTitleText = (TextView) findViewById(android.R.id.title);
-        mSecondaryText = (TextView) findViewById(android.R.id.summary);
-        mEndContainer = (LinearLayout) findViewById(android.R.id.widget_frame);
-    }
-
-    @Override
-    public String getMode() {
-        return SliceView.MODE_SMALL;
-    }
-
-    @Override
-    public void setSliceItem(SliceItem slice) {
-        resetViews();
-        SliceItem colorItem = SliceQuery.find(slice, SliceItem.TYPE_COLOR);
-        int color = colorItem != null ? colorItem.getColor() : -1;
-
-        // Look for any title elements
-        List<SliceItem> titleItems = SliceQuery.findAll(slice, -1, Slice.HINT_TITLE,
-                null);
-        boolean hasTitleText = false;
-        boolean hasTitleItem = false;
-        for (int i = 0; i < titleItems.size(); i++) {
-            SliceItem item = titleItems.get(i);
-            if (!hasTitleItem) {
-                // icon, action icon, or timestamp
-                if (item.getType() == SliceItem.TYPE_ACTION) {
-                    hasTitleItem = addIcon(item, color, mStartContainer);
-                } else if (item.getType() == SliceItem.TYPE_IMAGE) {
-                    addIcon(item, color, mStartContainer);
-                    hasTitleItem = true;
-                } else if (item.getType() == SliceItem.TYPE_TIMESTAMP) {
-                    TextView tv = new TextView(getContext());
-                    tv.setText(convertTimeToString(item.getTimestamp()));
-                    hasTitleItem = true;
-                }
-            }
-            if (!hasTitleText && item.getType() == SliceItem.TYPE_TEXT) {
-                mTitleText.setText(item.getText());
-                hasTitleText = true;
-            }
-            if (hasTitleText && hasTitleItem) {
-                break;
-            }
-        }
-        mTitleText.setVisibility(hasTitleText ? View.VISIBLE : View.GONE);
-        mStartContainer.setVisibility(hasTitleItem ? View.VISIBLE : View.GONE);
-
-        if (slice.getType() != SliceItem.TYPE_SLICE) {
-            return;
-        }
-
-        // Deal with remaining items
-        int itemCount = 0;
-        boolean hasSummary = false;
-        ArrayList<SliceItem> sliceItems = new ArrayList<SliceItem>(
-                Arrays.asList(slice.getSlice().getItems()));
-        for (int i = 0; i < sliceItems.size(); i++) {
-            SliceItem item = sliceItems.get(i);
-            if (!hasSummary && item.getType() == SliceItem.TYPE_TEXT
-                    && !item.hasHint(Slice.HINT_TITLE)) {
-                // TODO -- Should combine all text items?
-                mSecondaryText.setText(item.getText());
-                hasSummary = true;
-            }
-            if (itemCount <= 3) {
-                if (item.getType() == SliceItem.TYPE_ACTION) {
-                    if (addIcon(item, color, mEndContainer)) {
-                        itemCount++;
-                    }
-                } else if (item.getType() == SliceItem.TYPE_IMAGE) {
-                    addIcon(item, color, mEndContainer);
-                    itemCount++;
-                } else if (item.getType() == SliceItem.TYPE_TIMESTAMP) {
-                    TextView tv = new TextView(getContext());
-                    tv.setText(convertTimeToString(item.getTimestamp()));
-                    mEndContainer.addView(tv);
-                    itemCount++;
-                } else if (item.getType() == SliceItem.TYPE_SLICE) {
-                    SliceItem[] subItems = item.getSlice().getItems();
-                    for (int j = 0; j < subItems.length; j++) {
-                        sliceItems.add(subItems[j]);
-                    }
-                }
-            }
-        }
-    }
-
-    @Override
-    public void setSlice(Slice slice) {
-        setSliceItem(new SliceItem(slice, SliceItem.TYPE_SLICE, slice.getHints()));
-    }
-
-    /**
-     * @return Whether an icon was added.
-     */
-    private boolean addIcon(SliceItem sliceItem, int color, LinearLayout container) {
-        SliceItem image = null;
-        SliceItem action = null;
-        if (sliceItem.getType() == SliceItem.TYPE_ACTION) {
-            image = SliceQuery.find(sliceItem.getSlice(), SliceItem.TYPE_IMAGE);
-            action = sliceItem;
-        } else if (sliceItem.getType() == SliceItem.TYPE_IMAGE) {
-            image = sliceItem;
-        }
-        if (image != null) {
-            ImageView iv = new ImageView(getContext());
-            iv.setImageIcon(image.getIcon());
-            if (action != null) {
-                final SliceItem sliceAction = action;
-                iv.setOnClickListener(v -> AsyncTask.execute(
-                        () -> {
-                            try {
-                                sliceAction.getAction().send();
-                            } catch (CanceledException e) {
-                                e.printStackTrace();
-                            }
-                        }));
-                iv.setBackground(SliceViewUtil.getDrawable(getContext(),
-                        android.R.attr.selectableItemBackground));
-            }
-            if (color != -1 && !sliceItem.hasHint(Slice.HINT_NO_TINT)) {
-                iv.setColorFilter(color);
-            }
-            container.addView(iv);
-            LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) iv.getLayoutParams();
-            lp.width = mIconSize;
-            lp.height = mIconSize;
-            lp.setMarginStart(mPadding);
-            return true;
-        }
-        return false;
-    }
-
-    private String convertTimeToString(long time) {
-        // TODO -- figure out what format(s) we support
-        Date date = new Date(time);
-        Format format = new SimpleDateFormat("MM dd yyyy HH:mm:ss");
-        return format.format(date);
-    }
-
-    private void resetViews() {
-        mStartContainer.removeAllViews();
-        mEndContainer.removeAllViews();
-        mTitleText.setText(null);
-        mSecondaryText.setText(null);
-    }
-}
diff --git a/core/java/android/text/AndroidBidi.java b/core/java/android/text/AndroidBidi.java
index bbe1523..179d545 100644
--- a/core/java/android/text/AndroidBidi.java
+++ b/core/java/android/text/AndroidBidi.java
@@ -16,6 +16,11 @@
 
 package android.text;
 
+import android.icu.lang.UCharacter;
+import android.icu.lang.UCharacterDirection;
+import android.icu.lang.UProperty;
+import android.icu.text.Bidi;
+import android.icu.text.BidiClassifier;
 import android.text.Layout.Directions;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -27,26 +32,57 @@
 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
 public class AndroidBidi {
 
-    public static int bidi(int dir, char[] chs, byte[] chInfo, int n, boolean haveInfo) {
+    private static class EmojiBidiOverride extends BidiClassifier {
+        EmojiBidiOverride() {
+            super(null /* No persisting object needed */);
+        }
+
+        // Tells ICU to use the standard Unicode value.
+        private static final int NO_OVERRIDE =
+                UCharacter.getIntPropertyMaxValue(UProperty.BIDI_CLASS) + 1;
+
+        @Override
+        public int classify(int c) {
+            if (Emoji.isNewEmoji(c)) {
+                // All new emoji characters in Unicode 10.0 are of the bidi class ON.
+                return UCharacterDirection.OTHER_NEUTRAL;
+            } else {
+                return NO_OVERRIDE;
+            }
+        }
+    }
+
+    private static final EmojiBidiOverride sEmojiBidiOverride = new EmojiBidiOverride();
+
+    /**
+     * Runs the bidi algorithm on input text.
+     */
+    public static int bidi(int dir, char[] chs, byte[] chInfo) {
         if (chs == null || chInfo == null) {
             throw new NullPointerException();
         }
 
-        if (n < 0 || chs.length < n || chInfo.length < n) {
+        final int length = chs.length;
+        if (chInfo.length < length) {
             throw new IndexOutOfBoundsException();
         }
 
-        switch(dir) {
-            case Layout.DIR_REQUEST_LTR: dir = 0; break;
-            case Layout.DIR_REQUEST_RTL: dir = 1; break;
-            case Layout.DIR_REQUEST_DEFAULT_LTR: dir = -2; break;
-            case Layout.DIR_REQUEST_DEFAULT_RTL: dir = -1; break;
-            default: dir = 0; break;
+        final byte paraLevel;
+        switch (dir) {
+            case Layout.DIR_REQUEST_LTR: paraLevel = Bidi.LTR; break;
+            case Layout.DIR_REQUEST_RTL: paraLevel = Bidi.RTL; break;
+            case Layout.DIR_REQUEST_DEFAULT_LTR: paraLevel = Bidi.LEVEL_DEFAULT_LTR; break;
+            case Layout.DIR_REQUEST_DEFAULT_RTL: paraLevel = Bidi.LEVEL_DEFAULT_RTL; break;
+            default: paraLevel = Bidi.LTR; break;
         }
-
-        int result = runBidi(dir, chs, chInfo, n, haveInfo);
-        result = (result & 0x1) == 0 ? Layout.DIR_LEFT_TO_RIGHT : Layout.DIR_RIGHT_TO_LEFT;
-        return result;
+        final Bidi icuBidi = new Bidi(length /* maxLength */, 0 /* maxRunCount */);
+        icuBidi.setCustomClassifier(sEmojiBidiOverride);
+        icuBidi.setPara(chs, paraLevel, null /* embeddingLevels */);
+        for (int i = 0; i < length; i++) {
+            chInfo[i] = icuBidi.getLevelAt(i);
+        }
+        final byte result = icuBidi.getParaLevel();
+        return (result & 0x1) == 0 ? Layout.DIR_LEFT_TO_RIGHT : Layout.DIR_RIGHT_TO_LEFT;
     }
 
     /**
@@ -178,6 +214,4 @@
         }
         return new Directions(ld);
     }
-
-    private native static int runBidi(int dir, char[] chs, byte[] chInfo, int n, boolean haveInfo);
 }
\ No newline at end of file
diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java
index ad26f23..4f1488e 100644
--- a/core/java/android/text/Hyphenator.java
+++ b/core/java/android/text/Hyphenator.java
@@ -16,258 +16,15 @@
 
 package android.text;
 
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.util.HashMap;
-import java.util.Locale;
-
 /**
- * Hyphenator is a wrapper class for a native implementation of automatic hyphenation,
+ * Hyphenator just initializes the native implementation of automatic hyphenation,
  * in essence finding valid hyphenation opportunities in a word.
  *
  * @hide
  */
 public class Hyphenator {
-    private static String TAG = "Hyphenator";
-
-    private final static Object sLock = new Object();
-
-    @GuardedBy("sLock")
-    final static HashMap<Locale, Hyphenator> sMap = new HashMap<Locale, Hyphenator>();
-
-    private final long mNativePtr;
-    private final HyphenationData mData;
-
-    private Hyphenator(long nativePtr, HyphenationData data) {
-        mNativePtr = nativePtr;
-        mData = data;
-    }
-
-    public long getNativePtr() {
-        return mNativePtr;
-    }
-
-    public static Hyphenator get(@Nullable Locale locale) {
-        synchronized (sLock) {
-            Hyphenator result = sMap.get(locale);
-            if (result != null) {
-                return result;
-            }
-
-            // If there's a variant, fall back to language+variant only, if available
-            final String variant = locale.getVariant();
-            if (!variant.isEmpty()) {
-                final Locale languageAndVariantOnlyLocale =
-                        new Locale(locale.getLanguage(), "", variant);
-                result = sMap.get(languageAndVariantOnlyLocale);
-                if (result != null) {
-                    return putAlias(locale, result);
-                }
-            }
-
-            // Fall back to language-only, if available
-            final Locale languageOnlyLocale = new Locale(locale.getLanguage());
-            result = sMap.get(languageOnlyLocale);
-            if (result != null) {
-                return putAlias(locale, result);
-            }
-
-            // Fall back to script-only, if available
-            final String script = locale.getScript();
-            if (!script.equals("")) {
-                final Locale scriptOnlyLocale = new Locale.Builder()
-                        .setLanguage("und")
-                        .setScript(script)
-                        .build();
-                result = sMap.get(scriptOnlyLocale);
-                if (result != null) {
-                    return putAlias(locale, result);
-                }
-            }
-
-            return putEmptyAlias(locale);
-        }
-    }
-
-    private static class HyphenationData {
-        private static final String SYSTEM_HYPHENATOR_LOCATION = "/system/usr/hyphen-data";
-
-        public final int mMinPrefix, mMinSuffix;
-        public final long mDataAddress;
-
-        // Reasonable enough values for cases where we have no hyphenation patterns but may be able
-        // to do some automatic hyphenation based on characters. These values would be used very
-        // rarely.
-        private static final int DEFAULT_MIN_PREFIX = 2;
-        private static final int DEFAULT_MIN_SUFFIX = 2;
-
-        public static final HyphenationData sEmptyData =
-                new HyphenationData(DEFAULT_MIN_PREFIX, DEFAULT_MIN_SUFFIX);
-
-        // Create empty HyphenationData.
-        private HyphenationData(int minPrefix, int minSuffix) {
-            mMinPrefix = minPrefix;
-            mMinSuffix = minSuffix;
-            mDataAddress = 0;
-        }
-
-        HyphenationData(String languageTag, int minPrefix, int minSuffix) {
-            mMinPrefix = minPrefix;
-            mMinSuffix = minSuffix;
-
-            final String patternFilename = "hyph-" + languageTag.toLowerCase(Locale.US) + ".hyb";
-            final File patternFile = new File(SYSTEM_HYPHENATOR_LOCATION, patternFilename);
-            if (!patternFile.canRead()) {
-                Log.e(TAG, "hyphenation patterns for " + patternFile + " not found or unreadable");
-                mDataAddress = 0;
-            } else {
-                long address;
-                try (RandomAccessFile f = new RandomAccessFile(patternFile, "r")) {
-                    address = Os.mmap(0, f.length(), OsConstants.PROT_READ,
-                            OsConstants.MAP_SHARED, f.getFD(), 0 /* offset */);
-                } catch (IOException | ErrnoException e) {
-                    Log.e(TAG, "error loading hyphenation " + patternFile, e);
-                    address = 0;
-                }
-                mDataAddress = address;
-            }
-        }
-    }
-
-    // Do not call this method outside of init method.
-    private static Hyphenator putNewHyphenator(Locale loc, HyphenationData data) {
-        final Hyphenator hyphenator = new Hyphenator(nBuildHyphenator(
-                data.mDataAddress, loc.getLanguage(), data.mMinPrefix, data.mMinSuffix), data);
-        sMap.put(loc, hyphenator);
-        return hyphenator;
-    }
-
-    // Do not call this method outside of init method.
-    private static void loadData(String langTag, int minPrefix, int maxPrefix) {
-        final HyphenationData data = new HyphenationData(langTag, minPrefix, maxPrefix);
-        putNewHyphenator(Locale.forLanguageTag(langTag), data);
-    }
-
-    // Caller must acquire sLock before calling this method.
-    // The Hyphenator for the baseLangTag must exists.
-    private static Hyphenator addAliasByTag(String langTag, String baseLangTag) {
-        return putAlias(Locale.forLanguageTag(langTag),
-                sMap.get(Locale.forLanguageTag(baseLangTag)));
-    }
-
-    // Caller must acquire sLock before calling this method.
-    private static Hyphenator putAlias(Locale locale, Hyphenator base) {
-        return putNewHyphenator(locale, base.mData);
-    }
-
-    // Caller must acquire sLock before calling this method.
-    private static Hyphenator putEmptyAlias(Locale locale) {
-        return putNewHyphenator(locale, HyphenationData.sEmptyData);
-    }
-
-    // TODO: Confirm that these are the best values. Various sources suggest (1, 1), but
-    // that appears too small.
-    private static final int INDIC_MIN_PREFIX = 2;
-    private static final int INDIC_MIN_SUFFIX = 2;
-
-    /**
-     * Load hyphenation patterns at initialization time. We want to have patterns
-     * for all locales loaded and ready to use so we don't have to do any file IO
-     * on the UI thread when drawing text in different locales.
-     *
-     * @hide
-     */
     public static void init() {
-        synchronized (sLock) {
-            sMap.put(null, null);
-
-            loadData("as", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Assamese
-            loadData("bg", 2, 2); // Bulgarian
-            loadData("bn", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Bengali
-            loadData("cu", 1, 2); // Church Slavonic
-            loadData("cy", 2, 3); // Welsh
-            loadData("da", 2, 2); // Danish
-            loadData("de-1901", 2, 2); // German 1901 orthography
-            loadData("de-1996", 2, 2); // German 1996 orthography
-            loadData("de-CH-1901", 2, 2); // Swiss High German 1901 orthography
-            loadData("en-GB", 2, 3); // British English
-            loadData("en-US", 2, 3); // American English
-            loadData("es", 2, 2); // Spanish
-            loadData("et", 2, 3); // Estonian
-            loadData("eu", 2, 2); // Basque
-            loadData("fr", 2, 3); // French
-            loadData("ga", 2, 3); // Irish
-            loadData("gu", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Gujarati
-            loadData("hi", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Hindi
-            loadData("hr", 2, 2); // Croatian
-            loadData("hu", 2, 2); // Hungarian
-            // texhyphen sources say Armenian may be (1, 2); but that it needs confirmation.
-            // Going with a more conservative value of (2, 2) for now.
-            loadData("hy", 2, 2); // Armenian
-            loadData("kn", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Kannada
-            loadData("ml", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Malayalam
-            loadData("mn-Cyrl", 2, 2); // Mongolian in Cyrillic script
-            loadData("mr", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Marathi
-            loadData("nb", 2, 2); // Norwegian Bokmål
-            loadData("nn", 2, 2); // Norwegian Nynorsk
-            loadData("or", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Oriya
-            loadData("pa", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Punjabi
-            loadData("pt", 2, 3); // Portuguese
-            loadData("sl", 2, 2); // Slovenian
-            loadData("ta", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Tamil
-            loadData("te", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Telugu
-            loadData("tk", 2, 2); // Turkmen
-            loadData("und-Ethi", 1, 1); // Any language in Ethiopic script
-
-            // English locales that fall back to en-US. The data is
-            // from CLDR. It's all English locales, minus the locales whose
-            // parent is en-001 (from supplementalData.xml, under <parentLocales>).
-            // TODO: Figure out how to get this from ICU.
-            addAliasByTag("en-AS", "en-US"); // English (American Samoa)
-            addAliasByTag("en-GU", "en-US"); // English (Guam)
-            addAliasByTag("en-MH", "en-US"); // English (Marshall Islands)
-            addAliasByTag("en-MP", "en-US"); // English (Northern Mariana Islands)
-            addAliasByTag("en-PR", "en-US"); // English (Puerto Rico)
-            addAliasByTag("en-UM", "en-US"); // English (United States Minor Outlying Islands)
-            addAliasByTag("en-VI", "en-US"); // English (Virgin Islands)
-
-            // All English locales other than those falling back to en-US are mapped to en-GB.
-            addAliasByTag("en", "en-GB");
-
-            // For German, we're assuming the 1996 (and later) orthography by default.
-            addAliasByTag("de", "de-1996");
-            // Liechtenstein uses the Swiss hyphenation rules for the 1901 orthography.
-            addAliasByTag("de-LI-1901", "de-CH-1901");
-
-            // Norwegian is very probably Norwegian Bokmål.
-            addAliasByTag("no", "nb");
-
-            // Use mn-Cyrl. According to CLDR's likelySubtags.xml, mn is most likely to be mn-Cyrl.
-            addAliasByTag("mn", "mn-Cyrl"); // Mongolian
-
-            // Fall back to Ethiopic script for languages likely to be written in Ethiopic.
-            // Data is from CLDR's likelySubtags.xml.
-            // TODO: Convert this to a mechanism using ICU4J's ULocale#addLikelySubtags().
-            addAliasByTag("am", "und-Ethi"); // Amharic
-            addAliasByTag("byn", "und-Ethi"); // Blin
-            addAliasByTag("gez", "und-Ethi"); // Geʻez
-            addAliasByTag("ti", "und-Ethi"); // Tigrinya
-            addAliasByTag("wal", "und-Ethi"); // Wolaytta
-        }
-    };
-
-    private static native long nBuildHyphenator(/* non-zero */ long dataAddress,
-            @NonNull String langTag, @IntRange(from = 1) int minPrefix,
-            @IntRange(from = 1) int minSuffix);
+        nInit();
+    }
+    private static native void nInit();
 }
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index b09ccc2..ffc44a7 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -106,8 +106,8 @@
         if (mWidths == null || mWidths.length < len) {
             mWidths = ArrayUtils.newUnpaddedFloatArray(len);
         }
-        if (mChars == null || mChars.length < len) {
-            mChars = ArrayUtils.newUnpaddedCharArray(len);
+        if (mChars == null || mChars.length != len) {
+            mChars = new char[len];
         }
         TextUtils.getChars(text, start, end, mChars, 0);
 
@@ -151,7 +151,7 @@
                 boolean isRtl = textDir.isRtl(mChars, 0, len);
                 bidiRequest = isRtl ? Layout.DIR_REQUEST_RTL : Layout.DIR_REQUEST_LTR;
             }
-            mDir = AndroidBidi.bidi(bidiRequest, mChars, mLevels, len, false);
+            mDir = AndroidBidi.bidi(bidiRequest, mChars, mLevels);
             mEasy = false;
         }
     }
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 4b6b6ae..5c60188 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -21,21 +21,18 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.Paint;
-import android.os.LocaleList;
 import android.text.style.LeadingMarginSpan;
 import android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
 import android.text.style.LineHeightSpan;
 import android.text.style.MetricAffectingSpan;
 import android.text.style.TabStopSpan;
 import android.util.Log;
-import android.util.Pair;
 import android.util.Pools.SynchronizedPool;
 
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.GrowingArrayUtils;
 
 import java.util.Arrays;
-import java.util.Locale;
 
 /**
  * StaticLayout is a Layout for text that will not be edited after it
@@ -101,7 +98,6 @@
             b.mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
             b.mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE;
             b.mJustificationMode = Layout.JUSTIFICATION_MODE_NONE;
-            b.mLocales = null;
 
             b.mMeasuredText = MeasuredText.obtain();
             return b;
@@ -118,7 +114,6 @@
             b.mMeasuredText = null;
             b.mLeftIndents = null;
             b.mRightIndents = null;
-            b.mLocales = null;
             b.mLeftPaddings = null;
             b.mRightPaddings = null;
             nFinishBuilder(b.mNativePtr);
@@ -409,17 +404,6 @@
             return this;
         }
 
-        @NonNull
-        private long[] getHyphenators(@NonNull LocaleList locales) {
-            final int length = locales.size();
-            final long[] result = new long[length];
-            for (int i = 0; i < length; i++) {
-                final Locale locale = locales.get(i);
-                result[i] = Hyphenator.get(locale).getNativePtr();
-            }
-            return result;
-        }
-
         /**
          * Measurement and break iteration is done in native code. The protocol for using
          * the native code is as follows.
@@ -438,27 +422,12 @@
          * After all paragraphs, call finish() to release expensive buffers.
          */
 
-        private Pair<String, long[]> getLocaleAndHyphenatorIfChanged(TextPaint paint) {
-            final LocaleList locales = paint.getTextLocales();
-            if (!locales.equals(mLocales)) {
-                mLocales = locales;
-                return new Pair(locales.toLanguageTags(), getHyphenators(locales));
-            } else {
-                // passing null means keep current locale.
-                // TODO: move locale change detection to native.
-                return new Pair(null, null);
-            }
-        }
-
         /* package */ void addStyleRun(TextPaint paint, int start, int end, boolean isRtl) {
-            Pair<String, long[]> locHyph = getLocaleAndHyphenatorIfChanged(paint);
-            nAddStyleRun(mNativePtr, paint.getNativeInstance(), start, end, isRtl, locHyph.first,
-                    locHyph.second);
+            nAddStyleRun(mNativePtr, paint.getNativeInstance(), start, end, isRtl);
         }
 
         /* package */ void addReplacementRun(TextPaint paint, int start, int end, float width) {
-            Pair<String, long[]> locHyph = getLocaleAndHyphenatorIfChanged(paint);
-            nAddReplacementRun(mNativePtr, start, end, width, locHyph.first, locHyph.second);
+            nAddReplacementRun(mNativePtr, paint.getNativeInstance(), start, end, width);
         }
 
         /**
@@ -516,8 +485,6 @@
         // This will go away and be subsumed by native builder code
         private MeasuredText mMeasuredText;
 
-        private LocaleList mLocales;
-
         private static final SynchronizedPool<Builder> sPool = new SynchronizedPool<>(3);
     }
 
@@ -807,9 +774,6 @@
                 }
             }
 
-            // TODO: Move locale tracking code to native.
-            b.mLocales = null;  // Reset the locale tracking.
-
             nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart,
                     firstWidth, firstWidthLineCount, restWidth,
                     variableTabStops, TAB_INCREMENT, b.mBreakStrategy, b.mHyphenationFrequency,
@@ -1537,15 +1501,16 @@
             @Nullable int[] indents, @Nullable int[] leftPaddings, @Nullable int[] rightPaddings,
             @IntRange(from = 0) int indentsOffset);
 
+    // TODO: Make this method CriticalNative once native code defers doing layouts.
     private static native void nAddStyleRun(
             /* non-zero */ long nativePtr, /* non-zero */ long nativePaint,
-            @IntRange(from = 0) int start, @IntRange(from = 0) int end, boolean isRtl,
-            @Nullable String languageTags, @Nullable long[] hyphenators);
+            @IntRange(from = 0) int start, @IntRange(from = 0) int end, boolean isRtl);
 
-    private static native void nAddReplacementRun(/* non-zero */ long nativePtr,
+    // TODO: Make this method CriticalNative once native code defers doing layouts.
+    private static native void nAddReplacementRun(
+            /* non-zero */ long nativePtr, /* non-zero */ long nativePaint,
             @IntRange(from = 0) int start, @IntRange(from = 0) int end,
-            @FloatRange(from = 0.0f) float width, @Nullable String languageTags,
-            @Nullable long[] hyphenators);
+            @FloatRange(from = 0.0f) float width);
 
     // populates LineBreaks and returns the number of breaks found
     //
diff --git a/core/java/android/util/MutableBoolean.java b/core/java/android/util/MutableBoolean.java
new file mode 100644
index 0000000..ed837ab
--- /dev/null
+++ b/core/java/android/util/MutableBoolean.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+/**
+ */
+public final class MutableBoolean {
+    public boolean value;
+
+    public MutableBoolean(boolean value) {
+        this.value = value;
+    }
+}
diff --git a/core/java/android/util/MutableByte.java b/core/java/android/util/MutableByte.java
new file mode 100644
index 0000000..cc6b00a
--- /dev/null
+++ b/core/java/android/util/MutableByte.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+/**
+ */
+public final class MutableByte {
+    public byte value;
+
+    public MutableByte(byte value) {
+        this.value = value;
+    }
+}
diff --git a/core/java/android/util/MutableChar.java b/core/java/android/util/MutableChar.java
new file mode 100644
index 0000000..9a2e2bc
--- /dev/null
+++ b/core/java/android/util/MutableChar.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+/**
+ */
+public final class MutableChar {
+    public char value;
+
+    public MutableChar(char value) {
+        this.value = value;
+    }
+}
diff --git a/core/java/android/util/MutableDouble.java b/core/java/android/util/MutableDouble.java
new file mode 100644
index 0000000..bd7329a
--- /dev/null
+++ b/core/java/android/util/MutableDouble.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+/**
+ */
+public final class MutableDouble {
+    public double value;
+
+    public MutableDouble(double value) {
+        this.value = value;
+    }
+}
diff --git a/core/java/android/util/MutableFloat.java b/core/java/android/util/MutableFloat.java
new file mode 100644
index 0000000..e6f2d7d
--- /dev/null
+++ b/core/java/android/util/MutableFloat.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+/**
+ */
+public final class MutableFloat {
+    public float value;
+
+    public MutableFloat(float value) {
+        this.value = value;
+    }
+}
diff --git a/core/java/android/util/MutableShort.java b/core/java/android/util/MutableShort.java
new file mode 100644
index 0000000..48fb232
--- /dev/null
+++ b/core/java/android/util/MutableShort.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+/**
+ */
+public final class MutableShort {
+    public short value;
+
+    public MutableShort(short value) {
+        this.value = value;
+    }
+}
diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java
deleted file mode 100644
index 0be1a8c..0000000
--- a/core/java/android/util/StatsLog.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2007 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.util;
-
-/**
- * Logging access for platform metrics.
- *
- * <p>This is <b>not</b> the main "logcat" debugging log ({@link android.util.Log})!
- * These diagnostic stats are for system integrators, not application authors.
- *
- * <p>Stats use integer tag codes.
- * They carry a payload of one or more int, long, or String values.
- * @hide
- */
-public class StatsLog {
-    /** @hide */ public StatsLog() {}
-
-    private static final String TAG = "StatsLog";
-
-    // We assume that the native methods deal with any concurrency issues.
-
-    /**
-     * Records an stats log message.
-     * @param tag The stats type tag code
-     * @param value A value to log
-     * @return The number of bytes written
-     */
-    public static native int writeInt(int tag, int value);
-
-    /**
-     * Records an stats log message.
-     * @param tag The stats type tag code
-     * @param value A value to log
-     * @return The number of bytes written
-     */
-    public static native int writeLong(int tag, long value);
-
-    /**
-     * Records an stats log message.
-     * @param tag The stats type tag code
-     * @param value A value to log
-     * @return The number of bytes written
-     */
-    public static native int writeFloat(int tag, float value);
-
-    /**
-     * Records an stats log message.
-     * @param tag The stats type tag code
-     * @param str A value to log
-     * @return The number of bytes written
-     */
-    public static native int writeString(int tag, String str);
-
-    /**
-     * Records an stats log message.
-     * @param tag The stats type tag code
-     * @param list A list of values to log. All values should
-     * be of type int, long, float or String.
-     * @return The number of bytes written
-     */
-    public static native int writeArray(int tag, Object... list);
-}
diff --git a/core/java/android/util/StatsLogKey.java b/core/java/android/util/StatsLogKey.java
deleted file mode 100644
index 9ad0a23..0000000
--- a/core/java/android/util/StatsLogKey.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// THIS FILE IS AUTO-GENERATED.
-// DO NOT MODIFY.
-
-package android.util;
-
-/** @hide */
-public class StatsLogKey {
-    private StatsLogKey() {}
-
-    /** Constants for android.os.statsd.ScreenStateChange. */
-
-    /** display_state */
-    public static final int SCREEN_STATE_CHANGE__DISPLAY_STATE = 1;
-
-    /** Constants for android.os.statsd.ProcessStateChange. */
-
-    /** state */
-    public static final int PROCESS_STATE_CHANGE__STATE = 1;
-
-    /** uid */
-    public static final int PROCESS_STATE_CHANGE__UID = 2;
-
-    /** package_name */
-    public static final int PROCESS_STATE_CHANGE__PACKAGE_NAME = 1002;
-
-    /** package_version */
-    public static final int PROCESS_STATE_CHANGE__PACKAGE_VERSION = 3;
-
-    /** package_version_string */
-    public static final int PROCESS_STATE_CHANGE__PACKAGE_VERSION_STRING = 4;
-
-}
diff --git a/core/java/android/util/StatsLogTag.java b/core/java/android/util/StatsLogTag.java
deleted file mode 100644
index 5e5a828..0000000
--- a/core/java/android/util/StatsLogTag.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// THIS FILE IS AUTO-GENERATED.
-// DO NOT MODIFY.
-
-package android.util;
-
-/** @hide */
-public class StatsLogTag {
-    private StatsLogTag() {}
-
-    /** android.os.statsd.ScreenStateChange. */
-    public static final int SCREEN_STATE_CHANGE = 2;
-
-    /** android.os.statsd.ProcessStateChange. */
-    public static final int PROCESS_STATE_CHANGE = 1112;
-
-}
diff --git a/core/java/android/util/StatsLogValue.java b/core/java/android/util/StatsLogValue.java
deleted file mode 100644
index 05b9d93..0000000
--- a/core/java/android/util/StatsLogValue.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// THIS FILE IS AUTO-GENERATED.
-// DO NOT MODIFY.
-
-package android.util;
-
-/** @hide */
-public class StatsLogValue {
-    private StatsLogValue() {}
-
-    /** Constants for android.os.statsd.ScreenStateChange. */
-
-    /** display_state: STATE_UNKNOWN */
-    public static final int SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_UNKNOWN = 0;
-
-    /** display_state: STATE_OFF */
-    public static final int SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF = 1;
-
-    /** display_state: STATE_ON */
-    public static final int SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON = 2;
-
-    /** display_state: STATE_DOZE */
-    public static final int SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_DOZE = 3;
-
-    /** display_state: STATE_DOZE_SUSPEND */
-    public static final int SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_DOZE_SUSPEND = 4;
-
-    /** display_state: STATE_VR */
-    public static final int SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_VR = 5;
-
-    /** Constants for android.os.statsd.ProcessStateChange. */
-
-    /** state: START */
-    public static final int PROCESS_STATE_CHANGE__STATE__START = 1;
-
-    /** state: CRASH */
-    public static final int PROCESS_STATE_CHANGE__STATE__CRASH = 2;
-
-}
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index 0216a07..a9ccae1 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -17,6 +17,7 @@
 package android.util.apk;
 
 import android.system.ErrnoException;
+import android.system.Os;
 import android.system.OsConstants;
 import android.util.ArrayMap;
 import android.util.Pair;
@@ -59,9 +60,6 @@
 import java.util.Map;
 import java.util.Set;
 
-import libcore.io.Libcore;
-import libcore.io.Os;
-
 /**
  * APK Signature Scheme v2 verifier.
  *
@@ -994,8 +992,7 @@
      * {@link DataSource#feedIntoMessageDigests(MessageDigest[], long, int) feedIntoMessageDigests}.
      */
     private static final class MemoryMappedFileDataSource implements DataSource {
-        private static final Os OS = Libcore.os;
-        private static final long MEMORY_PAGE_SIZE_BYTES = OS.sysconf(OsConstants._SC_PAGESIZE);
+        private static final long MEMORY_PAGE_SIZE_BYTES = Os.sysconf(OsConstants._SC_PAGESIZE);
 
         private final FileDescriptor mFd;
         private final long mFilePosition;
@@ -1041,7 +1038,7 @@
             long mmapRegionSize = size + dataStartOffsetInMmapRegion;
             long mmapPtr = 0;
             try {
-                mmapPtr = OS.mmap(
+                mmapPtr = Os.mmap(
                         0, // let the OS choose the start address of the region in memory
                         mmapRegionSize,
                         OsConstants.PROT_READ,
@@ -1066,7 +1063,7 @@
             } finally {
                 if (mmapPtr != 0) {
                     try {
-                        OS.munmap(mmapPtr, mmapRegionSize);
+                        Os.munmap(mmapPtr, mmapRegionSize);
                     } catch (ErrnoException ignored) {}
                 }
             }
diff --git a/core/java/android/view/MenuItem.java b/core/java/android/view/MenuItem.java
index 88b9c0d..ad160cb 100644
--- a/core/java/android/view/MenuItem.java
+++ b/core/java/android/view/MenuItem.java
@@ -72,11 +72,6 @@
     public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8;
 
     /**
-     * @hide
-     */
-    int SHOW_AS_OVERFLOW_ALWAYS = 1 << 31;
-
-    /**
      * Interface definition for a callback to be invoked when a menu item is
      * clicked.
      *
@@ -806,12 +801,22 @@
     }
 
     /**
-     * Returns true if {@link #setShowAsAction(int)} was set to {@link #SHOW_AS_OVERFLOW_ALWAYS}.
-     * Default value if {@code false}.
+     * Returns true if {@link #setShowAsAction(int)} was set to {@link #SHOW_AS_ACTION_ALWAYS}.
+     * Default value is {@code false}.
+     *
+     * @hide
+     */
+    default boolean requiresActionButton() {
+        return false;
+    }
+
+    /**
+     * Returns true if {@link #setShowAsAction(int)} was set to {@link #SHOW_AS_ACTION_NEVER}.
+     * Default value is {@code true}.
      *
      * @hide
      */
     default boolean requiresOverflow() {
-        return false;
+        return true;
     }
 }
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 31daeff..ff027a9 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -21,15 +21,22 @@
 import android.annotation.Size;
 import android.graphics.Bitmap;
 import android.graphics.GraphicBuffer;
+import android.graphics.Point;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.Binder;
+import android.os.Debug;
 import android.os.IBinder;
 import android.util.Log;
 import android.view.Surface.OutOfResourcesException;
 
 import dalvik.system.CloseGuard;
 
+import java.io.Closeable;
+
+import libcore.util.NativeAllocationRegistry;
+
 /**
  * SurfaceControl
  *  @hide
@@ -54,25 +61,34 @@
             Rect sourceCrop, int width, int height, int minLayer, int maxLayer,
             boolean allLayers, boolean useIdentityTransform);
 
-    private static native void nativeOpenTransaction();
-    private static native void nativeCloseTransaction(boolean sync);
-    private static native void nativeSetAnimationTransaction();
+    private static native long nativeCreateTransaction();
+    private static native long nativeGetNativeTransactionFinalizer();
+    private static native void nativeApplyTransaction(long transactionObj, boolean sync);
+    private static native void nativeSetAnimationTransaction(long transactionObj);
 
-    private static native void nativeSetLayer(long nativeObject, int zorder);
-    private static native void nativeSetRelativeLayer(long nativeObject, IBinder relativeTo,
-            int zorder);
-    private static native void nativeSetPosition(long nativeObject, float x, float y);
-    private static native void nativeSetGeometryAppliesWithResize(long nativeObject);
-    private static native void nativeSetSize(long nativeObject, int w, int h);
-    private static native void nativeSetTransparentRegionHint(long nativeObject, Region region);
-    private static native void nativeSetAlpha(long nativeObject, float alpha);
-    private static native void nativeSetColor(long nativeObject, float[] color);
-    private static native void nativeSetMatrix(long nativeObject, float dsdx, float dtdx,
+    private static native void nativeSetLayer(long transactionObj, long nativeObject, int zorder);
+    private static native void nativeSetRelativeLayer(long transactionObj, long nativeObject,
+            IBinder relativeTo, int zorder);
+    private static native void nativeSetPosition(long transactionObj, long nativeObject,
+            float x, float y);
+    private static native void nativeSetGeometryAppliesWithResize(long transactionObj,
+            long nativeObject);
+    private static native void nativeSetSize(long transactionObj, long nativeObject, int w, int h);
+    private static native void nativeSetTransparentRegionHint(long transactionObj,
+            long nativeObject, Region region);
+    private static native void nativeSetAlpha(long transactionObj, long nativeObject, float alpha);
+    private static native void nativeSetMatrix(long transactionObj, long nativeObject,
+            float dsdx, float dtdx,
             float dtdy, float dsdy);
-    private static native void nativeSetFlags(long nativeObject, int flags, int mask);
-    private static native void nativeSetWindowCrop(long nativeObject, int l, int t, int r, int b);
-    private static native void nativeSetFinalCrop(long nativeObject, int l, int t, int r, int b);
-    private static native void nativeSetLayerStack(long nativeObject, int layerStack);
+    private static native void nativeSetColor(long transactionObj, long nativeObject, float[] color);
+    private static native void nativeSetFlags(long transactionObj, long nativeObject,
+            int flags, int mask);
+    private static native void nativeSetWindowCrop(long transactionObj, long nativeObject,
+            int l, int t, int r, int b);
+    private static native void nativeSetFinalCrop(long transactionObj, long nativeObject,
+            int l, int t, int r, int b);
+    private static native void nativeSetLayerStack(long transactionObj, long nativeObject,
+            int layerStack);
 
     private static native boolean nativeClearContentFrameStats(long nativeObject);
     private static native boolean nativeGetContentFrameStats(long nativeObject, WindowContentFrameStats outStats);
@@ -82,15 +98,16 @@
     private static native IBinder nativeGetBuiltInDisplay(int physicalDisplayId);
     private static native IBinder nativeCreateDisplay(String name, boolean secure);
     private static native void nativeDestroyDisplay(IBinder displayToken);
-    private static native void nativeSetDisplaySurface(
+    private static native void nativeSetDisplaySurface(long transactionObj,
             IBinder displayToken, long nativeSurfaceObject);
-    private static native void nativeSetDisplayLayerStack(
+    private static native void nativeSetDisplayLayerStack(long transactionObj,
             IBinder displayToken, int layerStack);
-    private static native void nativeSetDisplayProjection(
+    private static native void nativeSetDisplayProjection(long transactionObj,
             IBinder displayToken, int orientation,
             int l, int t, int r, int b,
             int L, int T, int R, int B);
-    private static native void nativeSetDisplaySize(IBinder displayToken, int width, int height);
+    private static native void nativeSetDisplaySize(long transactionObj, IBinder displayToken,
+            int width, int height);
     private static native SurfaceControl.PhysicalDisplayInfo[] nativeGetDisplayConfigs(
             IBinder displayToken);
     private static native int nativeGetActiveConfig(IBinder displayToken);
@@ -101,16 +118,17 @@
             int colorMode);
     private static native void nativeSetDisplayPowerMode(
             IBinder displayToken, int mode);
-    private static native void nativeDeferTransactionUntil(long nativeObject,
+    private static native void nativeDeferTransactionUntil(long transactionObj, long nativeObject,
             IBinder handle, long frame);
-    private static native void nativeDeferTransactionUntilSurface(long nativeObject,
+    private static native void nativeDeferTransactionUntilSurface(long transactionObj,
+            long nativeObject,
             long surfaceObject, long frame);
-    private static native void nativeReparentChildren(long nativeObject,
+    private static native void nativeReparentChildren(long transactionObj, long nativeObject,
             IBinder handle);
-    private static native void nativeReparent(long nativeObject,
+    private static native void nativeReparent(long transactionObj, long nativeObject,
             IBinder parentHandle);
-    private static native void nativeSeverChildren(long nativeObject);
-    private static native void nativeSetOverrideScalingMode(long nativeObject,
+    private static native void nativeSeverChildren(long transactionObj, long nativeObject);
+    private static native void nativeSetOverrideScalingMode(long transactionObj, long nativeObject,
             int scalingMode);
     private static native IBinder nativeGetHandle(long nativeObject);
     private static native boolean nativeGetTransformToDisplayInverse(long nativeObject);
@@ -122,6 +140,9 @@
     private final String mName;
     long mNativeObject; // package visibility only for Surface.java access
 
+    static Transaction sGlobalTransaction;
+    static long sTransactionNestCount = 0;
+
     /* flags used in constructor (keep in sync with ISurfaceComposerClient.h) */
 
     /**
@@ -377,11 +398,6 @@
         }
     }
 
-    @Override
-    public String toString() {
-        return "Surface(name=" + mName + ")";
-    }
-
     /**
      * Release the local reference to the server-side surface.
      * Always call release() when you're done with a Surface.
@@ -429,102 +445,141 @@
 
     /** start a transaction */
     public static void openTransaction() {
-        nativeOpenTransaction();
+        synchronized (SurfaceControl.class) {
+            if (sGlobalTransaction == null) {
+                sGlobalTransaction = new Transaction();
+            }
+            synchronized(SurfaceControl.class) {
+                sTransactionNestCount++;
+            }
+        }
+    }
+
+    private static void closeTransaction(boolean sync) {
+        synchronized(SurfaceControl.class) {
+            if (sTransactionNestCount == 0) {
+                Log.e(TAG, "Call to SurfaceControl.closeTransaction without matching openTransaction");
+            } else if (--sTransactionNestCount > 0) {
+                return;
+            }
+            sGlobalTransaction.apply(sync);
+        }
     }
 
     /** end a transaction */
     public static void closeTransaction() {
-        nativeCloseTransaction(false);
+        closeTransaction(false);
     }
 
     public static void closeTransactionSync() {
-        nativeCloseTransaction(true);
+        closeTransaction(true);
     }
 
     public void deferTransactionUntil(IBinder handle, long frame) {
         if (frame > 0) {
-            nativeDeferTransactionUntil(mNativeObject, handle, frame);
+            synchronized(SurfaceControl.class) {
+                sGlobalTransaction.deferTransactionUntil(this, handle, frame);
+            }
         }
     }
 
     public void deferTransactionUntil(Surface barrier, long frame) {
         if (frame > 0) {
-            nativeDeferTransactionUntilSurface(mNativeObject, barrier.mNativeObject, frame);
+            synchronized(SurfaceControl.class) {
+                sGlobalTransaction.deferTransactionUntilSurface(this, barrier, frame);
+            }
         }
     }
 
     public void reparentChildren(IBinder newParentHandle) {
-        nativeReparentChildren(mNativeObject, newParentHandle);
+        synchronized(SurfaceControl.class) {
+            sGlobalTransaction.reparentChildren(this, newParentHandle);
+        }
     }
 
-    /** Re-parents this layer to a new parent. */
     public void reparent(IBinder newParentHandle) {
-        nativeReparent(mNativeObject, newParentHandle);
+        synchronized(SurfaceControl.class) {
+            sGlobalTransaction.reparent(this, newParentHandle);
+        }
     }
 
     public void detachChildren() {
-        nativeSeverChildren(mNativeObject);
+        synchronized(SurfaceControl.class) {
+            sGlobalTransaction.detachChildren(this);
+        }
     }
 
     public void setOverrideScalingMode(int scalingMode) {
         checkNotReleased();
-        nativeSetOverrideScalingMode(mNativeObject, scalingMode);
+        synchronized(SurfaceControl.class) {
+            sGlobalTransaction.setOverrideScalingMode(this, scalingMode);
+        }
     }
 
     public IBinder getHandle() {
         return nativeGetHandle(mNativeObject);
     }
 
-    /** flag the transaction as an animation */
     public static void setAnimationTransaction() {
-        nativeSetAnimationTransaction();
+        synchronized (SurfaceControl.class) {
+            sGlobalTransaction.setAnimationTransaction();
+        }
     }
 
     public void setLayer(int zorder) {
         checkNotReleased();
-        nativeSetLayer(mNativeObject, zorder);
+        synchronized(SurfaceControl.class) {
+            sGlobalTransaction.setLayer(this, zorder);
+        }
     }
 
     public void setRelativeLayer(IBinder relativeTo, int zorder) {
         checkNotReleased();
-        nativeSetRelativeLayer(mNativeObject, relativeTo, zorder);
+        synchronized(SurfaceControl.class) {
+            sGlobalTransaction.setRelativeLayer(this, relativeTo, zorder);
+        }
     }
 
     public void setPosition(float x, float y) {
         checkNotReleased();
-        nativeSetPosition(mNativeObject, x, y);
+        synchronized(SurfaceControl.class) {
+            sGlobalTransaction.setPosition(this, x, y);
+        }
     }
 
-    /**
-     * If the buffer size changes in this transaction, position and crop updates specified
-     * in this transaction will not complete until a buffer of the new size
-     * arrives. As transform matrix and size are already frozen in this fashion,
-     * this enables totally freezing the surface until the resize has completed
-     * (at which point the geometry influencing aspects of this transaction will then occur)
-     */
     public void setGeometryAppliesWithResize() {
         checkNotReleased();
-        nativeSetGeometryAppliesWithResize(mNativeObject);
+        synchronized(SurfaceControl.class) {
+            sGlobalTransaction.setGeometryAppliesWithResize(this);
+        }
     }
 
     public void setSize(int w, int h) {
         checkNotReleased();
-        nativeSetSize(mNativeObject, w, h);
+        synchronized(SurfaceControl.class) {
+            sGlobalTransaction.setSize(this, w, h);
+        }
     }
 
     public void hide() {
         checkNotReleased();
-        nativeSetFlags(mNativeObject, SURFACE_HIDDEN, SURFACE_HIDDEN);
+        synchronized(SurfaceControl.class) {
+            sGlobalTransaction.hide(this);
+        }
     }
 
     public void show() {
         checkNotReleased();
-        nativeSetFlags(mNativeObject, 0, SURFACE_HIDDEN);
+        synchronized(SurfaceControl.class) {
+            sGlobalTransaction.show(this);
+        }
     }
 
     public void setTransparentRegionHint(Region region) {
         checkNotReleased();
-        nativeSetTransparentRegionHint(mNativeObject, region);
+        synchronized(SurfaceControl.class) {
+            sGlobalTransaction.setTransparentRegionHint(this, region);
+        }
     }
 
     public boolean clearContentFrameStats() {
@@ -545,80 +600,70 @@
         return nativeGetAnimationFrameStats(outStats);
     }
 
-    /**
-     * Sets an alpha value for the entire Surface.  This value is combined with the
-     * per-pixel alpha.  It may be used with opaque Surfaces.
-     */
     public void setAlpha(float alpha) {
         checkNotReleased();
-        nativeSetAlpha(mNativeObject, alpha);
+        synchronized(SurfaceControl.class) {
+            sGlobalTransaction.setAlpha(this, alpha);
+        }
     }
 
-    /**
-     * Sets a color for the Surface.
-     * @param color A float array with three values to represent r, g, b in range [0..1]
-     */
     public void setColor(@Size(3) float[] color) {
         checkNotReleased();
-        nativeSetColor(mNativeObject, color);
+        synchronized (SurfaceControl.class) {
+            sGlobalTransaction.setColor(this, color);
+        }
     }
 
     public void setMatrix(float dsdx, float dtdx, float dtdy, float dsdy) {
         checkNotReleased();
-        nativeSetMatrix(mNativeObject, dsdx, dtdx, dtdy, dsdy);
+        synchronized(SurfaceControl.class) {
+            sGlobalTransaction.setMatrix(this, dsdx, dtdx, dtdy, dsdy);
+        }
     }
 
     public void setWindowCrop(Rect crop) {
         checkNotReleased();
-        if (crop != null) {
-            nativeSetWindowCrop(mNativeObject,
-                crop.left, crop.top, crop.right, crop.bottom);
-        } else {
-            nativeSetWindowCrop(mNativeObject, 0, 0, 0, 0);
+        synchronized (SurfaceControl.class) {
+            sGlobalTransaction.setWindowCrop(this, crop);
         }
     }
 
     public void setFinalCrop(Rect crop) {
         checkNotReleased();
-        if (crop != null) {
-            nativeSetFinalCrop(mNativeObject,
-                crop.left, crop.top, crop.right, crop.bottom);
-        } else {
-            nativeSetFinalCrop(mNativeObject, 0, 0, 0, 0);
+        synchronized (SurfaceControl.class) {
+            sGlobalTransaction.setFinalCrop(this, crop);
         }
     }
 
     public void setLayerStack(int layerStack) {
         checkNotReleased();
-        nativeSetLayerStack(mNativeObject, layerStack);
+        synchronized(SurfaceControl.class) {
+            sGlobalTransaction.setLayerStack(this, layerStack);
+        }
     }
 
-    /**
-     * Sets the opacity of the surface.  Setting the flag is equivalent to creating the
-     * Surface with the {@link #OPAQUE} flag.
-     */
     public void setOpaque(boolean isOpaque) {
         checkNotReleased();
-        if (isOpaque) {
-            nativeSetFlags(mNativeObject, SURFACE_OPAQUE, SURFACE_OPAQUE);
-        } else {
-            nativeSetFlags(mNativeObject, 0, SURFACE_OPAQUE);
+
+        synchronized (SurfaceControl.class) {
+            sGlobalTransaction.setOpaque(this, isOpaque);
         }
     }
 
-    /**
-     * Sets the security of the surface.  Setting the flag is equivalent to creating the
-     * Surface with the {@link #SECURE} flag.
-     */
     public void setSecure(boolean isSecure) {
         checkNotReleased();
-        if (isSecure) {
-            nativeSetFlags(mNativeObject, SECURE, SECURE);
-        } else {
-            nativeSetFlags(mNativeObject, 0, SECURE);
+
+        synchronized (SurfaceControl.class) {
+            sGlobalTransaction.setSecure(this, isSecure);
         }
     }
 
+    @Override
+    public String toString() {
+        return "Surface(name=" + mName + ")/@0x" +
+                Integer.toHexString(System.identityHashCode(this));
+    }
+
     /*
      * set display parameters.
      * needs to be inside open/closeTransaction block
@@ -741,50 +786,28 @@
 
     public static void setDisplayProjection(IBinder displayToken,
             int orientation, Rect layerStackRect, Rect displayRect) {
-        if (displayToken == null) {
-            throw new IllegalArgumentException("displayToken must not be null");
+        synchronized (SurfaceControl.class) {
+            sGlobalTransaction.setDisplayProjection(displayToken, orientation,
+                    layerStackRect, displayRect);
         }
-        if (layerStackRect == null) {
-            throw new IllegalArgumentException("layerStackRect must not be null");
-        }
-        if (displayRect == null) {
-            throw new IllegalArgumentException("displayRect must not be null");
-        }
-        nativeSetDisplayProjection(displayToken, orientation,
-                layerStackRect.left, layerStackRect.top, layerStackRect.right, layerStackRect.bottom,
-                displayRect.left, displayRect.top, displayRect.right, displayRect.bottom);
     }
 
     public static void setDisplayLayerStack(IBinder displayToken, int layerStack) {
-        if (displayToken == null) {
-            throw new IllegalArgumentException("displayToken must not be null");
+        synchronized (SurfaceControl.class) {
+            sGlobalTransaction.setDisplayLayerStack(displayToken, layerStack);
         }
-        nativeSetDisplayLayerStack(displayToken, layerStack);
     }
 
     public static void setDisplaySurface(IBinder displayToken, Surface surface) {
-        if (displayToken == null) {
-            throw new IllegalArgumentException("displayToken must not be null");
-        }
-
-        if (surface != null) {
-            synchronized (surface.mLock) {
-                nativeSetDisplaySurface(displayToken, surface.mNativeObject);
-            }
-        } else {
-            nativeSetDisplaySurface(displayToken, 0);
+        synchronized (SurfaceControl.class) {
+            sGlobalTransaction.setDisplaySurface(displayToken, surface);
         }
     }
 
     public static void setDisplaySize(IBinder displayToken, int width, int height) {
-        if (displayToken == null) {
-            throw new IllegalArgumentException("displayToken must not be null");
+        synchronized (SurfaceControl.class) {
+            sGlobalTransaction.setDisplaySize(displayToken, width, height);
         }
-        if (width <= 0 || height <= 0) {
-            throw new IllegalArgumentException("width and height must be positive");
-        }
-
-        nativeSetDisplaySize(displayToken, width, height);
     }
 
     public static Display.HdrCapabilities getHdrCapabilities(IBinder displayToken) {
@@ -946,4 +969,261 @@
         nativeScreenshot(display, consumer, sourceCrop, width, height,
                 minLayer, maxLayer, allLayers, useIdentityTransform);
     }
+
+    public static class Transaction implements Closeable {
+        public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
+                Transaction.class.getClassLoader(),
+                nativeGetNativeTransactionFinalizer(), 512);
+        private long mNativeObject;
+
+        Runnable mFreeNativeResources;
+
+        public Transaction() {
+            mNativeObject = nativeCreateTransaction();
+            mFreeNativeResources
+                = sRegistry.registerNativeAllocation(this, mNativeObject);
+        }
+
+        /**
+         * Apply the transaction, clearing it's state, and making it usable
+         * as a new transaction.
+         */
+        public void apply() {
+            apply(false);
+        }
+
+        /**
+         * Close the transaction, if the transaction was not already applied this will cancel the
+         * transaction.
+         */
+        @Override
+        public void close() {
+            mFreeNativeResources.run();
+            mNativeObject = 0;
+        }
+
+        /**
+         * Jankier version of apply. Avoid use (b/28068298).
+         */
+        public void apply(boolean sync) {
+            nativeApplyTransaction(mNativeObject, sync);
+        }
+
+        public Transaction show(SurfaceControl sc) {
+            nativeSetFlags(mNativeObject, sc.mNativeObject, 0, SURFACE_HIDDEN);
+            return this;
+        }
+
+        public Transaction hide(SurfaceControl sc) {
+            nativeSetFlags(mNativeObject, sc.mNativeObject, SURFACE_HIDDEN, SURFACE_HIDDEN);
+            return this;
+        }
+
+        public Transaction setPosition(SurfaceControl sc, float x, float y) {
+            nativeSetPosition(mNativeObject, sc.mNativeObject, x, y);
+            return this;
+        }
+
+        public Transaction setSize(SurfaceControl sc, int w, int h) {
+            nativeSetSize(mNativeObject, sc.mNativeObject,
+                    w, h);
+            return this;
+        }
+
+        public Transaction setLayer(SurfaceControl sc, int z) {
+            nativeSetLayer(mNativeObject, sc.mNativeObject, z);
+            return this;
+        }
+
+        public Transaction setRelativeLayer(SurfaceControl sc, IBinder relativeTo, int z) {
+            nativeSetRelativeLayer(mNativeObject, sc.mNativeObject,
+                    relativeTo, z);
+            return this;
+        }
+
+        public Transaction setTransparentRegionHint(SurfaceControl sc, Region transparentRegion) {
+            nativeSetTransparentRegionHint(mNativeObject,
+                    sc.mNativeObject, transparentRegion);
+            return this;
+        }
+
+        public Transaction setAlpha(SurfaceControl sc, float alpha) {
+            nativeSetAlpha(mNativeObject, sc.mNativeObject, alpha);
+            return this;
+        }
+
+        public Transaction setMatrix(SurfaceControl sc,
+                float dsdx, float dtdx, float dtdy, float dsdy) {
+            nativeSetMatrix(mNativeObject, sc.mNativeObject,
+                    dsdx, dtdx, dtdy, dsdy);
+            return this;
+        }
+
+        public Transaction setWindowCrop(SurfaceControl sc, Rect crop) {
+            if (crop != null) {
+                nativeSetWindowCrop(mNativeObject, sc.mNativeObject,
+                        crop.left, crop.top, crop.right, crop.bottom);
+            } else {
+                nativeSetWindowCrop(mNativeObject, sc.mNativeObject, 0, 0, 0, 0);
+            }
+
+            return this;
+        }
+
+        public Transaction setFinalCrop(SurfaceControl sc, Rect crop) {
+            if (crop != null) {
+                nativeSetFinalCrop(mNativeObject, sc.mNativeObject,
+                        crop.left, crop.top, crop.right, crop.bottom);
+            } else {
+                nativeSetFinalCrop(mNativeObject, sc.mNativeObject, 0, 0, 0, 0);
+            }
+
+            return this;
+        }
+
+        public Transaction setLayerStack(SurfaceControl sc, int layerStack) {
+            nativeSetLayerStack(mNativeObject, sc.mNativeObject, layerStack);
+            return this;
+        }
+
+        public Transaction deferTransactionUntil(SurfaceControl sc, IBinder handle, long frameNumber) {
+            nativeDeferTransactionUntil(mNativeObject, sc.mNativeObject, handle, frameNumber);
+            return this;
+        }
+
+        public Transaction deferTransactionUntilSurface(SurfaceControl sc, Surface barrierSurface,
+                long frameNumber) {
+            nativeDeferTransactionUntilSurface(mNativeObject, sc.mNativeObject,
+                    barrierSurface.mNativeObject, frameNumber);
+            return this;
+        }
+
+        public Transaction reparentChildren(SurfaceControl sc, IBinder newParentHandle) {
+            nativeReparentChildren(mNativeObject, sc.mNativeObject, newParentHandle);
+            return this;
+        }
+
+        /** Re-parents a specific child layer to a new parent */
+        public Transaction reparent(SurfaceControl sc, IBinder newParentHandle) {
+            nativeReparent(mNativeObject, sc.mNativeObject,
+                    newParentHandle);
+            return this;
+        }
+
+        public Transaction detachChildren(SurfaceControl sc) {
+            nativeSeverChildren(mNativeObject, sc.mNativeObject);
+            return this;
+        }
+
+        public Transaction setOverrideScalingMode(SurfaceControl sc, int overrideScalingMode) {
+            nativeSetOverrideScalingMode(mNativeObject, sc.mNativeObject,
+                    overrideScalingMode);
+            return this;
+        }
+
+        /**
+         * Sets a color for the Surface.
+         * @param color A float array with three values to represent r, g, b in range [0..1]
+         */
+        public Transaction setColor(SurfaceControl sc, @Size(3) float[] color) {
+            nativeSetColor(mNativeObject, sc.mNativeObject, color);
+            return this;
+        }
+
+        /**
+         * If the buffer size changes in this transaction, position and crop updates specified
+         * in this transaction will not complete until a buffer of the new size
+         * arrives. As transform matrix and size are already frozen in this fashion,
+         * this enables totally freezing the surface until the resize has completed
+         * (at which point the geometry influencing aspects of this transaction will then occur)
+         */
+        public Transaction setGeometryAppliesWithResize(SurfaceControl sc) {
+            nativeSetGeometryAppliesWithResize(mNativeObject, sc.mNativeObject);
+            return this;
+        }
+
+        /**
+         * Sets the security of the surface.  Setting the flag is equivalent to creating the
+         * Surface with the {@link #SECURE} flag.
+         */
+        Transaction setSecure(SurfaceControl sc, boolean isSecure) {
+            if (isSecure) {
+                nativeSetFlags(mNativeObject, sc.mNativeObject, SECURE, SECURE);
+            } else {
+                nativeSetFlags(mNativeObject, sc.mNativeObject, 0, SECURE);
+            }
+            return this;
+        }
+
+        /**
+         * Sets the opacity of the surface.  Setting the flag is equivalent to creating the
+         * Surface with the {@link #OPAQUE} flag.
+         */
+        public Transaction setOpaque(SurfaceControl sc, boolean isOpaque) {
+            if (isOpaque) {
+                nativeSetFlags(mNativeObject, sc.mNativeObject, SURFACE_OPAQUE, SURFACE_OPAQUE);
+            } else {
+                nativeSetFlags(mNativeObject, sc.mNativeObject, 0, SURFACE_OPAQUE);
+            }
+            return this;
+        }
+
+        public Transaction setDisplaySurface(IBinder displayToken, Surface surface) {
+            if (displayToken == null) {
+                throw new IllegalArgumentException("displayToken must not be null");
+            }
+
+            if (surface != null) {
+                synchronized (surface.mLock) {
+                    nativeSetDisplaySurface(mNativeObject, displayToken, surface.mNativeObject);
+                }
+            } else {
+                nativeSetDisplaySurface(mNativeObject, displayToken, 0);
+            }
+            return this;
+        }
+
+        public Transaction setDisplayLayerStack(IBinder displayToken, int layerStack) {
+            if (displayToken == null) {
+                throw new IllegalArgumentException("displayToken must not be null");
+            }
+            nativeSetDisplayLayerStack(mNativeObject, displayToken, layerStack);
+            return this;
+        }
+
+        public Transaction setDisplayProjection(IBinder displayToken,
+                int orientation, Rect layerStackRect, Rect displayRect) {
+            if (displayToken == null) {
+                throw new IllegalArgumentException("displayToken must not be null");
+            }
+            if (layerStackRect == null) {
+                throw new IllegalArgumentException("layerStackRect must not be null");
+            }
+            if (displayRect == null) {
+                throw new IllegalArgumentException("displayRect must not be null");
+            }
+            nativeSetDisplayProjection(mNativeObject, displayToken, orientation,
+                    layerStackRect.left, layerStackRect.top, layerStackRect.right, layerStackRect.bottom,
+                    displayRect.left, displayRect.top, displayRect.right, displayRect.bottom);
+            return this;
+        }
+
+        public Transaction setDisplaySize(IBinder displayToken, int width, int height) {
+            if (displayToken == null) {
+                throw new IllegalArgumentException("displayToken must not be null");
+            }
+            if (width <= 0 || height <= 0) {
+                throw new IllegalArgumentException("width and height must be positive");
+            }
+
+            nativeSetDisplaySize(mNativeObject, displayToken, width, height);
+            return this;
+        }
+
+        /** flag the transaction as an animation */
+        public Transaction setAnimationTransaction() {
+            nativeSetAnimationTransaction(mNativeObject);
+            return this;
+        }
+    }
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0d1258d..c043dca 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2342,9 +2342,9 @@
     private static final int PFLAG_HOVERED             = 0x10000000;
 
     /**
-     * no longer needed, should be reused
+     * Flag set by {@link AutofillManager} if it needs to be notified when this view is clicked.
      */
-    private static final int PFLAG_DOES_NOTHING_REUSE_PLEASE = 0x20000000;
+    private static final int PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK = 0x20000000;
 
     /** {@hide} */
     static final int PFLAG_ACTIVATED                   = 0x40000000;
@@ -6397,6 +6397,42 @@
         return null;
     }
 
+    /** @hide */
+    public void setNotifyAutofillManagerOnClick(boolean notify) {
+        if (notify) {
+            mPrivateFlags |= PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK;
+        } else {
+            mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK;
+        }
+    }
+
+    private void notifyAutofillManagerOnClick() {
+        if ((mPrivateFlags & PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK) != 0) {
+            try {
+                getAutofillManager().notifyViewClicked(this);
+            } finally {
+                // Set it to already called so it's not called twice when called by
+                // performClickInternal()
+                mPrivateFlags |= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK;
+            }
+        }
+    }
+
+    /**
+     * Entry point for {@link #performClick()} - other methods on View should call it instead of
+     * {@code performClick()} directly to make sure the autofill manager is notified when
+     * necessary (as subclasses could extend {@code performClick()} without calling the parent's
+     * method).
+     */
+    private boolean performClickInternal() {
+        // Must notify autofill manager before performing the click actions to avoid scenarios where
+        // the app has a click listener that changes the state of views the autofill service might
+        // be interested on.
+        notifyAutofillManagerOnClick();
+
+        return performClick();
+    }
+
     /**
      * Call this view's OnClickListener, if it is defined.  Performs all normal
      * actions associated with clicking: reporting accessibility event, playing
@@ -6405,7 +6441,14 @@
      * @return True there was an assigned OnClickListener that was called, false
      *         otherwise is returned.
      */
+    // NOTE: other methods on View should not call this method directly, but performClickInternal()
+    // instead, to guarantee that the autofill manager is notified when necessary (as subclasses
+    // could extend this method without calling super.performClick()).
     public boolean performClick() {
+        // We still need to call this method to handle the cases where performClick() was called
+        // externally, instead of through performClickInternal()
+        notifyAutofillManagerOnClick();
+
         final boolean result;
         final ListenerInfo li = mListenerInfo;
         if (li != null && li.mOnClickListener != null) {
@@ -11503,7 +11546,7 @@
         switch (action) {
             case AccessibilityNodeInfo.ACTION_CLICK: {
                 if (isClickable()) {
-                    performClick();
+                    performClickInternal();
                     return true;
                 }
             } break;
@@ -12615,7 +12658,7 @@
                     // This is a tap, so remove the longpress check
                     removeLongPressCallback();
                     if (!event.isCanceled()) {
-                        return performClick();
+                        return performClickInternal();
                     }
                 }
             }
@@ -13187,7 +13230,7 @@
                                     mPerformClick = new PerformClick();
                                 }
                                 if (!post(mPerformClick)) {
-                                    performClick();
+                                    performClickInternal();
                                 }
                             }
                         }
@@ -18228,10 +18271,11 @@
      */
     @SuppressWarnings({"UnusedDeclaration"})
     public void outputDirtyFlags(String indent, boolean clear, int clearMask) {
-        Log.d("View", indent + this + "             DIRTY(" + (mPrivateFlags & View.PFLAG_DIRTY_MASK) +
-                ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" +
-                (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) +
-                ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")");
+        Log.d(VIEW_LOG_TAG, indent + this + "             DIRTY("
+                + (mPrivateFlags & View.PFLAG_DIRTY_MASK)
+                + ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID("
+                + (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID)
+                + ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")");
         if (clear) {
             mPrivateFlags &= clearMask;
         }
@@ -20008,7 +20052,7 @@
         boolean changed = false;
 
         if (DBG) {
-            Log.d("View", this + " View.setFrame(" + left + "," + top + ","
+            Log.d(VIEW_LOG_TAG, this + " View.setFrame(" + left + "," + top + ","
                     + right + "," + bottom + ")");
         }
 
@@ -25054,7 +25098,7 @@
     private final class PerformClick implements Runnable {
         @Override
         public void run() {
-            performClick();
+            performClickInternal();
         }
     }
 
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 574137b..4500862 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -84,12 +84,17 @@
 
     /**
      * Defines the duration in milliseconds a user needs to hold down the
-     * appropriate button to bring up the accessibility shortcut (first time) or enable it
-     * (once shortcut is configured).
+     * appropriate button to bring up the accessibility shortcut for the first time
      */
     private static final int A11Y_SHORTCUT_KEY_TIMEOUT = 3000;
 
     /**
+     * Defines the duration in milliseconds a user needs to hold down the
+     * appropriate button to enable the accessibility shortcut once it's configured.
+     */
+    private static final int A11Y_SHORTCUT_KEY_TIMEOUT_AFTER_CONFIRMATION = 1500;
+
+    /**
      * Defines the duration in milliseconds we will wait to see if a touch event
      * is a tap or a scroll. If the user does not move within this interval, it is
      * considered to be a tap.
@@ -851,6 +856,15 @@
     }
 
     /**
+     * @return The amount of time a user needs to press the relevant keys to activate the
+     *   accessibility shortcut after it's confirmed that accessibility shortcut is used.
+     * @hide
+     */
+    public long getAccessibilityShortcutKeyTimeoutAfterConfirmation() {
+        return A11Y_SHORTCUT_KEY_TIMEOUT_AFTER_CONFIRMATION;
+    }
+
+    /**
      * The amount of friction applied to scrolls and flings.
      *
      * @return A scalar dimensionless value representing the coefficient of
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 3426485..afa9413 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -528,84 +528,23 @@
     /** @hide */
     public static void profileViewAndChildren(final View view, BufferedWriter out)
             throws IOException {
-        profileViewAndChildren(view, out, true);
+        RenderNode node = RenderNode.create("ViewDebug", null);
+        profileViewAndChildren(view, node, out, true);
+        node.destroy();
     }
 
-    private static void profileViewAndChildren(final View view, BufferedWriter out, boolean root)
-            throws IOException {
-
+    private static void profileViewAndChildren(View view, RenderNode node, BufferedWriter out,
+            boolean root) throws IOException {
         long durationMeasure =
                 (root || (view.mPrivateFlags & View.PFLAG_MEASURED_DIMENSION_SET) != 0)
-                        ? profileViewOperation(view, new ViewOperation<Void>() {
-                    public Void[] pre() {
-                        forceLayout(view);
-                        return null;
-                    }
-
-                    private void forceLayout(View view) {
-                        view.forceLayout();
-                        if (view instanceof ViewGroup) {
-                            ViewGroup group = (ViewGroup) view;
-                            final int count = group.getChildCount();
-                            for (int i = 0; i < count; i++) {
-                                forceLayout(group.getChildAt(i));
-                            }
-                        }
-                    }
-
-                    public void run(Void... data) {
-                        view.measure(view.mOldWidthMeasureSpec, view.mOldHeightMeasureSpec);
-                    }
-
-                    public void post(Void... data) {
-                    }
-                })
-                        : 0;
+                        ? profileViewMeasure(view) : 0;
         long durationLayout =
                 (root || (view.mPrivateFlags & View.PFLAG_LAYOUT_REQUIRED) != 0)
-                        ? profileViewOperation(view, new ViewOperation<Void>() {
-                    public Void[] pre() {
-                        return null;
-                    }
-
-                    public void run(Void... data) {
-                        view.layout(view.mLeft, view.mTop, view.mRight, view.mBottom);
-                    }
-
-                    public void post(Void... data) {
-                    }
-                }) : 0;
+                        ? profileViewLayout(view) : 0;
         long durationDraw =
                 (root || !view.willNotDraw() || (view.mPrivateFlags & View.PFLAG_DRAWN) != 0)
-                        ? profileViewOperation(view, new ViewOperation<Object>() {
-                    public Object[] pre() {
-                        final DisplayMetrics metrics =
-                                (view != null && view.getResources() != null) ?
-                                        view.getResources().getDisplayMetrics() : null;
-                        final Bitmap bitmap = metrics != null ?
-                                Bitmap.createBitmap(metrics, metrics.widthPixels,
-                                        metrics.heightPixels, Bitmap.Config.RGB_565) : null;
-                        final Canvas canvas = bitmap != null ? new Canvas(bitmap) : null;
-                        return new Object[] {
-                                bitmap, canvas
-                        };
-                    }
+                        ? profileViewDraw(view, node) : 0;
 
-                    public void run(Object... data) {
-                        if (data[1] != null) {
-                            view.draw((Canvas) data[1]);
-                        }
-                    }
-
-                    public void post(Object... data) {
-                        if (data[1] != null) {
-                            ((Canvas) data[1]).setBitmap(null);
-                        }
-                        if (data[0] != null) {
-                            ((Bitmap) data[0]).recycle();
-                        }
-                    }
-                }) : 0;
         out.write(String.valueOf(durationMeasure));
         out.write(' ');
         out.write(String.valueOf(durationLayout));
@@ -616,34 +555,86 @@
             ViewGroup group = (ViewGroup) view;
             final int count = group.getChildCount();
             for (int i = 0; i < count; i++) {
-                profileViewAndChildren(group.getChildAt(i), out, false);
+                profileViewAndChildren(group.getChildAt(i), node, out, false);
             }
         }
     }
 
-    interface ViewOperation<T> {
-        T[] pre();
-        void run(T... data);
-        void post(T... data);
+    private static long profileViewMeasure(final View view) {
+        return profileViewOperation(view, new ViewOperation() {
+            @Override
+            public void pre() {
+                forceLayout(view);
+            }
+
+            private void forceLayout(View view) {
+                view.forceLayout();
+                if (view instanceof ViewGroup) {
+                    ViewGroup group = (ViewGroup) view;
+                    final int count = group.getChildCount();
+                    for (int i = 0; i < count; i++) {
+                        forceLayout(group.getChildAt(i));
+                    }
+                }
+            }
+
+            @Override
+            public void run() {
+                view.measure(view.mOldWidthMeasureSpec, view.mOldHeightMeasureSpec);
+            }
+        });
     }
 
-    private static <T> long profileViewOperation(View view, final ViewOperation<T> operation) {
+    private static long profileViewLayout(View view) {
+        return profileViewOperation(view,
+                () -> view.layout(view.mLeft, view.mTop, view.mRight, view.mBottom));
+    }
+
+    private static long profileViewDraw(View view, RenderNode node) {
+        DisplayMetrics dm = view.getResources().getDisplayMetrics();
+        if (dm == null) {
+            return 0;
+        }
+
+        if (view.isHardwareAccelerated()) {
+            DisplayListCanvas canvas = node.start(dm.widthPixels, dm.heightPixels);
+            try {
+                return profileViewOperation(view, () -> view.draw(canvas));
+            } finally {
+                node.end(canvas);
+            }
+        } else {
+            Bitmap bitmap = Bitmap.createBitmap(
+                    dm, dm.widthPixels, dm.heightPixels, Bitmap.Config.RGB_565);
+            Canvas canvas = new Canvas(bitmap);
+            try {
+                return profileViewOperation(view, () -> view.draw(canvas));
+            } finally {
+                canvas.setBitmap(null);
+                bitmap.recycle();
+            }
+        }
+    }
+
+    interface ViewOperation {
+        default void pre() {}
+
+        void run();
+    }
+
+    private static long profileViewOperation(View view, final ViewOperation operation) {
         final CountDownLatch latch = new CountDownLatch(1);
         final long[] duration = new long[1];
 
-        view.post(new Runnable() {
-            public void run() {
-                try {
-                    T[] data = operation.pre();
-                    long start = Debug.threadCpuTimeNanos();
-                    //noinspection unchecked
-                    operation.run(data);
-                    duration[0] = Debug.threadCpuTimeNanos() - start;
-                    //noinspection unchecked
-                    operation.post(data);
-                } finally {
-                    latch.countDown();
-                }
+        view.post(() -> {
+            try {
+                operation.pre();
+                long start = Debug.threadCpuTimeNanos();
+                //noinspection unchecked
+                operation.run();
+                duration[0] = Debug.threadCpuTimeNanos() - start;
+            } finally {
+                latch.countDown();
             }
         });
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 71106ad..99438d8 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -72,6 +72,7 @@
 import android.util.Log;
 import android.util.MergedConfiguration;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.TimeUtils;
 import android.util.TypedValue;
 import android.view.Surface.OutOfResourcesException;
@@ -1668,8 +1669,6 @@
             host.dispatchAttachedToWindow(mAttachInfo, 0);
             mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
             dispatchApplyInsets(host);
-            //Log.i(mTag, "Screen on initialized: " + attachInfo.mKeepScreenOn);
-
         } else {
             desiredWindowWidth = frame.width();
             desiredWindowHeight = frame.height();
@@ -2827,7 +2826,7 @@
                 try {
                     mWindowDrawCountDown.await();
                 } catch (InterruptedException e) {
-                    Log.e(mTag, "Window redraw count down interruped!");
+                    Log.e(mTag, "Window redraw count down interrupted!");
                 }
                 mWindowDrawCountDown = null;
             }
@@ -2897,8 +2896,6 @@
         final float appScale = mAttachInfo.mApplicationScale;
         final boolean scalingRequired = mAttachInfo.mScalingRequired;
 
-        int resizeAlpha = 0;
-
         final Rect dirty = mDirty;
         if (mSurfaceHolder != null) {
             // The app owns the surface, we won't draw.
@@ -3469,6 +3466,7 @@
     }
 
     void dispatchDetachedFromWindow() {
+        mFirstInputStage.onDetachedFromWindow();
         if (mView != null && mView.mAttachInfo != null) {
             mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
             mView.dispatchDetachedFromWindow();
@@ -3731,266 +3729,273 @@
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-            case MSG_INVALIDATE:
-                ((View) msg.obj).invalidate();
-                break;
-            case MSG_INVALIDATE_RECT:
-                final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
-                info.target.invalidate(info.left, info.top, info.right, info.bottom);
-                info.recycle();
-                break;
-            case MSG_PROCESS_INPUT_EVENTS:
-                mProcessInputEventsScheduled = false;
-                doProcessInputEvents();
-                break;
-            case MSG_DISPATCH_APP_VISIBILITY:
-                handleAppVisibility(msg.arg1 != 0);
-                break;
-            case MSG_DISPATCH_GET_NEW_SURFACE:
-                handleGetNewSurface();
-                break;
-            case MSG_RESIZED: {
-                // Recycled in the fall through...
-                SomeArgs args = (SomeArgs) msg.obj;
-                if (mWinFrame.equals(args.arg1)
-                        && mPendingOverscanInsets.equals(args.arg5)
-                        && mPendingContentInsets.equals(args.arg2)
-                        && mPendingStableInsets.equals(args.arg6)
-                        && mPendingVisibleInsets.equals(args.arg3)
-                        && mPendingOutsets.equals(args.arg7)
-                        && mPendingBackDropFrame.equals(args.arg8)
-                        && args.arg4 == null
-                        && args.argi1 == 0
-                        && mDisplay.getDisplayId() == args.argi3) {
+                case MSG_INVALIDATE:
+                    ((View) msg.obj).invalidate();
                     break;
-                }
-                } // fall through...
-            case MSG_RESIZED_REPORT:
-                if (mAdded) {
+                case MSG_INVALIDATE_RECT:
+                    final View.AttachInfo.InvalidateInfo info =
+                            (View.AttachInfo.InvalidateInfo) msg.obj;
+                    info.target.invalidate(info.left, info.top, info.right, info.bottom);
+                    info.recycle();
+                    break;
+                case MSG_PROCESS_INPUT_EVENTS:
+                    mProcessInputEventsScheduled = false;
+                    doProcessInputEvents();
+                    break;
+                case MSG_DISPATCH_APP_VISIBILITY:
+                    handleAppVisibility(msg.arg1 != 0);
+                    break;
+                case MSG_DISPATCH_GET_NEW_SURFACE:
+                    handleGetNewSurface();
+                    break;
+                case MSG_RESIZED: {
+                    // Recycled in the fall through...
                     SomeArgs args = (SomeArgs) msg.obj;
-
-                    final int displayId = args.argi3;
-                    MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg4;
-                    final boolean displayChanged = mDisplay.getDisplayId() != displayId;
-
-                    if (!mLastReportedMergedConfiguration.equals(mergedConfiguration)) {
-                        // If configuration changed - notify about that and, maybe, about move to
-                        // display.
-                        performConfigurationChange(mergedConfiguration, false /* force */,
-                                displayChanged ? displayId : INVALID_DISPLAY /* same display */);
-                    } else if (displayChanged) {
-                        // Moved to display without config change - report last applied one.
-                        onMovedToDisplay(displayId, mLastConfigurationFromResources);
+                    if (mWinFrame.equals(args.arg1)
+                            && mPendingOverscanInsets.equals(args.arg5)
+                            && mPendingContentInsets.equals(args.arg2)
+                            && mPendingStableInsets.equals(args.arg6)
+                            && mPendingVisibleInsets.equals(args.arg3)
+                            && mPendingOutsets.equals(args.arg7)
+                            && mPendingBackDropFrame.equals(args.arg8)
+                            && args.arg4 == null
+                            && args.argi1 == 0
+                            && mDisplay.getDisplayId() == args.argi3) {
+                        break;
                     }
+                } // fall through...
+                case MSG_RESIZED_REPORT:
+                    if (mAdded) {
+                        SomeArgs args = (SomeArgs) msg.obj;
 
-                    final boolean framesChanged = !mWinFrame.equals(args.arg1)
-                            || !mPendingOverscanInsets.equals(args.arg5)
-                            || !mPendingContentInsets.equals(args.arg2)
-                            || !mPendingStableInsets.equals(args.arg6)
-                            || !mPendingVisibleInsets.equals(args.arg3)
-                            || !mPendingOutsets.equals(args.arg7);
+                        final int displayId = args.argi3;
+                        MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg4;
+                        final boolean displayChanged = mDisplay.getDisplayId() != displayId;
 
-                    mWinFrame.set((Rect) args.arg1);
-                    mPendingOverscanInsets.set((Rect) args.arg5);
-                    mPendingContentInsets.set((Rect) args.arg2);
-                    mPendingStableInsets.set((Rect) args.arg6);
-                    mPendingVisibleInsets.set((Rect) args.arg3);
-                    mPendingOutsets.set((Rect) args.arg7);
-                    mPendingBackDropFrame.set((Rect) args.arg8);
-                    mForceNextWindowRelayout = args.argi1 != 0;
-                    mPendingAlwaysConsumeNavBar = args.argi2 != 0;
+                        if (!mLastReportedMergedConfiguration.equals(mergedConfiguration)) {
+                            // If configuration changed - notify about that and, maybe,
+                            // about move to display.
+                            performConfigurationChange(mergedConfiguration, false /* force */,
+                                    displayChanged
+                                            ? displayId : INVALID_DISPLAY /* same display */);
+                        } else if (displayChanged) {
+                            // Moved to display without config change - report last applied one.
+                            onMovedToDisplay(displayId, mLastConfigurationFromResources);
+                        }
 
-                    args.recycle();
+                        final boolean framesChanged = !mWinFrame.equals(args.arg1)
+                                || !mPendingOverscanInsets.equals(args.arg5)
+                                || !mPendingContentInsets.equals(args.arg2)
+                                || !mPendingStableInsets.equals(args.arg6)
+                                || !mPendingVisibleInsets.equals(args.arg3)
+                                || !mPendingOutsets.equals(args.arg7);
 
-                    if (msg.what == MSG_RESIZED_REPORT) {
-                        reportNextDraw();
+                        mWinFrame.set((Rect) args.arg1);
+                        mPendingOverscanInsets.set((Rect) args.arg5);
+                        mPendingContentInsets.set((Rect) args.arg2);
+                        mPendingStableInsets.set((Rect) args.arg6);
+                        mPendingVisibleInsets.set((Rect) args.arg3);
+                        mPendingOutsets.set((Rect) args.arg7);
+                        mPendingBackDropFrame.set((Rect) args.arg8);
+                        mForceNextWindowRelayout = args.argi1 != 0;
+                        mPendingAlwaysConsumeNavBar = args.argi2 != 0;
+
+                        args.recycle();
+
+                        if (msg.what == MSG_RESIZED_REPORT) {
+                            reportNextDraw();
+                        }
+
+                        if (mView != null && framesChanged) {
+                            forceLayout(mView);
+                        }
+                        requestLayout();
                     }
+                    break;
+                case MSG_WINDOW_MOVED:
+                    if (mAdded) {
+                        final int w = mWinFrame.width();
+                        final int h = mWinFrame.height();
+                        final int l = msg.arg1;
+                        final int t = msg.arg2;
+                        mWinFrame.left = l;
+                        mWinFrame.right = l + w;
+                        mWinFrame.top = t;
+                        mWinFrame.bottom = t + h;
 
-                    if (mView != null && framesChanged) {
-                        forceLayout(mView);
+                        mPendingBackDropFrame.set(mWinFrame);
+                        maybeHandleWindowMove(mWinFrame);
                     }
-                    requestLayout();
-                }
-                break;
-            case MSG_WINDOW_MOVED:
-                if (mAdded) {
-                    final int w = mWinFrame.width();
-                    final int h = mWinFrame.height();
-                    final int l = msg.arg1;
-                    final int t = msg.arg2;
-                    mWinFrame.left = l;
-                    mWinFrame.right = l + w;
-                    mWinFrame.top = t;
-                    mWinFrame.bottom = t + h;
+                    break;
+                case MSG_WINDOW_FOCUS_CHANGED: {
+                    final boolean hasWindowFocus = msg.arg1 != 0;
+                    if (mAdded) {
+                        mAttachInfo.mHasWindowFocus = hasWindowFocus;
 
-                    mPendingBackDropFrame.set(mWinFrame);
-                    maybeHandleWindowMove(mWinFrame);
-                }
-                break;
-            case MSG_WINDOW_FOCUS_CHANGED: {
-                if (mAdded) {
-                    boolean hasWindowFocus = msg.arg1 != 0;
-                    mAttachInfo.mHasWindowFocus = hasWindowFocus;
+                        profileRendering(hasWindowFocus);
 
-                    profileRendering(hasWindowFocus);
-
-                    if (hasWindowFocus) {
-                        boolean inTouchMode = msg.arg2 != 0;
-                        ensureTouchModeLocally(inTouchMode);
-
-                        if (mAttachInfo.mThreadedRenderer != null && mSurface.isValid()){
-                            mFullRedrawNeeded = true;
-                            try {
-                                final WindowManager.LayoutParams lp = mWindowAttributes;
-                                final Rect surfaceInsets = lp != null ? lp.surfaceInsets : null;
-                                mAttachInfo.mThreadedRenderer.initializeIfNeeded(
-                                        mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
-                            } catch (OutOfResourcesException e) {
-                                Log.e(mTag, "OutOfResourcesException locking surface", e);
+                        if (hasWindowFocus) {
+                            boolean inTouchMode = msg.arg2 != 0;
+                            ensureTouchModeLocally(inTouchMode);
+                            if (mAttachInfo.mThreadedRenderer != null && mSurface.isValid()) {
+                                mFullRedrawNeeded = true;
                                 try {
-                                    if (!mWindowSession.outOfMemory(mWindow)) {
-                                        Slog.w(mTag, "No processes killed for memory; killing self");
-                                        Process.killProcess(Process.myPid());
+                                    final WindowManager.LayoutParams lp = mWindowAttributes;
+                                    final Rect surfaceInsets = lp != null ? lp.surfaceInsets : null;
+                                    mAttachInfo.mThreadedRenderer.initializeIfNeeded(
+                                            mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
+                                } catch (OutOfResourcesException e) {
+                                    Log.e(mTag, "OutOfResourcesException locking surface", e);
+                                    try {
+                                        if (!mWindowSession.outOfMemory(mWindow)) {
+                                            Slog.w(mTag, "No processes killed for memory;"
+                                                    + " killing self");
+                                            Process.killProcess(Process.myPid());
+                                        }
+                                    } catch (RemoteException ex) {
                                     }
-                                } catch (RemoteException ex) {
+                                    // Retry in a bit.
+                                    sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2),
+                                            500);
+                                    return;
                                 }
-                                // Retry in a bit.
-                                sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
-                                return;
+                            }
+                        }
+
+                        mLastWasImTarget = WindowManager.LayoutParams
+                                .mayUseInputMethod(mWindowAttributes.flags);
+
+                        InputMethodManager imm = InputMethodManager.peekInstance();
+                        if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
+                            imm.onPreWindowFocus(mView, hasWindowFocus);
+                        }
+                        if (mView != null) {
+                            mAttachInfo.mKeyDispatchState.reset();
+                            mView.dispatchWindowFocusChanged(hasWindowFocus);
+                            mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
+
+                            if (mAttachInfo.mTooltipHost != null) {
+                                mAttachInfo.mTooltipHost.hideTooltip();
+                            }
+                        }
+
+                        // Note: must be done after the focus change callbacks,
+                        // so all of the view state is set up correctly.
+                        if (hasWindowFocus) {
+                            if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
+                                imm.onPostWindowFocus(mView, mView.findFocus(),
+                                        mWindowAttributes.softInputMode,
+                                        !mHasHadWindowFocus, mWindowAttributes.flags);
+                            }
+                            // Clear the forward bit.  We can just do this directly, since
+                            // the window manager doesn't care about it.
+                            mWindowAttributes.softInputMode &=
+                                    ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
+                            ((WindowManager.LayoutParams) mView.getLayoutParams())
+                                    .softInputMode &=
+                                        ~WindowManager.LayoutParams
+                                                .SOFT_INPUT_IS_FORWARD_NAVIGATION;
+                            mHasHadWindowFocus = true;
+                        } else {
+                            if (mPointerCapture) {
+                                handlePointerCaptureChanged(false);
                             }
                         }
                     }
-
-                    mLastWasImTarget = WindowManager.LayoutParams
-                            .mayUseInputMethod(mWindowAttributes.flags);
-
+                    mFirstInputStage.onWindowFocusChanged(hasWindowFocus);
+                } break;
+                case MSG_DIE:
+                    doDie();
+                    break;
+                case MSG_DISPATCH_INPUT_EVENT: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    InputEvent event = (InputEvent) args.arg1;
+                    InputEventReceiver receiver = (InputEventReceiver) args.arg2;
+                    enqueueInputEvent(event, receiver, 0, true);
+                    args.recycle();
+                } break;
+                case MSG_SYNTHESIZE_INPUT_EVENT: {
+                    InputEvent event = (InputEvent) msg.obj;
+                    enqueueInputEvent(event, null, QueuedInputEvent.FLAG_UNHANDLED, true);
+                } break;
+                case MSG_DISPATCH_KEY_FROM_IME: {
+                    if (LOCAL_LOGV) {
+                        Log.v(TAG, "Dispatching key " + msg.obj + " from IME to " + mView);
+                    }
+                    KeyEvent event = (KeyEvent) msg.obj;
+                    if ((event.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) != 0) {
+                        // The IME is trying to say this event is from the
+                        // system!  Bad bad bad!
+                        //noinspection UnusedAssignment
+                        event = KeyEvent.changeFlags(event,
+                                event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
+                    }
+                    enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
+                } break;
+                case MSG_CHECK_FOCUS: {
                     InputMethodManager imm = InputMethodManager.peekInstance();
-                    if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
-                        imm.onPreWindowFocus(mView, hasWindowFocus);
+                    if (imm != null) {
+                        imm.checkFocus();
                     }
+                } break;
+                case MSG_CLOSE_SYSTEM_DIALOGS: {
                     if (mView != null) {
-                        mAttachInfo.mKeyDispatchState.reset();
-                        mView.dispatchWindowFocusChanged(hasWindowFocus);
-                        mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
-
-                        if (mAttachInfo.mTooltipHost != null) {
-                            mAttachInfo.mTooltipHost.hideTooltip();
-                        }
+                        mView.onCloseSystemDialogs((String) msg.obj);
+                    }
+                } break;
+                case MSG_DISPATCH_DRAG_EVENT: {
+                } // fall through
+                case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
+                    DragEvent event = (DragEvent) msg.obj;
+                    // only present when this app called startDrag()
+                    event.mLocalState = mLocalDragState;
+                    handleDragEvent(event);
+                } break;
+                case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
+                    handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj);
+                } break;
+                case MSG_UPDATE_CONFIGURATION: {
+                    Configuration config = (Configuration) msg.obj;
+                    if (config.isOtherSeqNewer(
+                            mLastReportedMergedConfiguration.getMergedConfiguration())) {
+                        // If we already have a newer merged config applied - use its global part.
+                        config = mLastReportedMergedConfiguration.getGlobalConfiguration();
                     }
 
-                    // Note: must be done after the focus change callbacks,
-                    // so all of the view state is set up correctly.
-                    if (hasWindowFocus) {
-                        if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
-                            imm.onPostWindowFocus(mView, mView.findFocus(),
-                                    mWindowAttributes.softInputMode,
-                                    !mHasHadWindowFocus, mWindowAttributes.flags);
-                        }
-                        // Clear the forward bit.  We can just do this directly, since
-                        // the window manager doesn't care about it.
-                        mWindowAttributes.softInputMode &=
-                                ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
-                        ((WindowManager.LayoutParams)mView.getLayoutParams())
-                                .softInputMode &=
-                                    ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
-                        mHasHadWindowFocus = true;
-                    } else {
-                        if (mPointerCapture) {
-                            handlePointerCaptureChanged(false);
-                        }
+                    // Use the newer global config and last reported override config.
+                    mPendingMergedConfiguration.setConfiguration(config,
+                            mLastReportedMergedConfiguration.getOverrideConfiguration());
+
+                    performConfigurationChange(mPendingMergedConfiguration, false /* force */,
+                            INVALID_DISPLAY /* same display */);
+                } break;
+                case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
+                    setAccessibilityFocus(null, null);
+                } break;
+                case MSG_INVALIDATE_WORLD: {
+                    if (mView != null) {
+                        invalidateWorld(mView);
                     }
-                }
-            } break;
-            case MSG_DIE:
-                doDie();
-                break;
-            case MSG_DISPATCH_INPUT_EVENT: {
-                SomeArgs args = (SomeArgs)msg.obj;
-                InputEvent event = (InputEvent)args.arg1;
-                InputEventReceiver receiver = (InputEventReceiver)args.arg2;
-                enqueueInputEvent(event, receiver, 0, true);
-                args.recycle();
-            } break;
-            case MSG_SYNTHESIZE_INPUT_EVENT: {
-                InputEvent event = (InputEvent)msg.obj;
-                enqueueInputEvent(event, null, QueuedInputEvent.FLAG_UNHANDLED, true);
-            } break;
-            case MSG_DISPATCH_KEY_FROM_IME: {
-                if (LOCAL_LOGV) Log.v(
-                    TAG, "Dispatching key "
-                    + msg.obj + " from IME to " + mView);
-                KeyEvent event = (KeyEvent)msg.obj;
-                if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
-                    // The IME is trying to say this event is from the
-                    // system!  Bad bad bad!
-                    //noinspection UnusedAssignment
-                    event = KeyEvent.changeFlags(event, event.getFlags() &
-                            ~KeyEvent.FLAG_FROM_SYSTEM);
-                }
-                enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
-            } break;
-            case MSG_CHECK_FOCUS: {
-                InputMethodManager imm = InputMethodManager.peekInstance();
-                if (imm != null) {
-                    imm.checkFocus();
-                }
-            } break;
-            case MSG_CLOSE_SYSTEM_DIALOGS: {
-                if (mView != null) {
-                    mView.onCloseSystemDialogs((String)msg.obj);
-                }
-            } break;
-            case MSG_DISPATCH_DRAG_EVENT:
-            case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
-                DragEvent event = (DragEvent)msg.obj;
-                event.mLocalState = mLocalDragState;    // only present when this app called startDrag()
-                handleDragEvent(event);
-            } break;
-            case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
-                handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj);
-            } break;
-            case MSG_UPDATE_CONFIGURATION: {
-                Configuration config = (Configuration) msg.obj;
-                if (config.isOtherSeqNewer(
-                        mLastReportedMergedConfiguration.getMergedConfiguration())) {
-                    // If we already have a newer merged config applied - use its global part.
-                    config = mLastReportedMergedConfiguration.getGlobalConfiguration();
-                }
-
-                // Use the newer global config and last reported override config.
-                mPendingMergedConfiguration.setConfiguration(config,
-                        mLastReportedMergedConfiguration.getOverrideConfiguration());
-
-                performConfigurationChange(mPendingMergedConfiguration, false /* force */,
-                        INVALID_DISPLAY /* same display */);
-            } break;
-            case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
-                setAccessibilityFocus(null, null);
-            } break;
-            case MSG_INVALIDATE_WORLD: {
-                if (mView != null) {
-                    invalidateWorld(mView);
-                }
-            } break;
-            case MSG_DISPATCH_WINDOW_SHOWN: {
-                handleDispatchWindowShown();
-            } break;
-            case MSG_REQUEST_KEYBOARD_SHORTCUTS: {
-                final IResultReceiver receiver = (IResultReceiver) msg.obj;
-                final int deviceId = msg.arg1;
-                handleRequestKeyboardShortcuts(receiver, deviceId);
-            } break;
-            case MSG_UPDATE_POINTER_ICON: {
-                MotionEvent event = (MotionEvent) msg.obj;
-                resetPointerIcon(event);
-            } break;
-            case MSG_POINTER_CAPTURE_CHANGED: {
-                final boolean hasCapture = msg.arg1 != 0;
-                handlePointerCaptureChanged(hasCapture);
-            } break;
-            case MSG_DRAW_FINISHED: {
-                pendingDrawFinished();
-            } break;
+                } break;
+                case MSG_DISPATCH_WINDOW_SHOWN: {
+                    handleDispatchWindowShown();
+                } break;
+                case MSG_REQUEST_KEYBOARD_SHORTCUTS: {
+                    final IResultReceiver receiver = (IResultReceiver) msg.obj;
+                    final int deviceId = msg.arg1;
+                    handleRequestKeyboardShortcuts(receiver, deviceId);
+                } break;
+                case MSG_UPDATE_POINTER_ICON: {
+                    MotionEvent event = (MotionEvent) msg.obj;
+                    resetPointerIcon(event);
+                } break;
+                case MSG_POINTER_CAPTURE_CHANGED: {
+                    final boolean hasCapture = msg.arg1 != 0;
+                    handlePointerCaptureChanged(hasCapture);
+                } break;
+                case MSG_DRAW_FINISHED: {
+                    pendingDrawFinished();
+                } break;
             }
         }
     }
@@ -4203,6 +4208,18 @@
             }
         }
 
+        protected void onWindowFocusChanged(boolean hasWindowFocus) {
+            if (mNext != null) {
+                mNext.onWindowFocusChanged(hasWindowFocus);
+            }
+        }
+
+        protected void onDetachedFromWindow() {
+            if (mNext != null) {
+                mNext.onDetachedFromWindow();
+            }
+        }
+
         protected boolean shouldDropInputEvent(QueuedInputEvent q) {
             if (mView == null || !mAdded) {
                 Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent);
@@ -4956,9 +4973,9 @@
                     final MotionEvent event = (MotionEvent)q.mEvent;
                     final int source = event.getSource();
                     if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
-                        mTrackball.cancel(event);
+                        mTrackball.cancel();
                     } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
-                        mJoystick.cancel(event);
+                        mJoystick.cancel();
                     } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
                             == InputDevice.SOURCE_TOUCH_NAVIGATION) {
                         mTouchNavigation.cancel(event);
@@ -4967,6 +4984,18 @@
             }
             super.onDeliverToNext(q);
         }
+
+        @Override
+        protected void onWindowFocusChanged(boolean hasWindowFocus) {
+            if (!hasWindowFocus) {
+                mJoystick.cancel();
+            }
+        }
+
+        @Override
+        protected void onDetachedFromWindow() {
+            mJoystick.cancel();
+        }
     }
 
     /**
@@ -5079,7 +5108,7 @@
             }
         }
 
-        public void cancel(MotionEvent event) {
+        public void cancel() {
             mLastTime = Integer.MIN_VALUE;
 
             // If we reach this, we consumed a trackball event.
@@ -5263,14 +5292,11 @@
      * Creates dpad events from unhandled joystick movements.
      */
     final class SyntheticJoystickHandler extends Handler {
-        private final static String TAG = "SyntheticJoystickHandler";
         private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
         private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
 
-        private int mLastXDirection;
-        private int mLastYDirection;
-        private int mLastXKeyCode;
-        private int mLastYKeyCode;
+        private final JoystickAxesState mJoystickAxesState = new JoystickAxesState();
+        private final SparseArray<KeyEvent> mDeviceKeyEvents = new SparseArray<>();
 
         public SyntheticJoystickHandler() {
             super(true);
@@ -5281,11 +5307,10 @@
             switch (msg.what) {
                 case MSG_ENQUEUE_X_AXIS_KEY_REPEAT:
                 case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: {
-                    KeyEvent oldEvent = (KeyEvent)msg.obj;
-                    KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent,
-                            SystemClock.uptimeMillis(),
-                            oldEvent.getRepeatCount() + 1);
                     if (mAttachInfo.mHasWindowFocus) {
+                        KeyEvent oldEvent = (KeyEvent) msg.obj;
+                        KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent,
+                                SystemClock.uptimeMillis(), oldEvent.getRepeatCount() + 1);
                         enqueueInputEvent(e);
                         Message m = obtainMessage(msg.what, e);
                         m.setAsynchronous(true);
@@ -5297,97 +5322,176 @@
 
         public void process(MotionEvent event) {
             switch(event.getActionMasked()) {
-            case MotionEvent.ACTION_CANCEL:
-                cancel(event);
-                break;
-            case MotionEvent.ACTION_MOVE:
-                update(event, true);
-                break;
-            default:
-                Log.w(mTag, "Unexpected action: " + event.getActionMasked());
+                case MotionEvent.ACTION_CANCEL:
+                    cancel();
+                    break;
+                case MotionEvent.ACTION_MOVE:
+                    update(event);
+                    break;
+                default:
+                    Log.w(mTag, "Unexpected action: " + event.getActionMasked());
             }
         }
 
-        private void cancel(MotionEvent event) {
+        private void cancel() {
             removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
             removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
-            update(event, false);
+            for (int i = 0; i < mDeviceKeyEvents.size(); i++) {
+                final KeyEvent keyEvent = mDeviceKeyEvents.valueAt(i);
+                if (keyEvent != null) {
+                    enqueueInputEvent(KeyEvent.changeTimeRepeat(keyEvent,
+                            SystemClock.uptimeMillis(), 0));
+                }
+            }
+            mDeviceKeyEvents.clear();
+            mJoystickAxesState.resetState();
         }
 
-        private void update(MotionEvent event, boolean synthesizeNewKeys) {
+        private void update(MotionEvent event) {
+            final int historySize = event.getHistorySize();
+            for (int h = 0; h < historySize; h++) {
+                final long time = event.getHistoricalEventTime(h);
+                mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X,
+                        event.getHistoricalAxisValue(MotionEvent.AXIS_X, 0, h));
+                mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y,
+                        event.getHistoricalAxisValue(MotionEvent.AXIS_Y, 0, h));
+                mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X,
+                        event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_X, 0, h));
+                mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y,
+                        event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_Y, 0, h));
+            }
             final long time = event.getEventTime();
-            final int metaState = event.getMetaState();
-            final int deviceId = event.getDeviceId();
-            final int source = event.getSource();
-
-            int xDirection = joystickAxisValueToDirection(
+            mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X,
+                    event.getAxisValue(MotionEvent.AXIS_X));
+            mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y,
+                    event.getAxisValue(MotionEvent.AXIS_Y));
+            mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X,
                     event.getAxisValue(MotionEvent.AXIS_HAT_X));
-            if (xDirection == 0) {
-                xDirection = joystickAxisValueToDirection(event.getX());
-            }
-
-            int yDirection = joystickAxisValueToDirection(
+            mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y,
                     event.getAxisValue(MotionEvent.AXIS_HAT_Y));
-            if (yDirection == 0) {
-                yDirection = joystickAxisValueToDirection(event.getY());
-            }
-
-            if (xDirection != mLastXDirection) {
-                if (mLastXKeyCode != 0) {
-                    removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
-                    enqueueInputEvent(new KeyEvent(time, time,
-                            KeyEvent.ACTION_UP, mLastXKeyCode, 0, metaState,
-                            deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
-                    mLastXKeyCode = 0;
-                }
-
-                mLastXDirection = xDirection;
-
-                if (xDirection != 0 && synthesizeNewKeys) {
-                    mLastXKeyCode = xDirection > 0
-                            ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
-                    final KeyEvent e = new KeyEvent(time, time,
-                            KeyEvent.ACTION_DOWN, mLastXKeyCode, 0, metaState,
-                            deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
-                    enqueueInputEvent(e);
-                    Message m = obtainMessage(MSG_ENQUEUE_X_AXIS_KEY_REPEAT, e);
-                    m.setAsynchronous(true);
-                    sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
-                }
-            }
-
-            if (yDirection != mLastYDirection) {
-                if (mLastYKeyCode != 0) {
-                    removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
-                    enqueueInputEvent(new KeyEvent(time, time,
-                            KeyEvent.ACTION_UP, mLastYKeyCode, 0, metaState,
-                            deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
-                    mLastYKeyCode = 0;
-                }
-
-                mLastYDirection = yDirection;
-
-                if (yDirection != 0 && synthesizeNewKeys) {
-                    mLastYKeyCode = yDirection > 0
-                            ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
-                    final KeyEvent e = new KeyEvent(time, time,
-                            KeyEvent.ACTION_DOWN, mLastYKeyCode, 0, metaState,
-                            deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
-                    enqueueInputEvent(e);
-                    Message m = obtainMessage(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT, e);
-                    m.setAsynchronous(true);
-                    sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
-                }
-            }
         }
 
-        private int joystickAxisValueToDirection(float value) {
-            if (value >= 0.5f) {
-                return 1;
-            } else if (value <= -0.5f) {
-                return -1;
-            } else {
-                return 0;
+        final class JoystickAxesState {
+            // State machine: from neutral state (no button press) can go into
+            // button STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state, emitting an ACTION_DOWN event.
+            // From STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state can go into neutral state,
+            // emitting an ACTION_UP event.
+            private static final int STATE_UP_OR_LEFT = -1;
+            private static final int STATE_NEUTRAL = 0;
+            private static final int STATE_DOWN_OR_RIGHT = 1;
+
+            final int[] mAxisStatesHat = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_HAT_X, AXIS_HAT_Y}
+            final int[] mAxisStatesStick = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_X, AXIS_Y}
+
+            void resetState() {
+                mAxisStatesHat[0] = STATE_NEUTRAL;
+                mAxisStatesHat[1] = STATE_NEUTRAL;
+                mAxisStatesStick[0] = STATE_NEUTRAL;
+                mAxisStatesStick[1] = STATE_NEUTRAL;
+            }
+
+            void updateStateForAxis(MotionEvent event, long time, int axis, float value) {
+                // Emit KeyEvent if necessary
+                // axis can be AXIS_X, AXIS_Y, AXIS_HAT_X, AXIS_HAT_Y
+                final int axisStateIndex;
+                final int repeatMessage;
+                if (isXAxis(axis)) {
+                    axisStateIndex = 0;
+                    repeatMessage = MSG_ENQUEUE_X_AXIS_KEY_REPEAT;
+                } else if (isYAxis(axis)) {
+                    axisStateIndex = 1;
+                    repeatMessage = MSG_ENQUEUE_Y_AXIS_KEY_REPEAT;
+                } else {
+                    Log.e(mTag, "Unexpected axis " + axis + " in updateStateForAxis!");
+                    return;
+                }
+                final int newState = joystickAxisValueToState(value);
+
+                final int currentState;
+                if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) {
+                    currentState = mAxisStatesStick[axisStateIndex];
+                } else {
+                    currentState = mAxisStatesHat[axisStateIndex];
+                }
+
+                if (currentState == newState) {
+                    return;
+                }
+
+                final int metaState = event.getMetaState();
+                final int deviceId = event.getDeviceId();
+                final int source = event.getSource();
+
+                if (currentState == STATE_DOWN_OR_RIGHT || currentState == STATE_UP_OR_LEFT) {
+                    // send a button release event
+                    final int keyCode = joystickAxisAndStateToKeycode(axis, currentState);
+                    if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
+                        enqueueInputEvent(new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode,
+                                0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
+                        // remove the corresponding pending UP event if focus lost/view detached
+                        mDeviceKeyEvents.put(deviceId, null);
+                    }
+                    removeMessages(repeatMessage);
+                }
+
+                if (newState == STATE_DOWN_OR_RIGHT || newState == STATE_UP_OR_LEFT) {
+                    // send a button down event
+                    final int keyCode = joystickAxisAndStateToKeycode(axis, newState);
+                    if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
+                        KeyEvent keyEvent = new KeyEvent(time, time, KeyEvent.ACTION_DOWN, keyCode,
+                                0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
+                        enqueueInputEvent(keyEvent);
+                        Message m = obtainMessage(repeatMessage, keyEvent);
+                        m.setAsynchronous(true);
+                        sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
+                        // store the corresponding ACTION_UP event so that it can be sent
+                        // if focus is lost or root view is removed
+                        mDeviceKeyEvents.put(deviceId,
+                                new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode,
+                                        0, metaState, deviceId, 0,
+                                        KeyEvent.FLAG_FALLBACK | KeyEvent.FLAG_CANCELED,
+                                        source));
+                    }
+                }
+                if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) {
+                    mAxisStatesStick[axisStateIndex] = newState;
+                } else {
+                    mAxisStatesHat[axisStateIndex] = newState;
+                }
+            }
+
+            private boolean isXAxis(int axis) {
+                return axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_HAT_X;
+            }
+            private boolean isYAxis(int axis) {
+                return axis == MotionEvent.AXIS_Y || axis == MotionEvent.AXIS_HAT_Y;
+            }
+
+            private int joystickAxisAndStateToKeycode(int axis, int state) {
+                if (isXAxis(axis) && state == STATE_UP_OR_LEFT) {
+                    return KeyEvent.KEYCODE_DPAD_LEFT;
+                }
+                if (isXAxis(axis) && state == STATE_DOWN_OR_RIGHT) {
+                    return KeyEvent.KEYCODE_DPAD_RIGHT;
+                }
+                if (isYAxis(axis) && state == STATE_UP_OR_LEFT) {
+                    return KeyEvent.KEYCODE_DPAD_UP;
+                }
+                if (isYAxis(axis) && state == STATE_DOWN_OR_RIGHT) {
+                    return KeyEvent.KEYCODE_DPAD_DOWN;
+                }
+                Log.e(mTag, "Unknown axis " + axis + " or direction " + state);
+                return KeyEvent.KEYCODE_UNKNOWN; // should never happen
+            }
+
+            private int joystickAxisValueToState(float value) {
+                if (value >= 0.5f) {
+                    return STATE_DOWN_OR_RIGHT;
+                } else if (value <= -0.5f) {
+                    return STATE_UP_OR_LEFT;
+                } else {
+                    return STATE_NEUTRAL;
+                }
             }
         }
     }
@@ -6108,7 +6212,6 @@
             if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
         }
 
-        //Log.d(mTag, ">>>>>> CALLING relayout");
         if (params != null && mOrigWindowType != params.type) {
             // For compatibility with old apps, don't crash here.
             if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
@@ -6129,7 +6232,6 @@
         mPendingAlwaysConsumeNavBar =
                 (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR) != 0;
 
-        //Log.d(mTag, "<<<<<< BACK FROM relayout");
         if (restore) {
             params.restore();
         }
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index f671c34..d665dde 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -365,6 +365,30 @@
     public abstract void setDataIsSensitive(boolean sensitive);
 
     /**
+     * Sets the minimum width in ems of the text associated with this view, when supported.
+     *
+     * <p>Should only be set when the node is used for autofill purposes - it will be ignored
+     * when used for Assist.
+     */
+    public void setMinTextEms(@SuppressWarnings("unused") int minEms) {}
+
+    /**
+     * Sets the maximum width in ems of the text associated with this view, when supported.
+     *
+     * <p>Should only be set when the node is used for autofill purposes - it will be ignored
+     * when used for Assist.
+     */
+    public void setMaxTextEms(@SuppressWarnings("unused") int maxEms) {}
+
+    /**
+     * Sets the maximum length of the text associated with this view, when supported.
+     *
+     * <p>Should only be set when the node is used for autofill purposes - it will be ignored
+     * when used for Assist.
+     */
+    public void setMaxTextLength(@SuppressWarnings("unused") int maxLength) {}
+
+    /**
      * Call when done populating a {@link ViewStructure} returned by
      * {@link #asyncNewChild}.
      */
diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java
index 0f21c5c..d785117 100644
--- a/core/java/android/view/accessibility/AccessibilityCache.java
+++ b/core/java/android/view/accessibility/AccessibilityCache.java
@@ -329,8 +329,6 @@
                 final long oldParentId = oldInfo.getParentNodeId();
                 if (info.getParentNodeId() != oldParentId) {
                     clearSubTreeLocked(windowId, oldParentId);
-                } else {
-                    oldInfo.recycle();
                 }
            }
 
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 4fb2a99..e564fa3 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -91,10 +91,10 @@
  * </ul>
  *
  * <p>When the service returns datasets, the Android System displays an autofill dataset picker
- * UI affordance associated with the view, when the view is focused on and is part of a dataset.
- * The application can be notified when the affordance is shown by registering an
+ * UI associated with the view, when the view is focused on and is part of a dataset.
+ * The application can be notified when the UI is shown by registering an
  * {@link AutofillCallback} through {@link #registerCallback(AutofillCallback)}. When the user
- * selects a dataset from the affordance, all views present in the dataset are autofilled, through
+ * selects a dataset from the UI, all views present in the dataset are autofilled, through
  * calls to {@link View#autofill(AutofillValue)} or {@link View#autofill(SparseArray)}.
  *
  * <p>When the service returns ids of savable views, the Android System keeps track of changes
@@ -108,7 +108,7 @@
  * </ul>
  *
  * <p>Finally, after the autofill context is commited (i.e., not cancelled), the Android System
- * shows a save UI affordance if the value of savable views have changed. If the user selects the
+ * shows an autofill save UI if the value of savable views have changed. If the user selects the
  * option to Save, the current value of the views is then sent to the autofill service.
  *
  * <p>It is safe to call into its methods from any thread.
@@ -150,6 +150,12 @@
      * service authentication will contain the Bundle set by
      * {@link android.service.autofill.FillResponse.Builder#setClientState(Bundle)} on this extra.
      *
+     * <p>On Android {@link android.os.Build.VERSION_CODES#P} and higher, the autofill service
+     * can also add this bundle to the {@link Intent} set as the
+     * {@link android.app.Activity#setResult(int, Intent) result} for an authentication request,
+     * so the bundle can be recovered later on
+     * {@link android.service.autofill.SaveRequest#getClientState()}.
+     *
      * <p>
      * Type: {@link android.os.Bundle}
      */
@@ -311,6 +317,14 @@
     @GuardedBy("mLock")
     @Nullable private ArraySet<AutofillId> mFillableIds;
 
+    /** If set, session is commited when the field is clicked. */
+    @GuardedBy("mLock")
+    @Nullable private AutofillId mSaveTriggerId;
+
+    /** If set, session is commited when the activity is finished; otherwise session is canceled. */
+    @GuardedBy("mLock")
+    private boolean mSaveOnFinish;
+
     /** @hide */
     public interface AutofillClient {
         /**
@@ -834,6 +848,46 @@
         }
     }
 
+
+    /**
+     * Called when a {@link View} is clicked. Currently only used by views that should trigger save.
+     *
+     * @hide
+     */
+    public void notifyViewClicked(View view) {
+        final AutofillId id = view.getAutofillId();
+
+        if (sVerbose) Log.v(TAG, "notifyViewClicked(): id=" + id + ", trigger=" + mSaveTriggerId);
+
+        synchronized (mLock) {
+            if (mSaveTriggerId != null && mSaveTriggerId.equals(id)) {
+                if (sDebug) Log.d(TAG, "triggering commit by click of " + id);
+                commitLocked();
+                mMetricsLogger.action(MetricsEvent.AUTOFILL_SAVE_EXPLICITLY_TRIGGERED,
+                        mContext.getPackageName());
+            }
+        }
+    }
+
+    /**
+     * Called by {@link android.app.Activity} to commit or cancel the session on finish.
+     *
+     * @hide
+     */
+    public void onActivityFinished() {
+        if (!hasAutofillFeature()) {
+            return;
+        }
+        synchronized (mLock) {
+            if (mSaveOnFinish) {
+                commitLocked();
+            } else {
+                if (sDebug) Log.d(TAG, "Cancelling session on finish() as requested by service");
+                cancelLocked();
+            }
+        }
+    }
+
     /**
      * Called to indicate the current autofill context should be commited.
      *
@@ -850,14 +904,17 @@
             return;
         }
         synchronized (mLock) {
-            if (!mEnabled && !isActiveLocked()) {
-                return;
-            }
-
-            finishSessionLocked();
+            commitLocked();
         }
     }
 
+    private void commitLocked() {
+        if (!mEnabled && !isActiveLocked()) {
+            return;
+        }
+        finishSessionLocked();
+    }
+
     /**
      * Called to indicate the current autofill context should be cancelled.
      *
@@ -874,14 +931,17 @@
             return;
         }
         synchronized (mLock) {
-            if (!mEnabled && !isActiveLocked()) {
-                return;
-            }
-
-            cancelSessionLocked();
+            cancelLocked();
         }
     }
 
+    private void cancelLocked() {
+        if (!mEnabled && !isActiveLocked()) {
+            return;
+        }
+        cancelSessionLocked();
+    }
+
     /** @hide */
     public void disableOwnedAutofillServices() {
         disableAutofillServices();
@@ -937,7 +997,12 @@
     }
 
     private AutofillClient getClientLocked() {
-        return mContext.getAutofillClient();
+        final AutofillClient client = mContext.getAutofillClient();
+        if (client == null && sDebug) {
+            Log.d(TAG, "No AutofillClient for " + mContext.getPackageName() + " on context "
+                    + mContext);
+        }
+        return client;
     }
 
     /** @hide */
@@ -959,6 +1024,10 @@
             final Parcelable result = data.getParcelableExtra(EXTRA_AUTHENTICATION_RESULT);
             final Bundle responseData = new Bundle();
             responseData.putParcelable(EXTRA_AUTHENTICATION_RESULT, result);
+            final Bundle newClientState = data.getBundleExtra(EXTRA_CLIENT_STATE);
+            if (newClientState != null) {
+                responseData.putBundle(EXTRA_CLIENT_STATE, newClientState);
+            }
             try {
                 mService.setAuthenticationResult(responseData, mSessionId, authenticationId,
                         mContext.getUserId());
@@ -1038,6 +1107,7 @@
         mState = STATE_UNKNOWN;
         mTrackedViews = null;
         mFillableIds = null;
+        mSaveTriggerId = null;
     }
 
     private void updateSessionLocked(AutofillId id, Rect bounds, AutofillValue value, int action,
@@ -1289,12 +1359,15 @@
     /**
      *  Set the tracked views.
      *
-     * @param trackedIds The views to be tracked
+     * @param trackedIds The views to be tracked.
      * @param saveOnAllViewsInvisible Finish the session once all tracked views are invisible.
+     * @param saveOnFinish Finish the session once the activity is finished.
      * @param fillableIds Views that might anchor FillUI.
+     * @param saveTriggerId View that when clicked triggers commit().
      */
     private void setTrackedViews(int sessionId, @Nullable AutofillId[] trackedIds,
-            boolean saveOnAllViewsInvisible, @Nullable AutofillId[] fillableIds) {
+            boolean saveOnAllViewsInvisible, boolean saveOnFinish,
+            @Nullable AutofillId[] fillableIds, @Nullable AutofillId saveTriggerId) {
         synchronized (mLock) {
             if (mEnabled && mSessionId == sessionId) {
                 if (saveOnAllViewsInvisible) {
@@ -1302,6 +1375,7 @@
                 } else {
                     mTrackedViews = null;
                 }
+                mSaveOnFinish = saveOnFinish;
                 if (fillableIds != null) {
                     if (mFillableIds == null) {
                         mFillableIds = new ArraySet<>(fillableIds.length);
@@ -1314,10 +1388,30 @@
                                 + ", mFillableIds" + mFillableIds);
                     }
                 }
+
+                if (mSaveTriggerId != null && !mSaveTriggerId.equals(saveTriggerId)) {
+                    // Turn off trigger on previous view id.
+                    setNotifyOnClickLocked(mSaveTriggerId, false);
+                }
+
+                if (saveTriggerId != null && !saveTriggerId.equals(mSaveTriggerId)) {
+                    // Turn on trigger on new view id.
+                    mSaveTriggerId = saveTriggerId;
+                    setNotifyOnClickLocked(mSaveTriggerId, true);
+                }
             }
         }
     }
 
+    private void setNotifyOnClickLocked(@NonNull AutofillId id, boolean notify) {
+        final View view = findView(id);
+        if (view == null) {
+            Log.w(TAG, "setNotifyOnClick(): invalid id: " + id);
+            return;
+        }
+        view.setNotifyAutofillManagerOnClick(notify);
+    }
+
     private void setSaveUiState(int sessionId, boolean shown) {
         if (sDebug) Log.d(TAG, "setSaveUiState(" + sessionId + "): " + shown);
         synchronized (mLock) {
@@ -1490,6 +1584,7 @@
         final String pfx = outerPrefix + "  ";
         pw.print(pfx); pw.print("sessionId: "); pw.println(mSessionId);
         pw.print(pfx); pw.print("state: "); pw.println(getStateAsStringLocked());
+        pw.print(pfx); pw.print("context: "); pw.println(mContext);
         pw.print(pfx); pw.print("enabled: "); pw.println(mEnabled);
         pw.print(pfx); pw.print("hasService: "); pw.println(mService != null);
         pw.print(pfx); pw.print("hasCallback: "); pw.println(mCallback != null);
@@ -1504,6 +1599,8 @@
             pw.print(pfx2); pw.print("invisible:"); pw.println(mTrackedViews.mInvisibleTrackedIds);
         }
         pw.print(pfx); pw.print("fillable ids: "); pw.println(mFillableIds);
+        pw.print(pfx); pw.print("save trigger id: "); pw.println(mSaveTriggerId);
+        pw.print(pfx); pw.print("save on finish(): "); pw.println(mSaveOnFinish);
     }
 
     private String getStateAsStringLocked() {
@@ -1752,7 +1849,7 @@
      * Callback for autofill related events.
      *
      * <p>Typically used for applications that display their own "auto-complete" views, so they can
-     * enable / disable such views when the autofill UI affordance is shown / hidden.
+     * enable / disable such views when the autofill UI is shown / hidden.
      */
     public abstract static class AutofillCallback {
 
@@ -1762,26 +1859,26 @@
         public @interface AutofillEventType {}
 
         /**
-         * The autofill input UI affordance associated with the view was shown.
+         * The autofill input UI associated with the view was shown.
          *
-         * <p>If the view provides its own auto-complete UI affordance and its currently shown, it
+         * <p>If the view provides its own auto-complete UI and its currently shown, it
          * should be hidden upon receiving this event.
          */
         public static final int EVENT_INPUT_SHOWN = 1;
 
         /**
-         * The autofill input UI affordance associated with the view was hidden.
+         * The autofill input UI associated with the view was hidden.
          *
-         * <p>If the view provides its own auto-complete UI affordance that was hidden upon a
+         * <p>If the view provides its own auto-complete UI that was hidden upon a
          * {@link #EVENT_INPUT_SHOWN} event, it could be shown again now.
          */
         public static final int EVENT_INPUT_HIDDEN = 2;
 
         /**
-         * The autofill input UI affordance associated with the view isn't shown because
+         * The autofill input UI associated with the view isn't shown because
          * autofill is not available.
          *
-         * <p>If the view provides its own auto-complete UI affordance but was not displaying it
+         * <p>If the view provides its own auto-complete UI but was not displaying it
          * to avoid flickering, it could shown it upon receiving this event.
          */
         public static final int EVENT_INPUT_UNAVAILABLE = 3;
@@ -1883,12 +1980,12 @@
 
         @Override
         public void setTrackedViews(int sessionId, AutofillId[] ids,
-                boolean saveOnAllViewsInvisible, AutofillId[] fillableIds) {
+                boolean saveOnAllViewsInvisible, boolean saveOnFinish, AutofillId[] fillableIds,
+                AutofillId saveTriggerId) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
-                afm.post(() ->
-                        afm.setTrackedViews(sessionId, ids, saveOnAllViewsInvisible, fillableIds)
-                );
+                afm.post(() -> afm.setTrackedViews(sessionId, ids, saveOnAllViewsInvisible,
+                        saveOnFinish, fillableIds, saveTriggerId));
             }
         }
 
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index 3dabcec..56a22c22 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -53,7 +53,8 @@
       * the session is finished automatically.
       */
     void setTrackedViews(int sessionId, in @nullable AutofillId[] savableIds,
-            boolean saveOnAllViewsInvisible, in @nullable AutofillId[] fillableIds);
+            boolean saveOnAllViewsInvisible, boolean saveOnFinish,
+            in @nullable AutofillId[] fillableIds, in AutofillId saveTriggerId);
 
     /**
      * Requests showing the fill UI.
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index 0922422..ab8886b 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -16,6 +16,7 @@
 
 package android.view.inputmethod;
 
+import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
@@ -90,8 +91,9 @@
      * accept the first token given to you.  Any after that may come from the
      * client.
      */
+    @MainThread
     public void attachToken(IBinder token);
-    
+
     /**
      * Bind a new application environment in to the input method, so that it
      * can later start and stop input processing.
@@ -104,6 +106,7 @@
      * @see InputBinding
      * @see #unbindInput()
      */
+    @MainThread
     public void bindInput(InputBinding binding);
 
     /**
@@ -114,6 +117,7 @@
      * Typically this method is called when the application changes to be
      * non-foreground.
      */
+    @MainThread
     public void unbindInput();
 
     /**
@@ -129,6 +133,7 @@
      * 
      * @see EditorInfo
      */
+    @MainThread
     public void startInput(InputConnection inputConnection, EditorInfo info);
 
     /**
@@ -147,6 +152,7 @@
      * 
      * @see EditorInfo
      */
+    @MainThread
     public void restartInput(InputConnection inputConnection, EditorInfo attribute);
 
     /**
@@ -177,6 +183,7 @@
      * @see EditorInfo
      * @hide
      */
+    @MainThread
     default void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
             @NonNull EditorInfo editorInfo, boolean restarting,
             @NonNull IBinder startInputToken) {
@@ -195,6 +202,7 @@
      * 
      * @param callback Interface that is called with the newly created session.
      */
+    @MainThread
     public void createSession(SessionCallback callback);
     
     /**
@@ -203,6 +211,7 @@
      * @param session The {@link InputMethodSession} previously provided through
      * SessionCallback.sessionCreated() that is to be changed.
      */
+    @MainThread
     public void setSessionEnabled(InputMethodSession session, boolean enabled);
     
     /**
@@ -214,6 +223,7 @@
      * @param session The {@link InputMethodSession} previously provided through
      * SessionCallback.sessionCreated() that is to be revoked.
      */
+    @MainThread
     public void revokeSession(InputMethodSession session);
     
     /**
@@ -244,6 +254,7 @@
      * {@link InputMethodManager#RESULT_SHOWN InputMethodManager.RESULT_SHOWN}, or
      * {@link InputMethodManager#RESULT_HIDDEN InputMethodManager.RESULT_HIDDEN}.
      */
+    @MainThread
     public void showSoftInput(int flags, ResultReceiver resultReceiver);
     
     /**
@@ -258,11 +269,13 @@
      * {@link InputMethodManager#RESULT_SHOWN InputMethodManager.RESULT_SHOWN}, or
      * {@link InputMethodManager#RESULT_HIDDEN InputMethodManager.RESULT_HIDDEN}.
      */
+    @MainThread
     public void hideSoftInput(int flags, ResultReceiver resultReceiver);
 
     /**
      * Notify that the input method subtype is being changed in the same input method.
      * @param subtype New subtype of the notified input method
      */
+    @MainThread
     public void changeInputMethodSubtype(InputMethodSubtype subtype);
 }
diff --git a/core/java/android/view/textclassifier/Log.java b/core/java/android/view/textclassifier/Log.java
new file mode 100644
index 0000000..83ca15d
--- /dev/null
+++ b/core/java/android/view/textclassifier/Log.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.textclassifier;
+
+import android.util.Slog;
+
+/**
+ * Logging for android.view.textclassifier package.
+ */
+final class Log {
+
+    /**
+     * true: Enables full logging.
+     * false: Limits logging to debug level.
+     */
+    private static final boolean ENABLE_FULL_LOGGING = false;
+
+    private Log() {}
+
+    public static void d(String tag, String msg) {
+        Slog.d(tag, msg);
+    }
+
+    public static void e(String tag, String msg, Throwable tr) {
+        if (ENABLE_FULL_LOGGING) {
+            Slog.e(tag, msg, tr);
+        } else {
+            final String trString = (tr != null) ? tr.getClass().getSimpleName() : "??";
+            Slog.d(tag, String.format("%s (%s)", msg, trString));
+        }
+    }
+}
diff --git a/core/java/android/view/textclassifier/SmartSelection.java b/core/java/android/view/textclassifier/SmartSelection.java
index f0e83d1..2c93a19 100644
--- a/core/java/android/view/textclassifier/SmartSelection.java
+++ b/core/java/android/view/textclassifier/SmartSelection.java
@@ -16,6 +16,8 @@
 
 package android.view.textclassifier;
 
+import android.content.res.AssetFileDescriptor;
+
 /**
  *  Java wrapper for SmartSelection native library interface.
  *  This library is used for detecting entities in text.
@@ -42,6 +44,26 @@
     }
 
     /**
+     * Creates a new instance of SmartSelect predictor, using the provided model image, given as a
+     * file path.
+     */
+    SmartSelection(String path) {
+        mCtx = nativeNewFromPath(path);
+    }
+
+    /**
+     * Creates a new instance of SmartSelect predictor, using the provided model image, given as an
+     * AssetFileDescriptor.
+     */
+    SmartSelection(AssetFileDescriptor afd) {
+        mCtx = nativeNewFromAssetFileDescriptor(afd, afd.getStartOffset(), afd.getLength());
+        if (mCtx == 0L) {
+            throw new IllegalArgumentException(
+                "Couldn't initialize TC from given AssetFileDescriptor");
+        }
+    }
+
+    /**
      * Given a string context and current selection, computes the SmartSelection suggestion.
      *
      * The begin and end are character indices into the context UTF8 string. selectionBegin is the
@@ -69,6 +91,15 @@
     }
 
     /**
+     * Annotates given input text. Every word of the input is a part of some annotation.
+     * The annotations are sorted by their position in the context string.
+     * The annotations do not overlap.
+     */
+    public AnnotatedSpan[] annotate(String text) {
+        return nativeAnnotate(mCtx, text);
+    }
+
+    /**
      * Frees up the allocated memory.
      */
     public void close() {
@@ -91,12 +122,19 @@
 
     private static native long nativeNew(int fd);
 
+    private static native long nativeNewFromPath(String path);
+
+    private static native long nativeNewFromAssetFileDescriptor(AssetFileDescriptor afd,
+                                                                long offset, long size);
+
     private static native int[] nativeSuggest(
             long context, String text, int selectionBegin, int selectionEnd);
 
     private static native ClassificationResult[] nativeClassifyText(
             long context, String text, int selectionBegin, int selectionEnd, int hintFlags);
 
+    private static native AnnotatedSpan[] nativeAnnotate(long context, String text);
+
     private static native void nativeClose(long context);
 
     private static native String nativeGetLanguage(int fd);
@@ -114,4 +152,29 @@
             mScore = score;
         }
     }
+
+    /** Represents a result of Annotate call. */
+    public static final class AnnotatedSpan {
+        final int mStartIndex;
+        final int mEndIndex;
+        final ClassificationResult[] mClassification;
+
+        AnnotatedSpan(int startIndex, int endIndex, ClassificationResult[] classification) {
+            mStartIndex = startIndex;
+            mEndIndex = endIndex;
+            mClassification = classification;
+        }
+
+        public int getStartIndex() {
+            return mStartIndex;
+        }
+
+        public int getEndIndex() {
+            return mEndIndex;
+        }
+
+        public ClassificationResult[] getClassification() {
+            return mClassification;
+        }
+    }
 }
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index bb1e693..c3601d9 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -152,4 +152,12 @@
      */
     @WorkerThread
     default void logEvent(String source, String event) {}
+
+    /**
+     * Returns this TextClassifier's settings.
+     * @hide
+     */
+    default TextClassifierConstants getSettings() {
+        return TextClassifierConstants.DEFAULT;
+    }
 }
diff --git a/core/java/android/view/textclassifier/TextClassifierConstants.java b/core/java/android/view/textclassifier/TextClassifierConstants.java
new file mode 100644
index 0000000..51e6168
--- /dev/null
+++ b/core/java/android/view/textclassifier/TextClassifierConstants.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.textclassifier;
+
+import android.annotation.Nullable;
+import android.util.KeyValueListParser;
+import android.util.Slog;
+
+/**
+ * TextClassifier specific settings.
+ * This is encoded as a key=value list, separated by commas. Ex:
+ *
+ * <pre>
+ * smart_selection_dark_launch              (boolean)
+ * smart_selection_enabled_for_edit_text    (boolean)
+ * </pre>
+ *
+ * <p>
+ * Type: string
+ * see also android.provider.Settings.Global.TEXT_CLASSIFIER_CONSTANTS
+ *
+ * Example of setting the values for testing.
+ * adb shell settings put global text_classifier_constants smart_selection_dark_launch=true,smart_selection_enabled_for_edit_text=true
+ * @hide
+ */
+public final class TextClassifierConstants {
+
+    private static final String LOG_TAG = "TextClassifierConstants";
+
+    private static final String SMART_SELECTION_DARK_LAUNCH =
+            "smart_selection_dark_launch";
+    private static final String SMART_SELECTION_ENABLED_FOR_EDIT_TEXT =
+            "smart_selection_enabled_for_edit_text";
+
+    private static final boolean SMART_SELECTION_DARK_LAUNCH_DEFAULT = false;
+    private static final boolean SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT = true;
+
+    /** Default settings. */
+    static final TextClassifierConstants DEFAULT = new TextClassifierConstants();
+
+    private final boolean mDarkLaunch;
+    private final boolean mSuggestSelectionEnabledForEditableText;
+
+    private TextClassifierConstants() {
+        mDarkLaunch = SMART_SELECTION_DARK_LAUNCH_DEFAULT;
+        mSuggestSelectionEnabledForEditableText = SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT;
+    }
+
+    private TextClassifierConstants(@Nullable String settings) {
+        final KeyValueListParser parser = new KeyValueListParser(',');
+        try {
+            parser.setString(settings);
+        } catch (IllegalArgumentException e) {
+            // Failed to parse the settings string, log this and move on with defaults.
+            Slog.e(LOG_TAG, "Bad TextClassifier settings: " + settings);
+        }
+        mDarkLaunch = parser.getBoolean(
+                SMART_SELECTION_DARK_LAUNCH,
+                SMART_SELECTION_DARK_LAUNCH_DEFAULT);
+        mSuggestSelectionEnabledForEditableText = parser.getBoolean(
+                SMART_SELECTION_ENABLED_FOR_EDIT_TEXT,
+                SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT);
+    }
+
+    static TextClassifierConstants loadFromString(String settings) {
+        return new TextClassifierConstants(settings);
+    }
+
+    public boolean isDarkLaunch() {
+        return mDarkLaunch;
+    }
+
+    public boolean isSuggestSelectionEnabledForEditableText() {
+        return mSuggestSelectionEnabledForEditableText;
+    }
+}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 2aa81a2..1c07be4 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -24,18 +24,17 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.graphics.drawable.Drawable;
-import android.icu.text.BreakIterator;
 import android.net.Uri;
 import android.os.LocaleList;
 import android.os.ParcelFileDescriptor;
 import android.provider.Browser;
 import android.provider.ContactsContract;
+import android.provider.Settings;
 import android.text.Spannable;
 import android.text.TextUtils;
 import android.text.method.WordIterator;
 import android.text.style.ClickableSpan;
 import android.text.util.Linkify;
-import android.util.Log;
 import android.util.Patterns;
 import android.view.View;
 import android.widget.TextViewMetrics;
@@ -47,6 +46,7 @@
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.text.BreakIterator;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -91,6 +91,8 @@
     @GuardedBy("mSmartSelectionLock") // Do not access outside this lock.
     private SmartSelection mSmartSelection;
 
+    private TextClassifierConstants mSettings;
+
     TextClassifierImpl(Context context) {
         mContext = Preconditions.checkNotNull(context);
     }
@@ -160,7 +162,7 @@
             }
         } catch (Throwable t) {
             // Avoid throwing from this method. Log the error.
-            Log.e(LOG_TAG, "Error getting assist info.", t);
+            Log.e(LOG_TAG, "Error getting text classification info.", t);
         }
         // Getting here means something went wrong, return a NO_OP result.
         return TextClassifier.NO_OP.classifyText(
@@ -189,6 +191,15 @@
         }
     }
 
+    @Override
+    public TextClassifierConstants getSettings() {
+        if (mSettings == null) {
+            mSettings = TextClassifierConstants.loadFromString(Settings.Global.getString(
+                    mContext.getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS));
+        }
+        return mSettings;
+    }
+
     private SmartSelection getSmartSelection(LocaleList localeList) throws FileNotFoundException {
         synchronized (mSmartSelectionLock) {
             localeList = localeList == null ? LocaleList.getEmptyLocaleList() : localeList;
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index afd1188..af09592 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -165,7 +165,7 @@
     private static final int MENU_ITEM_ORDER_PASTE_AS_PLAIN_TEXT = 11;
     private static final int MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 100;
 
-    private static final float MAGNIFIER_ZOOM = 1.5f;
+    private static final float MAGNIFIER_ZOOM = 1.25f;
     @IntDef({MagnifierHandleTrigger.SELECTION_START,
             MagnifierHandleTrigger.SELECTION_END,
             MagnifierHandleTrigger.INSERTION})
@@ -476,6 +476,17 @@
         stopTextActionModeWithPreservingSelection();
     }
 
+    void invalidateMagnifier() {
+        final DisplayMetrics dm = mTextView.getResources().getDisplayMetrics();
+        invalidateMagnifier(0, 0, dm.widthPixels, dm.heightPixels);
+    }
+
+    void invalidateMagnifier(final float l, final float t, final float r, final float b) {
+        if (mMagnifier != null) {
+            mTextView.post(() -> mMagnifier.invalidate(new RectF(l, t, r, b)));
+        }
+    }
+
     private void discardTextDisplayLists() {
         if (mTextRenderNodes != null) {
             for (int i = 0; i < mTextRenderNodes.length; i++) {
@@ -3888,7 +3899,7 @@
                 if (selected == null || selected.isEmpty()) {
                     menu.add(Menu.NONE, TextView.ID_AUTOFILL, MENU_ITEM_ORDER_AUTOFILL,
                             com.android.internal.R.string.autofill)
-                            .setShowAsAction(MenuItem.SHOW_AS_OVERFLOW_ALWAYS);
+                            .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
                 }
             }
 
@@ -4545,17 +4556,17 @@
                     + mTextView.getLayout().getLineBottom(lineNumber)) / 2.0f;
             final int[] coordinatesOnScreen = new int[2];
             mTextView.getLocationOnScreen(coordinatesOnScreen);
-            final float centerXOnScreen = xPosInView + mTextView.getTotalPaddingLeft()
-                    - mTextView.getScrollX() + coordinatesOnScreen[0];
-            final float centerYOnScreen = yPosInView + mTextView.getTotalPaddingTop()
-                    - mTextView.getScrollY() + coordinatesOnScreen[1];
+            final float centerXOnScreen = mTextView.convertViewToScreenCoord(xPosInView, true);
+            final float centerYOnScreen = mTextView.convertViewToScreenCoord(yPosInView, false);
 
+            suspendBlink();
             mMagnifier.show(centerXOnScreen, centerYOnScreen, MAGNIFIER_ZOOM);
         }
 
         protected final void dismissMagnifier() {
             if (mMagnifier != null) {
                 mMagnifier.dismiss();
+                resumeBlink();
             }
         }
 
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 1b26f8e..631f388 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -131,7 +131,7 @@
      *
      * @hide
      */
-    private ApplicationInfo mApplication;
+    public ApplicationInfo mApplication;
 
     /**
      * The resource ID of the layout file. (Added to the parcel)
@@ -1519,8 +1519,7 @@
 
         @Override
         public boolean hasSameAppInfo(ApplicationInfo parentInfo) {
-            return mNestedViews.mApplication.packageName.equals(parentInfo.packageName)
-                    && mNestedViews.mApplication.uid == parentInfo.uid;
+            return mNestedViews.hasSameAppInfo(parentInfo);
         }
 
         @Override
@@ -2138,8 +2137,7 @@
         if (landscape == null || portrait == null) {
             throw new RuntimeException("Both RemoteViews must be non-null");
         }
-        if (landscape.mApplication.uid != portrait.mApplication.uid
-                || !landscape.mApplication.packageName.equals(portrait.mApplication.packageName)) {
+        if (!landscape.hasSameAppInfo(portrait.mApplication)) {
             throw new RuntimeException("Both RemoteViews must share the same package and user");
         }
         mApplication = portrait.mApplication;
@@ -2653,7 +2651,11 @@
     /**
      * Equivalent to calling
      * {@link android.view.View#setOnClickListener(android.view.View.OnClickListener)}
-     * to launch the provided {@link PendingIntent}.
+     * to launch the provided {@link PendingIntent}. The source bounds
+     * ({@link Intent#getSourceBounds()}) of the intent will be set to the bounds of the clicked
+     * view in screen space.
+     * Note that any activity options associated with the pendingIntent may get overridden
+     * before starting the intent.
      *
      * When setting the on-click action of items within collections (eg. {@link ListView},
      * {@link StackView} etc.), this method will not work. Instead, use {@link
@@ -3551,6 +3553,15 @@
     }
 
     /**
+     * Returns true if the {@link #mApplication} is same as the provided info.
+     *
+     * @hide
+     */
+    public boolean hasSameAppInfo(ApplicationInfo info) {
+        return mApplication.packageName.equals(info.packageName) && mApplication.uid == info.uid;
+    }
+
+    /**
      * Parcelable.Creator that instantiates RemoteViews objects
      */
     public static final Parcelable.Creator<RemoteViews> CREATOR = new Parcelable.Creator<RemoteViews>() {
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 0968652..51277e4 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -21,6 +21,7 @@
 import android.appwidget.AppWidgetManager;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -115,6 +116,12 @@
     private boolean mDataReady = false;
 
     /**
+     * USed to dedupe {@link RemoteViews#mApplication} so that we do not hold on to
+     * multiple copies of the same ApplicationInfo object.
+     */
+    private ApplicationInfo mLastRemoteViewAppInfo;
+
+    /**
      * An interface for the RemoteAdapter to notify other classes when adapters
      * are actually connected to/disconnected from their actual services.
      */
@@ -309,6 +316,8 @@
     static class RemoteViewsFrameLayout extends AppWidgetHostView {
         private final FixedSizeRemoteViewsCache mCache;
 
+        public int cacheIndex = -1;
+
         public RemoteViewsFrameLayout(Context context, FixedSizeRemoteViewsCache cache) {
             super(context);
             mCache = cache;
@@ -359,26 +368,23 @@
      * Stores the references of all the RemoteViewsFrameLayouts that have been returned by the
      * adapter that have not yet had their RemoteViews loaded.
      */
-    private class RemoteViewsFrameLayoutRefSet {
-        private final SparseArray<LinkedList<RemoteViewsFrameLayout>> mReferences =
-                new SparseArray<>();
-        private final HashMap<RemoteViewsFrameLayout, LinkedList<RemoteViewsFrameLayout>>
-                mViewToLinkedList = new HashMap<>();
+    private class RemoteViewsFrameLayoutRefSet
+            extends SparseArray<LinkedList<RemoteViewsFrameLayout>> {
 
         /**
          * Adds a new reference to a RemoteViewsFrameLayout returned by the adapter.
          */
         public void add(int position, RemoteViewsFrameLayout layout) {
-            LinkedList<RemoteViewsFrameLayout> refs = mReferences.get(position);
+            LinkedList<RemoteViewsFrameLayout> refs = get(position);
 
             // Create the list if necessary
             if (refs == null) {
-                refs = new LinkedList<RemoteViewsFrameLayout>();
-                mReferences.put(position, refs);
+                refs = new LinkedList<>();
+                put(position, refs);
             }
-            mViewToLinkedList.put(layout, refs);
 
             // Add the references to the list
+            layout.cacheIndex = position;
             refs.add(layout);
         }
 
@@ -389,18 +395,13 @@
         public void notifyOnRemoteViewsLoaded(int position, RemoteViews view) {
             if (view == null) return;
 
-            final LinkedList<RemoteViewsFrameLayout> refs = mReferences.get(position);
+            // Remove this set from the original mapping
+            final LinkedList<RemoteViewsFrameLayout> refs = removeReturnOld(position);
             if (refs != null) {
                 // Notify all the references for that position of the newly loaded RemoteViews
                 for (final RemoteViewsFrameLayout ref : refs) {
                     ref.onRemoteViewsLoaded(view, mRemoteViewsOnClickHandler, true);
-                    if (mViewToLinkedList.containsKey(ref)) {
-                        mViewToLinkedList.remove(ref);
-                    }
                 }
-                refs.clear();
-                // Remove this set from the original mapping
-                mReferences.remove(position);
             }
         }
 
@@ -408,20 +409,14 @@
          * We need to remove views from this set if they have been recycled by the AdapterView.
          */
         public void removeView(RemoteViewsFrameLayout rvfl) {
-            if (mViewToLinkedList.containsKey(rvfl)) {
-                mViewToLinkedList.get(rvfl).remove(rvfl);
-                mViewToLinkedList.remove(rvfl);
+            if (rvfl.cacheIndex < 0) {
+                return;
             }
-        }
-
-        /**
-         * Removes all references to all RemoteViewsFrameLayouts returned by the adapter.
-         */
-        public void clear() {
-            // We currently just clear the references, and leave all the previous layouts returned
-            // in their default state of the loading view.
-            mReferences.clear();
-            mViewToLinkedList.clear();
+            final LinkedList<RemoteViewsFrameLayout> refs = get(rvfl.cacheIndex);
+            if (refs != null) {
+                refs.remove(rvfl);
+            }
+            rvfl.cacheIndex = -1;
         }
     }
 
@@ -534,7 +529,7 @@
         // too much memory.
         private final SparseArray<RemoteViews> mIndexRemoteViews = new SparseArray<>();
 
-        // An array of indices to load, Indices which are explicitely requested are set to true,
+        // An array of indices to load, Indices which are explicitly requested are set to true,
         // and those determined by the preloading algorithm to prefetch are set to false.
         private final SparseBooleanArray mIndicesToLoad = new SparseBooleanArray();
 
@@ -994,6 +989,20 @@
             return;
         }
 
+        if (remoteViews.mApplication != null) {
+            // We keep track of last application info. This helps when all the remoteViews have
+            // same applicationInfo, which should be the case for a typical adapter. But if every
+            // view has different application info, there will not be any optimization.
+            if (mLastRemoteViewAppInfo != null
+                    && remoteViews.hasSameAppInfo(mLastRemoteViewAppInfo)) {
+                // We should probably also update the remoteViews for nested ViewActions.
+                // Hopefully, RemoteViews in an adapter would be less complicated.
+                remoteViews.mApplication = mLastRemoteViewAppInfo;
+            } else {
+                mLastRemoteViewAppInfo = remoteViews.mApplication;
+            }
+        }
+
         int layoutId = remoteViews.getLayoutId();
         RemoteViewsMetaData metaData = mCache.getMetaData();
         boolean viewTypeInRange;
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 3be42a5..5e22650 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -95,11 +95,15 @@
     }
 
     public void startActionModeAsync(boolean adjustSelection) {
+        // Check if the smart selection should run for editable text.
+        adjustSelection &= !mTextView.isTextEditable()
+                || mTextView.getTextClassifier().getSettings()
+                        .isSuggestSelectionEnabledForEditableText();
+
         mSelectionTracker.onOriginalSelection(
                 getText(mTextView),
                 mTextView.getSelectionStart(),
-                mTextView.getSelectionEnd(),
-                mTextView.isTextEditable());
+                mTextView.getSelectionEnd());
         cancelAsyncTask();
         if (skipTextClassification()) {
             startActionMode(null);
@@ -196,7 +200,10 @@
     private void startActionMode(@Nullable SelectionResult result) {
         final CharSequence text = getText(mTextView);
         if (result != null && text instanceof Spannable) {
-            Selection.setSelection((Spannable) text, result.mStart, result.mEnd);
+            // Do not change the selection if TextClassifier should be dark launched.
+            if (!mTextView.getTextClassifier().getSettings().isDarkLaunch()) {
+                Selection.setSelection((Spannable) text, result.mStart, result.mEnd);
+            }
             mTextClassification = result.mClassification;
         } else {
             mTextClassification = null;
@@ -377,7 +384,7 @@
     }
 
     private void resetTextClassificationHelper() {
-        mTextClassificationHelper.reset(
+        mTextClassificationHelper.init(
                 mTextView.getTextClassifier(),
                 getText(mTextView),
                 mTextView.getSelectionStart(), mTextView.getSelectionEnd(),
@@ -415,8 +422,7 @@
         /**
          * Called when the original selection happens, before smart selection is triggered.
          */
-        public void onOriginalSelection(
-                CharSequence text, int selectionStart, int selectionEnd, boolean editableText) {
+        public void onOriginalSelection(CharSequence text, int selectionStart, int selectionEnd) {
             // If we abandoned a selection and created a new one very shortly after, we may still
             // have a pending request to log ABANDON, which we flush here.
             mDelayedLogAbandon.flush();
@@ -812,11 +818,11 @@
 
         TextClassificationHelper(TextClassifier textClassifier,
                 CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
-            reset(textClassifier, text, selectionStart, selectionEnd, locales);
+            init(textClassifier, text, selectionStart, selectionEnd, locales);
         }
 
         @UiThread
-        public void reset(TextClassifier textClassifier,
+        public void init(TextClassifier textClassifier,
                 CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
             mTextClassifier = Preconditions.checkNotNull(textClassifier);
             mText = Preconditions.checkNotNull(text).toString();
@@ -839,8 +845,12 @@
             trimText();
             final TextSelection selection = mTextClassifier.suggestSelection(
                     mTrimmedText, mRelativeStart, mRelativeEnd, mLocales);
-            mSelectionStart = Math.max(0, selection.getSelectionStartIndex() + mTrimStart);
-            mSelectionEnd = Math.min(mText.length(), selection.getSelectionEndIndex() + mTrimStart);
+            // Do not classify new selection boundaries if TextClassifier should be dark launched.
+            if (!mTextClassifier.getSettings().isDarkLaunch()) {
+                mSelectionStart = Math.max(0, selection.getSelectionStartIndex() + mTrimStart);
+                mSelectionEnd = Math.min(
+                        mText.length(), selection.getSelectionEndIndex() + mTrimStart);
+            }
             return performClassification(selection);
         }
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 24ae03c..ce80552 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -9219,6 +9219,36 @@
         }
     }
 
+    @Override
+    public void invalidate() {
+        super.invalidate();
+
+        if (mEditor != null) {
+            mEditor.invalidateMagnifier();
+        }
+    }
+
+    @Override
+    public void invalidate(int l, int t, int r, int b) {
+        super.invalidate(l, t, r, b);
+
+        if (mEditor != null) {
+            mEditor.invalidateMagnifier(
+                    convertViewToScreenCoord(l, true /* isHorizontal */),
+                    convertViewToScreenCoord(t, false /* isHorizontal */),
+                    convertViewToScreenCoord(r, true /* isHorizontal */),
+                    convertViewToScreenCoord(b, false /* isHorizontal */));
+        }
+    }
+
+    float convertViewToScreenCoord(float viewCoord, boolean isHorizontal) {
+        final int[] coordinatesOnScreen = new int[2];
+        getLocationOnScreen(coordinatesOnScreen);
+        return isHorizontal
+                ? viewCoord + getTotalPaddingLeft() - getScrollX() + coordinatesOnScreen[0]
+                : viewCoord + getTotalPaddingTop() - getScrollY() + coordinatesOnScreen[1];
+    }
+
     /**
      * @return whether or not the cursor is visible (assuming this TextView is editable)
      *
@@ -10338,6 +10368,17 @@
                 // of the View (and can be any drawable) or a BackgroundColorSpan inside the text.
                 structure.setTextStyle(getTextSize(), getCurrentTextColor(),
                         AssistStructure.ViewNode.TEXT_COLOR_UNDEFINED /* bgColor */, style);
+            } else {
+                structure.setMinTextEms(getMinEms());
+                structure.setMaxTextEms(getMaxEms());
+                int maxLength = -1;
+                for (InputFilter filter: getFilters()) {
+                    if (filter instanceof InputFilter.LengthFilter) {
+                        maxLength = ((InputFilter.LengthFilter) filter).getMax();
+                        break;
+                    }
+                }
+                structure.setMaxTextLength(maxLength);
             }
         }
         structure.setHint(getHint());
diff --git a/core/java/com/android/internal/alsa/AlsaCardsParser.java b/core/java/com/android/internal/alsa/AlsaCardsParser.java
index 5b92a17..bb75bf6 100644
--- a/core/java/com/android/internal/alsa/AlsaCardsParser.java
+++ b/core/java/com/android/internal/alsa/AlsaCardsParser.java
@@ -37,6 +37,12 @@
 
     private ArrayList<AlsaCardRecord> mCardRecords = new ArrayList<AlsaCardRecord>();
 
+    public static final int SCANSTATUS_NOTSCANNED = -1;
+    public static final int SCANSTATUS_SUCCESS = 0;
+    public static final int SCANSTATUS_FAIL = 1;
+    public static final int SCANSTATUS_EMPTY = 2;
+    private int mScanStatus = SCANSTATUS_NOTSCANNED;
+
     public class AlsaCardRecord {
         private static final String TAG = "AlsaCardRecord";
         private static final String kUsbCardKeyStr = "at usb-";
@@ -104,10 +110,11 @@
 
     public AlsaCardsParser() {}
 
-    public void scan() {
+    public int scan() {
         if (DEBUG) {
-            Slog.i(TAG, "AlsaCardsParser.scan()");
+            Slog.i(TAG, "AlsaCardsParser.scan()....");
         }
+
         mCardRecords = new ArrayList<AlsaCardRecord>();
 
         File cardsFile = new File(kCardsFilePath);
@@ -134,11 +141,26 @@
                 mCardRecords.add(cardRecord);
             }
             reader.close();
+            if (mCardRecords.size() > 0) {
+                mScanStatus = SCANSTATUS_SUCCESS;
+            } else {
+                mScanStatus = SCANSTATUS_EMPTY;
+            }
         } catch (FileNotFoundException e) {
             e.printStackTrace();
+            mScanStatus = SCANSTATUS_FAIL;
         } catch (IOException e) {
             e.printStackTrace();
+            mScanStatus = SCANSTATUS_FAIL;
         }
+        if (DEBUG) {
+            Slog.i(TAG, "  status:" + mScanStatus);
+        }
+        return mScanStatus;
+    }
+
+    public int getScanStatus() {
+        return mScanStatus;
     }
 
     public ArrayList<AlsaCardRecord> getScanRecords() {
@@ -182,7 +204,11 @@
         }
 
         // get the new list of devices
-        scan();
+        if (scan() != SCANSTATUS_SUCCESS) {
+            Slog.e(TAG, "Error scanning Alsa cards file.");
+            return -1;
+        }
+
         if (DEBUG) {
             LogDevices("Current Devices:", mCardRecords);
         }
diff --git a/core/java/com/android/internal/alsa/AlsaDevicesParser.java b/core/java/com/android/internal/alsa/AlsaDevicesParser.java
index 6e3d596..15261baf 100644
--- a/core/java/com/android/internal/alsa/AlsaDevicesParser.java
+++ b/core/java/com/android/internal/alsa/AlsaDevicesParser.java
@@ -46,6 +46,12 @@
     private boolean mHasPlaybackDevices = false;
     private boolean mHasMIDIDevices = false;
 
+    public static final int SCANSTATUS_NOTSCANNED = -1;
+    public static final int SCANSTATUS_SUCCESS = 0;
+    public static final int SCANSTATUS_FAIL = 1;
+    public static final int SCANSTATUS_EMPTY = 2;
+    private int mScanStatus = SCANSTATUS_NOTSCANNED;
+
     public class AlsaDeviceRecord {
         public static final int kDeviceType_Unknown = -1;
         public static final int kDeviceType_Audio = 0;
@@ -258,7 +264,11 @@
         return line.charAt(kIndex_CardDeviceField) == '[';
     }
 
-    public boolean scan() {
+    public int scan() {
+        if (DEBUG) {
+            Slog.i(TAG, "AlsaDevicesParser.scan()....");
+        }
+
         mDeviceRecords.clear();
 
         File devicesFile = new File(kDevicesFilePath);
@@ -274,13 +284,27 @@
                 }
             }
             reader.close();
-            return true;
+            // success if we add at least 1 record
+            if (mDeviceRecords.size() > 0) {
+                mScanStatus = SCANSTATUS_SUCCESS;
+            } else {
+                mScanStatus = SCANSTATUS_EMPTY;
+            }
         } catch (FileNotFoundException e) {
             e.printStackTrace();
+            mScanStatus = SCANSTATUS_FAIL;
         } catch (IOException e) {
             e.printStackTrace();
+            mScanStatus = SCANSTATUS_FAIL;
         }
-        return false;
+        if (DEBUG) {
+            Slog.i(TAG, "  status:" + mScanStatus);
+        }
+        return mScanStatus;
+    }
+
+    public int getScanStatus() {
+        return mScanStatus;
     }
 
     //
diff --git a/core/java/com/android/internal/app/LocalePickerWithRegion.java b/core/java/com/android/internal/app/LocalePickerWithRegion.java
index 3d5cd0f..d0719ee 100644
--- a/core/java/com/android/internal/app/LocalePickerWithRegion.java
+++ b/core/java/com/android/internal/app/LocalePickerWithRegion.java
@@ -238,7 +238,7 @@
             mSearchView.setOnQueryTextListener(this);
 
             // Restore previous search status
-            if (mPreviousSearch != null) {
+            if (!TextUtils.isEmpty(mPreviousSearch)) {
                 searchMenuItem.expandActionView();
                 mSearchView.setIconified(false);
                 mSearchView.setActivated(true);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index dd07ddb..5c310b1 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -119,7 +119,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 167 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 168 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS;
@@ -13118,7 +13118,7 @@
                 }
             }
         } else {
-            // TODO: There should be two 0's printed here, not just one.
+            out.writeInt(0);
             out.writeInt(0);
         }
 
diff --git a/core/java/com/android/internal/os/KernelCpuSpeedReader.java b/core/java/com/android/internal/os/KernelCpuSpeedReader.java
index 757a112..4c0370c 100644
--- a/core/java/com/android/internal/os/KernelCpuSpeedReader.java
+++ b/core/java/com/android/internal/os/KernelCpuSpeedReader.java
@@ -15,13 +15,12 @@
  */
 package com.android.internal.os;
 
+import android.system.Os;
 import android.text.TextUtils;
 import android.os.StrictMode;
 import android.system.OsConstants;
 import android.util.Slog;
 
-import libcore.io.Libcore;
-
 import java.io.BufferedReader;
 import java.io.FileReader;
 import java.io.IOException;
@@ -53,7 +52,7 @@
                 cpuNumber);
         mLastSpeedTimesMs = new long[numSpeedSteps];
         mDeltaSpeedTimesMs = new long[numSpeedSteps];
-        long jiffyHz = Libcore.os.sysconf(OsConstants._SC_CLK_TCK);
+        long jiffyHz = Os.sysconf(OsConstants._SC_CLK_TCK);
         mJiffyMillis = 1000/jiffyHz;
     }
 
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index e46dfc4..bf31c7d 100644
--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -22,6 +22,7 @@
 import android.os.Process;
 import android.os.StrictMode;
 import android.os.SystemClock;
+import android.system.Os;
 import android.system.OsConstants;
 import android.util.Slog;
 
@@ -294,7 +295,7 @@
 
     public ProcessCpuTracker(boolean includeThreads) {
         mIncludeThreads = includeThreads;
-        long jiffyHz = Libcore.os.sysconf(OsConstants._SC_CLK_TCK);
+        long jiffyHz = Os.sysconf(OsConstants._SC_CLK_TCK);
         mJiffyMillis = 1000/jiffyHz;
     }
 
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 4abab28..2be6212 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -549,7 +549,7 @@
             try {
                 dexoptNeeded = DexFile.getDexOptNeeded(
                     classPathElement, instructionSet, systemServerFilter,
-                    false /* newProfile */, false /* downgrade */);
+                    null /* classLoaderContext */, false /* newProfile */, false /* downgrade */);
             } catch (FileNotFoundException ignored) {
                 // Do not add to the classpath.
                 Log.w(TAG, "Missing classpath element for system server: " + classPathElement);
diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java
index b71fa06..8d71666 100644
--- a/core/java/com/android/internal/util/MemInfoReader.java
+++ b/core/java/com/android/internal/util/MemInfoReader.java
@@ -82,7 +82,7 @@
      * that are mapped in to processes.
      */
     public long getCachedSizeKb() {
-        return mInfos[Debug.MEMINFO_BUFFERS]
+        return mInfos[Debug.MEMINFO_BUFFERS] + mInfos[Debug.MEMINFO_SLAB_RECLAIMABLE]
                 + mInfos[Debug.MEMINFO_CACHED] - mInfos[Debug.MEMINFO_MAPPED];
     }
 
@@ -90,7 +90,7 @@
      * Amount of RAM that is in use by the kernel for actual allocations.
      */
     public long getKernelUsedSizeKb() {
-        return mInfos[Debug.MEMINFO_SHMEM] + mInfos[Debug.MEMINFO_SLAB]
+        return mInfos[Debug.MEMINFO_SHMEM] + mInfos[Debug.MEMINFO_SLAB_UNRECLAIMABLE]
                 + mInfos[Debug.MEMINFO_VM_ALLOC_USED] + mInfos[Debug.MEMINFO_PAGE_TABLES]
                 + mInfos[Debug.MEMINFO_KERNEL_STACK];
     }
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index cc0ef75..2098ebd 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.view;
 
+import android.annotation.AnyThread;
+import android.annotation.BinderThread;
 import android.annotation.NonNull;
 import android.inputmethodservice.AbstractInputMethodService;
 import android.os.Bundle;
@@ -67,6 +69,7 @@
          * sequence number is set to a new integer.  We use a sequence number so that replies that
          * occur after a timeout has expired are not interpreted as replies to a later request.
          */
+        @AnyThread
         private static InputContextCallback getInstance() {
             synchronized (InputContextCallback.class) {
                 // Return sInstance if it's non-null, otherwise construct a new callback
@@ -90,6 +93,7 @@
         /**
          * Makes the given InputContextCallback available for use in the future.
          */
+        @AnyThread
         private void dispose() {
             synchronized (InputContextCallback.class) {
                 // If sInstance is non-null, just let this object be garbage-collected
@@ -102,7 +106,8 @@
                 }
             }
         }
-        
+
+        @BinderThread
         public void setTextBeforeCursor(CharSequence textBeforeCursor, int seq) {
             synchronized (this) {
                 if (seq == mSeq) {
@@ -116,6 +121,7 @@
             }
         }
 
+        @BinderThread
         public void setTextAfterCursor(CharSequence textAfterCursor, int seq) {
             synchronized (this) {
                 if (seq == mSeq) {
@@ -129,6 +135,7 @@
             }
         }
 
+        @BinderThread
         public void setSelectedText(CharSequence selectedText, int seq) {
             synchronized (this) {
                 if (seq == mSeq) {
@@ -142,6 +149,7 @@
             }
         }
 
+        @BinderThread
         public void setCursorCapsMode(int capsMode, int seq) {
             synchronized (this) {
                 if (seq == mSeq) {
@@ -155,6 +163,7 @@
             }
         }
 
+        @BinderThread
         public void setExtractedText(ExtractedText extractedText, int seq) {
             synchronized (this) {
                 if (seq == mSeq) {
@@ -168,6 +177,7 @@
             }
         }
 
+        @BinderThread
         public void setRequestUpdateCursorAnchorInfoResult(boolean result, int seq) {
             synchronized (this) {
                 if (seq == mSeq) {
@@ -181,6 +191,7 @@
             }
         }
 
+        @BinderThread
         public void setCommitContentResult(boolean result, int seq) {
             synchronized (this) {
                 if (seq == mSeq) {
@@ -199,6 +210,7 @@
          * 
          * <p>The caller must be synchronized on this callback object.
          */
+        @AnyThread
         void waitForResultLocked() {
             long startTime = SystemClock.uptimeMillis();
             long endTime = startTime + MAX_WAIT_TIME_MILLIS;
@@ -225,6 +237,7 @@
         mMissingMethods = missingMethods;
     }
 
+    @AnyThread
     public CharSequence getTextAfterCursor(int length, int flags) {
         CharSequence value = null;
         try {
@@ -242,7 +255,8 @@
         }
         return value;
     }
-    
+
+    @AnyThread
     public CharSequence getTextBeforeCursor(int length, int flags) {
         CharSequence value = null;
         try {
@@ -261,6 +275,7 @@
         return value;
     }
 
+    @AnyThread
     public CharSequence getSelectedText(int flags) {
         if (isMethodMissing(MissingMethodFlags.GET_SELECTED_TEXT)) {
             // This method is not implemented.
@@ -283,6 +298,7 @@
         return value;
     }
 
+    @AnyThread
     public int getCursorCapsMode(int reqModes) {
         int value = 0;
         try {
@@ -301,6 +317,7 @@
         return value;
     }
 
+    @AnyThread
     public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
         ExtractedText value = null;
         try {
@@ -318,7 +335,8 @@
         }
         return value;
     }
-    
+
+    @AnyThread
     public boolean commitText(CharSequence text, int newCursorPosition) {
         try {
             mIInputContext.commitText(text, newCursorPosition);
@@ -328,6 +346,7 @@
         }
     }
 
+    @AnyThread
     public boolean commitCompletion(CompletionInfo text) {
         if (isMethodMissing(MissingMethodFlags.COMMIT_CORRECTION)) {
             // This method is not implemented.
@@ -341,6 +360,7 @@
         }
     }
 
+    @AnyThread
     public boolean commitCorrection(CorrectionInfo correctionInfo) {
         try {
             mIInputContext.commitCorrection(correctionInfo);
@@ -350,6 +370,7 @@
         }
     }
 
+    @AnyThread
     public boolean setSelection(int start, int end) {
         try {
             mIInputContext.setSelection(start, end);
@@ -358,7 +379,8 @@
             return false;
         }
     }
-    
+
+    @AnyThread
     public boolean performEditorAction(int actionCode) {
         try {
             mIInputContext.performEditorAction(actionCode);
@@ -367,7 +389,8 @@
             return false;
         }
     }
-    
+
+    @AnyThread
     public boolean performContextMenuAction(int id) {
         try {
             mIInputContext.performContextMenuAction(id);
@@ -377,6 +400,7 @@
         }
     }
 
+    @AnyThread
     public boolean setComposingRegion(int start, int end) {
         if (isMethodMissing(MissingMethodFlags.SET_COMPOSING_REGION)) {
             // This method is not implemented.
@@ -390,6 +414,7 @@
         }
     }
 
+    @AnyThread
     public boolean setComposingText(CharSequence text, int newCursorPosition) {
         try {
             mIInputContext.setComposingText(text, newCursorPosition);
@@ -399,6 +424,7 @@
         }
     }
 
+    @AnyThread
     public boolean finishComposingText() {
         try {
             mIInputContext.finishComposingText();
@@ -408,6 +434,7 @@
         }
     }
 
+    @AnyThread
     public boolean beginBatchEdit() {
         try {
             mIInputContext.beginBatchEdit();
@@ -416,7 +443,8 @@
             return false;
         }
     }
-    
+
+    @AnyThread
     public boolean endBatchEdit() {
         try {
             mIInputContext.endBatchEdit();
@@ -425,7 +453,8 @@
             return false;
         }
     }
-    
+
+    @AnyThread
     public boolean sendKeyEvent(KeyEvent event) {
         try {
             mIInputContext.sendKeyEvent(event);
@@ -435,6 +464,7 @@
         }
     }
 
+    @AnyThread
     public boolean clearMetaKeyStates(int states) {
         try {
             mIInputContext.clearMetaKeyStates(states);
@@ -444,6 +474,7 @@
         }
     }
 
+    @AnyThread
     public boolean deleteSurroundingText(int beforeLength, int afterLength) {
         try {
             mIInputContext.deleteSurroundingText(beforeLength, afterLength);
@@ -453,6 +484,7 @@
         }
     }
 
+    @AnyThread
     public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
         if (isMethodMissing(MissingMethodFlags.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS)) {
             // This method is not implemented.
@@ -466,11 +498,13 @@
         }
     }
 
+    @AnyThread
     public boolean reportFullscreenMode(boolean enabled) {
         // Nothing should happen when called from input method.
         return false;
     }
 
+    @AnyThread
     public boolean performPrivateCommand(String action, Bundle data) {
         try {
             mIInputContext.performPrivateCommand(action, data);
@@ -480,6 +514,7 @@
         }
     }
 
+    @AnyThread
     public boolean requestCursorUpdates(int cursorUpdateMode) {
         boolean result = false;
         if (isMethodMissing(MissingMethodFlags.REQUEST_CURSOR_UPDATES)) {
@@ -502,15 +537,18 @@
         return result;
     }
 
+    @AnyThread
     public Handler getHandler() {
         // Nothing should happen when called from input method.
         return null;
     }
 
+    @AnyThread
     public void closeConnection() {
         // Nothing should happen when called from input method.
     }
 
+    @AnyThread
     public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
         boolean result = false;
         if (isMethodMissing(MissingMethodFlags.COMMIT_CONTENT)) {
@@ -542,10 +580,12 @@
         return result;
     }
 
+    @AnyThread
     private boolean isMethodMissing(@MissingMethodFlags final int methodFlag) {
         return (mMissingMethods & methodFlag) == methodFlag;
     }
 
+    @AnyThread
     @Override
     public String toString() {
         return "InputConnectionWrapper{idHash=#"
diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java
index f76c724..8f80bfe 100644
--- a/core/java/com/android/internal/view/menu/ListMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java
@@ -319,13 +319,15 @@
     public void setGroupDividerEnabled(boolean groupDividerEnabled) {
         // If mHasListDivider is true, disabling the groupDivider.
         // Otherwise, checking enbling it according to groupDividerEnabled flag.
-        mGroupDivider.setVisibility(!mHasListDivider
-                && groupDividerEnabled ? View.VISIBLE : View.GONE);
+        if (mGroupDivider != null) {
+            mGroupDivider.setVisibility(!mHasListDivider
+                    && groupDividerEnabled ? View.VISIBLE : View.GONE);
+        }
     }
 
     @Override
     public void adjustListItemSelectionBounds(Rect rect) {
-        if (mGroupDivider.getVisibility() == View.VISIBLE) {
+        if (mGroupDivider != null && mGroupDivider.getVisibility() == View.VISIBLE) {
             // groupDivider is a part of MenuItemListView.
             // If ListMenuItem with divider enabled is hovered/clicked, divider also gets selected.
             // Clipping the selector bounds from the top divider portion when divider is enabled,
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 15e271e..9d012de 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -658,7 +658,7 @@
 
     @Override
     public boolean requiresOverflow() {
-        return (mShowAsAction & SHOW_AS_OVERFLOW_ALWAYS) == SHOW_AS_OVERFLOW_ALWAYS;
+        return !requiresActionButton() && !requestsActionButton();
     }
 
     public void setIsActionButton(boolean isActionButton) {
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index f63b5a2..e3b1c01 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -64,6 +64,7 @@
 import com.android.internal.util.Preconditions;
 
 import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Objects;
@@ -118,6 +119,36 @@
     };
 
     /**
+     * Sorts the list of menu items to conform to certain requirements.
+     */
+    private final Comparator<MenuItem> mMenuItemComparator = (menuItem1, menuItem2) -> {
+        // Ensure the assist menu item is always the first item:
+        if (menuItem1.getItemId() == android.R.id.textAssist) {
+            return menuItem2.getItemId() == android.R.id.textAssist ? 0 : -1;
+        }
+        if (menuItem2.getItemId() == android.R.id.textAssist) {
+            return 1;
+        }
+
+        // Order by SHOW_AS_ACTION type:
+        if (menuItem1.requiresActionButton()) {
+            return menuItem2.requiresActionButton() ? 0 : -1;
+        }
+        if (menuItem2.requiresActionButton()) {
+            return 1;
+        }
+        if (menuItem1.requiresOverflow()) {
+            return menuItem2.requiresOverflow() ? 0 : 1;
+        }
+        if (menuItem2.requiresOverflow()) {
+            return -1;
+        }
+
+        // Order by order value:
+        return menuItem1.getOrder() - menuItem2.getOrder();
+    };
+
+    /**
      * Initializes a floating toolbar.
      */
     public FloatingToolbar(Window window) {
@@ -230,7 +261,7 @@
 
     private void doShow() {
         List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu);
-        tidy(menuItems);
+        menuItems.sort(mMenuItemComparator);
         if (!isCurrentlyShowing(menuItems) || mWidthChanged) {
             mPopup.dismiss();
             mPopup.layoutMenuItems(menuItems, mMenuItemClickListener, mSuggestedWidth);
@@ -288,36 +319,6 @@
         return menuItems;
     }
 
-    /**
-     * Update the list of menu items to conform to certain requirements.
-     */
-    private void tidy(List<MenuItem> menuItems) {
-        int assistItemIndex = -1;
-        Drawable assistItemDrawable = null;
-
-        final int size = menuItems.size();
-        for (int i = 0; i < size; i++) {
-            final MenuItem menuItem = menuItems.get(i);
-
-            if (menuItem.getItemId() == android.R.id.textAssist) {
-                assistItemIndex = i;
-                assistItemDrawable = menuItem.getIcon();
-            }
-
-            // Remove icons for all menu items with text.
-            if (!TextUtils.isEmpty(menuItem.getTitle())) {
-                menuItem.setIcon(null);
-            }
-        }
-        if (assistItemIndex > -1) {
-            final MenuItem assistMenuItem = menuItems.remove(assistItemIndex);
-            // Ensure the assist menu item preserves its icon.
-            assistMenuItem.setIcon(assistItemDrawable);
-            // Ensure the assist menu item is always the first item.
-            menuItems.add(0, assistMenuItem);
-        }
-    }
-
     private void registerOrientationHandler() {
         unregisterOrientationHandler();
         mWindow.getDecorView().addOnLayoutChangeListener(mOrientationChangeHandler);
@@ -1148,7 +1149,8 @@
             // add the overflow menu items to the end of the remainingMenuItems list.
             final LinkedList<MenuItem> overflowMenuItems = new LinkedList();
             for (MenuItem menuItem : menuItems) {
-                if (menuItem.requiresOverflow()) {
+                if (menuItem.getItemId() != android.R.id.textAssist
+                        && menuItem.requiresOverflow()) {
                     overflowMenuItems.add(menuItem);
                 } else {
                     remainingMenuItems.add(menuItem);
@@ -1171,7 +1173,9 @@
                     break;
                 }
 
-                View menuItemButton = createMenuItemButton(mContext, menuItem, mIconTextSpacing);
+                final boolean showIcon = isFirstItem && menuItem.getItemId() == R.id.textAssist;
+                final View menuItemButton = createMenuItemButton(
+                        mContext, menuItem, mIconTextSpacing, showIcon);
 
                 // Adding additional start padding for the first button to even out button spacing.
                 if (isFirstItem) {
@@ -1193,16 +1197,17 @@
                 }
 
                 menuItemButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
-                final int menuItemButtonWidth = Math.min(menuItemButton.getMeasuredWidth(), toolbarWidth);
+                final int menuItemButtonWidth = Math.min(
+                        menuItemButton.getMeasuredWidth(), toolbarWidth);
 
                 final boolean isNewGroup = !isFirstItem && lastGroupId != menuItem.getGroupId();
                 final int extraPadding = isNewGroup ? menuItemButton.getPaddingEnd() * 2 : 0;
 
                 // Check if we can fit an item while reserving space for the overflowButton.
-                boolean canFitWithOverflow =
+                final boolean canFitWithOverflow =
                         menuItemButtonWidth <=
                                 availableWidth - mOverflowButtonSize.getWidth() - extraPadding;
-                boolean canFitNoOverflow =
+                final boolean canFitNoOverflow =
                         isLastItem && menuItemButtonWidth <= availableWidth - extraPadding;
                 if (canFitWithOverflow || canFitNoOverflow) {
                     if (isNewGroup) {
@@ -1211,7 +1216,8 @@
 
                         // Add extra padding to the end of the previous button.
                         // Half of the extra padding (less borderWidth) goes to the previous button.
-                        View previousButton = mMainPanel.getChildAt(mMainPanel.getChildCount() - 1);
+                        final View previousButton = mMainPanel.getChildAt(
+                                mMainPanel.getChildCount() - 1);
                         final int prevPaddingEnd = previousButton.getPaddingEnd()
                                 + extraPadding / 2 - dividerWidth;
                         previousButton.setPaddingRelative(
@@ -1612,7 +1618,8 @@
             public View getView(MenuItem menuItem, int minimumWidth, View convertView) {
                 Preconditions.checkNotNull(menuItem);
                 if (convertView != null) {
-                    updateMenuItemButton(convertView, menuItem, mIconTextSpacing);
+                    updateMenuItemButton(
+                            convertView, menuItem, mIconTextSpacing, shouldShowIcon(menuItem));
                 } else {
                     convertView = createMenuButton(menuItem);
                 }
@@ -1621,17 +1628,26 @@
             }
 
             public int calculateWidth(MenuItem menuItem) {
-                updateMenuItemButton(mCalculator, menuItem, mIconTextSpacing);
+                updateMenuItemButton(
+                        mCalculator, menuItem, mIconTextSpacing, shouldShowIcon(menuItem));
                 mCalculator.measure(
                         View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
                 return mCalculator.getMeasuredWidth();
             }
 
             private View createMenuButton(MenuItem menuItem) {
-                View button = createMenuItemButton(mContext, menuItem, mIconTextSpacing);
+                View button = createMenuItemButton(
+                        mContext, menuItem, mIconTextSpacing, shouldShowIcon(menuItem));
                 button.setPadding(mSidePadding, 0, mSidePadding, 0);
                 return button;
             }
+
+            private boolean shouldShowIcon(MenuItem menuItem) {
+                if (menuItem != null) {
+                    return menuItem.getGroupId() == android.R.id.textAssist;
+                }
+                return false;
+            }
         }
     }
 
@@ -1639,11 +1655,11 @@
      * Creates and returns a menu button for the specified menu item.
      */
     private static View createMenuItemButton(
-            Context context, MenuItem menuItem, int iconTextSpacing) {
+            Context context, MenuItem menuItem, int iconTextSpacing, boolean showIcon) {
         final View menuItemButton = LayoutInflater.from(context)
                 .inflate(R.layout.floating_popup_menu_button, null);
         if (menuItem != null) {
-            updateMenuItemButton(menuItemButton, menuItem, iconTextSpacing);
+            updateMenuItemButton(menuItemButton, menuItem, iconTextSpacing, showIcon);
         }
         return menuItemButton;
     }
@@ -1652,18 +1668,19 @@
      * Updates the specified menu item button with the specified menu item data.
      */
     private static void updateMenuItemButton(
-            View menuItemButton, MenuItem menuItem, int iconTextSpacing) {
-        final TextView buttonText = (TextView) menuItemButton.findViewById(
+            View menuItemButton, MenuItem menuItem, int iconTextSpacing, boolean showIcon) {
+        final TextView buttonText = menuItemButton.findViewById(
                 R.id.floating_toolbar_menu_item_text);
+        buttonText.setEllipsize(null);
         if (TextUtils.isEmpty(menuItem.getTitle())) {
             buttonText.setVisibility(View.GONE);
         } else {
             buttonText.setVisibility(View.VISIBLE);
             buttonText.setText(menuItem.getTitle());
         }
-        final ImageView buttonIcon = (ImageView) menuItemButton
-                .findViewById(R.id.floating_toolbar_menu_item_image);
-        if (menuItem.getIcon() == null) {
+        final ImageView buttonIcon = menuItemButton.findViewById(
+                R.id.floating_toolbar_menu_item_image);
+        if (menuItem.getIcon() == null || !showIcon) {
             buttonIcon.setVisibility(View.GONE);
             if (buttonText != null) {
                 buttonText.setPaddingRelative(0, 0, 0, 0);
diff --git a/core/java/com/android/internal/widget/Magnifier.java b/core/java/com/android/internal/widget/Magnifier.java
index 86e7b38..9bc0778 100644
--- a/core/java/com/android/internal/widget/Magnifier.java
+++ b/core/java/com/android/internal/widget/Magnifier.java
@@ -22,7 +22,9 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Point;
+import android.graphics.PointF;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.os.Handler;
 import android.util.Log;
 import android.view.Gravity;
@@ -41,6 +43,8 @@
  */
 public final class Magnifier {
     private static final String LOG_TAG = "magnifier";
+    // Use this to specify that a previous configuration value does not exist.
+    private static final int INEXISTENT_PREVIOUS_CONFIG_VALUE = -1;
     // The view for which this magnifier is attached.
     private final View mView;
     // The window containing the magnifier.
@@ -59,6 +63,15 @@
     // the copy is finished.
     private final Handler mPixelCopyHandler = Handler.getMain();
 
+    private RectF mTmpRectF;
+
+    // Variables holding previous states, used for detecting redundant calls and invalidation.
+    private Point mPrevStartCoordsOnScreen = new Point(
+            INEXISTENT_PREVIOUS_CONFIG_VALUE, INEXISTENT_PREVIOUS_CONFIG_VALUE);
+    private PointF mPrevCenterCoordsOnScreen = new PointF(
+            INEXISTENT_PREVIOUS_CONFIG_VALUE, INEXISTENT_PREVIOUS_CONFIG_VALUE);
+    private float mPrevScale = INEXISTENT_PREVIOUS_CONFIG_VALUE;
+
     /**
      * Initializes a magnifier.
      *
@@ -88,16 +101,45 @@
     /**
      * Shows the magnifier on the screen.
      *
-     * @param centerXOnScreen horizontal coordinate of the center point of the magnifier source
-     * @param centerYOnScreen vertical coordinate of the center point of the magnifier source
-     * @param scale the scale at which the magnifier zooms on the source content
+     * @param centerXOnScreen horizontal coordinate of the center point of the magnifier source. The
+     *        lower end is clamped to 0
+     * @param centerYOnScreen vertical coordinate of the center point of the magnifier source. The
+     *        lower end is clamped to 0
+     * @param scale the scale at which the magnifier zooms on the source content. The
+     *        lower end is clamped to 1 and the higher end to 4
      */
     public void show(@FloatRange(from=0) float centerXOnScreen,
             @FloatRange(from=0) float centerYOnScreen,
-            @FloatRange(from=1, to=10) float scale) {
-        maybeResizeBitmap(scale);
+            @FloatRange(from=1, to=4) float scale) {
+        if (scale > 4) {
+            scale = 4;
+        }
+
+        if (scale < 1) {
+            scale = 1;
+        }
+
+        if (centerXOnScreen < 0) {
+            centerXOnScreen = 0;
+        }
+
+        if (centerYOnScreen < 0) {
+            centerYOnScreen = 0;
+        }
+
+        showInternal(centerXOnScreen, centerYOnScreen, scale, false);
+    }
+
+    private void showInternal(@FloatRange(from=0) float centerXOnScreen,
+            @FloatRange(from=0) float centerYOnScreen,
+            @FloatRange(from=1, to=4) float scale,
+            boolean forceShow) {
+        if (mPrevScale != scale) {
+            resizeBitmap(scale);
+            mPrevScale = scale;
+        }
         configureCoordinates(centerXOnScreen, centerYOnScreen);
-        performPixelCopy();
+        maybePerformPixelCopy(scale, forceShow);
 
         if (mWindow.isShowing()) {
             mWindow.update(mWindowCoords.x, mWindowCoords.y, mWindow.getWidth(),
@@ -106,6 +148,9 @@
             mWindow.showAtLocation(mView.getRootView(), Gravity.NO_GRAVITY,
                     mWindowCoords.x, mWindowCoords.y);
         }
+
+        mPrevCenterCoordsOnScreen.x = centerXOnScreen;
+        mPrevCenterCoordsOnScreen.y = centerYOnScreen;
     }
 
     /**
@@ -113,6 +158,38 @@
      */
     public void dismiss() {
         mWindow.dismiss();
+
+        mPrevStartCoordsOnScreen.x = INEXISTENT_PREVIOUS_CONFIG_VALUE;
+        mPrevStartCoordsOnScreen.y = INEXISTENT_PREVIOUS_CONFIG_VALUE;
+        mPrevCenterCoordsOnScreen.x = INEXISTENT_PREVIOUS_CONFIG_VALUE;
+        mPrevCenterCoordsOnScreen.y = INEXISTENT_PREVIOUS_CONFIG_VALUE;
+        mPrevScale = INEXISTENT_PREVIOUS_CONFIG_VALUE;
+    }
+
+    /**
+     * Forces the magnifier to update content by taking and showing a new snapshot using the
+     * previous coordinates. It does this only if the magnifier is showing and the dirty rectangle
+     * intersects the rectangle which holds the content to be magnified.
+     *
+     * @param dirtyRectOnScreen the rectangle representing the screen bounds of the dirty region
+     */
+    public void invalidate(RectF dirtyRectOnScreen) {
+        if (mWindow.isShowing() && mPrevCenterCoordsOnScreen.x != INEXISTENT_PREVIOUS_CONFIG_VALUE
+                && mPrevCenterCoordsOnScreen.y != INEXISTENT_PREVIOUS_CONFIG_VALUE
+                && mPrevScale != INEXISTENT_PREVIOUS_CONFIG_VALUE) {
+            // Update the current showing RectF.
+            mTmpRectF = new RectF(mPrevStartCoordsOnScreen.x,
+                    mPrevStartCoordsOnScreen.y,
+                    mPrevStartCoordsOnScreen.x + mBitmap.getWidth(),
+                    mPrevStartCoordsOnScreen.y + mBitmap.getHeight());
+
+            // Update only if we are currently showing content that has been declared as invalid.
+            if (RectF.intersects(dirtyRectOnScreen, mTmpRectF)) {
+                // Update the contents shown in the magnifier.
+                showInternal(mPrevCenterCoordsOnScreen.x, mPrevCenterCoordsOnScreen.y, mPrevScale,
+                        true /* forceShow */);
+            }
+        }
     }
 
     /**
@@ -129,13 +206,11 @@
         return mWindowWidth;
     }
 
-    private void maybeResizeBitmap(float scale) {
+    private void resizeBitmap(float scale) {
         final int bitmapWidth = (int) (mWindowWidth / scale);
         final int bitmapHeight = (int) (mWindowHeight / scale);
-        if (mBitmap.getWidth() != bitmapWidth || mBitmap.getHeight() != bitmapHeight) {
-            mBitmap.reconfigure(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
-            getImageView().setImageBitmap(mBitmap);
-        }
+        mBitmap.reconfigure(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
+        getImageView().setImageBitmap(mBitmap);
     }
 
     private void configureCoordinates(float posXOnScreen, float posYOnScreen) {
@@ -144,24 +219,29 @@
 
         final int verticalMagnifierOffset = mView.getContext().getResources().getDimensionPixelSize(
                 R.dimen.magnifier_offset);
-        final int availableTopSpace = (mCenterZoomCoords.y - mWindowHeight / 2)
-                - verticalMagnifierOffset - (mBitmap.getHeight() / 2);
-
         mWindowCoords.x = mCenterZoomCoords.x - mWindowWidth / 2;
-        mWindowCoords.y = mCenterZoomCoords.y - mWindowHeight / 2
-                + verticalMagnifierOffset * (availableTopSpace > 0 ? -1 : 1);
+        mWindowCoords.y = mCenterZoomCoords.y - mWindowHeight / 2 - verticalMagnifierOffset;
     }
 
-    private void performPixelCopy() {
-        int startX = mCenterZoomCoords.x - mBitmap.getWidth() / 2;
+    private void maybePerformPixelCopy(final float scale, final boolean forceShow) {
+        final int startY = mCenterZoomCoords.y - mBitmap.getHeight() / 2;
+        int rawStartX = mCenterZoomCoords.x - mBitmap.getWidth() / 2;
+
         // Clamp startX value to avoid distorting the rendering of the magnifier content.
-        if (startX < 0) {
-            startX = 0;
-        } else if (startX + mBitmap.getWidth() > mView.getWidth()) {
-            startX = mView.getWidth() - mBitmap.getWidth();
+        if (rawStartX < 0) {
+            rawStartX = 0;
+        } else if (rawStartX + mBitmap.getWidth() > mView.getWidth()) {
+            rawStartX = mView.getWidth() - mBitmap.getWidth();
         }
 
-        final int startY = mCenterZoomCoords.y - mBitmap.getHeight() / 2;
+        if (!forceShow && rawStartX == mPrevStartCoordsOnScreen.x
+                && startY == mPrevStartCoordsOnScreen.y
+                && scale == mPrevScale) {
+            // Skip, we are already showing the desired content.
+            return;
+        }
+
+        final int startX = rawStartX;
         final ViewRootImpl viewRootImpl = mView.getViewRootImpl();
 
         if (viewRootImpl != null && viewRootImpl.mSurface != null
@@ -171,7 +251,11 @@
                     new Rect(startX, startY, startX + mBitmap.getWidth(),
                             startY + mBitmap.getHeight()),
                     mBitmap,
-                    result -> getImageView().invalidate(),
+                    result -> {
+                        getImageView().invalidate();
+                        mPrevStartCoordsOnScreen.x = startX;
+                        mPrevStartCoordsOnScreen.y = startY;
+                    },
                     mPixelCopyHandler);
         } else {
             Log.d(LOG_TAG, "Could not perform PixelCopy request");
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 256b920..4fbd265 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -1,3 +1,13 @@
+
+genrule {
+    name: "android_util_StatsLog.cpp",
+    tools: ["stats-log-api-gen"],
+    cmd: "$(location stats-log-api-gen) --jni $(genDir)/android_util_StatsLog.cpp",
+    out: [
+        "android_util_StatsLog.cpp",
+    ],
+}
+
 cc_library_shared {
     name: "libandroid_runtime",
 
@@ -77,7 +87,6 @@
         "android_view_ThreadedRenderer.cpp",
         "android_view_VelocityTracker.cpp",
         "android_text_AndroidCharacter.cpp",
-        "android_text_AndroidBidi.cpp",
         "android_text_Hyphenator.cpp",
         "android_text_StaticLayout.cpp",
         "android_os_Debug.cpp",
@@ -104,7 +113,6 @@
         "android_nio_utils.cpp",
         "android_util_AssetManager.cpp",
         "android_util_Binder.cpp",
-	"android_util_StatsLog.cpp",
         "android_util_EventLog.cpp",
         "android_util_MemoryIntArray.cpp",
         "android_util_Log.cpp",
@@ -271,11 +279,13 @@
         "libhwbinder",
         "libvintf",
         "libnativewindow",
-
         "libhwui",
         "libdl",
+        "libstatslog",
     ],
 
+    generated_sources: ["android_util_StatsLog.cpp"],
+
     local_include_dirs: ["android/graphics"],
     export_include_dirs: [
         ".",
@@ -291,13 +301,4 @@
         // GraphicsJNI.h includes hwui headers
         "libhwui",
     ],
-
-    product_variables: {
-        debuggable: {
-            cflags: ["-D__ANDROID_DEBUGGABLE__"]
-        },
-        treble: {
-            cflags: ["-D__ANDROID_TREBLE__"]
-        },
-    },
 }
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index deb4d5a..8977891 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -19,6 +19,8 @@
 #define LOG_NDEBUG 1
 
 #include <android_runtime/AndroidRuntime.h>
+
+#include <android-base/properties.h>
 #include <binder/IBinder.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
@@ -47,8 +49,8 @@
 #include <string>
 #include <vector>
 
-
 using namespace android;
+using android::base::GetProperty;
 
 extern int register_android_os_Binder(JNIEnv* env);
 extern int register_android_os_Process(JNIEnv* env);
@@ -175,7 +177,6 @@
 extern int register_android_text_AndroidCharacter(JNIEnv *env);
 extern int register_android_text_Hyphenator(JNIEnv *env);
 extern int register_android_text_StaticLayout(JNIEnv *env);
-extern int register_android_text_AndroidBidi(JNIEnv *env);
 extern int register_android_opengl_classes(JNIEnv *env);
 extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
 extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env);
@@ -392,17 +393,6 @@
     return false;
 }
 
-// Convenience wrapper over the property API that returns an
-// std::string.
-std::string getProperty(const char* key, const char* defaultValue) {
-    std::vector<char> temp(PROPERTY_VALUE_MAX);
-    const int len = property_get(key, &temp[0], defaultValue);
-    if (len < 0) {
-        return "";
-    }
-    return std::string(&temp[0], len);
-}
-
 /*
  * Read the persistent locale. Inspects the following system properties
  * (in order) and returns the first non-empty property in the list :
@@ -419,15 +409,15 @@
  */
 const std::string readLocale()
 {
-    const std::string locale = getProperty("persist.sys.locale", "");
+    const std::string locale = GetProperty("persist.sys.locale", "");
     if (!locale.empty()) {
         return locale;
     }
 
-    const std::string language = getProperty("persist.sys.language", "");
+    const std::string language = GetProperty("persist.sys.language", "");
     if (!language.empty()) {
-        const std::string country = getProperty("persist.sys.country", "");
-        const std::string variant = getProperty("persist.sys.localevar", "");
+        const std::string country = GetProperty("persist.sys.country", "");
+        const std::string variant = GetProperty("persist.sys.localevar", "");
 
         std::string out = language;
         if (!country.empty()) {
@@ -441,15 +431,15 @@
         return out;
     }
 
-    const std::string productLocale = getProperty("ro.product.locale", "");
+    const std::string productLocale = GetProperty("ro.product.locale", "");
     if (!productLocale.empty()) {
         return productLocale;
     }
 
     // If persist.sys.locale and ro.product.locale are missing,
     // construct a locale value from the individual locale components.
-    const std::string productLanguage = getProperty("ro.product.locale.language", "en");
-    const std::string productRegion = getProperty("ro.product.locale.region", "US");
+    const std::string productLanguage = GetProperty("ro.product.locale.language", "en");
+    const std::string productRegion = GetProperty("ro.product.locale.region", "US");
 
     return productLanguage + "-" + productRegion;
 }
@@ -617,9 +607,12 @@
     char jitprithreadweightOptBuf[sizeof("-Xjitprithreadweight:")-1 + PROPERTY_VALUE_MAX];
     char jittransitionweightOptBuf[sizeof("-Xjittransitionweight:")-1 + PROPERTY_VALUE_MAX];
     char hotstartupsamplesOptsBuf[sizeof("-Xps-hot-startup-method-samples:")-1 + PROPERTY_VALUE_MAX];
+    char madviseRandomOptsBuf[sizeof("-XX:MadviseRandomAccess:")-1 + PROPERTY_VALUE_MAX];
     char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
     char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
     char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
+    char foregroundHeapGrowthMultiplierOptsBuf[
+            sizeof("-XX:ForegroundHeapGrowthMultiplier=")-1 + PROPERTY_VALUE_MAX];
     char cachePruneBuf[sizeof("-Xzygote-max-boot-retry=")-1 + PROPERTY_VALUE_MAX];
     char dex2oatXmsImageFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
     char dex2oatXmxImageFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
@@ -649,7 +642,7 @@
     char cpuAbiListBuf[sizeof("--cpu-abilist=") + PROPERTY_VALUE_MAX];
     char methodTraceFileBuf[sizeof("-Xmethod-trace-file:") + PROPERTY_VALUE_MAX];
     char methodTraceFileSizeBuf[sizeof("-Xmethod-trace-file-size:") + PROPERTY_VALUE_MAX];
-    char fingerprintBuf[sizeof("-Xfingerprint:") + PROPERTY_VALUE_MAX];
+    std::string fingerprintBuf;
 
     bool checkJni = false;
     property_get("dalvik.vm.checkjni", propBuf, "");
@@ -723,6 +716,11 @@
                        heaptargetutilizationOptsBuf,
                        "-XX:HeapTargetUtilization=");
 
+    /* Foreground heap growth multiplier option */
+    parseRuntimeOption("dalvik.vm.foreground-heap-growth-multiplier",
+                       foregroundHeapGrowthMultiplierOptsBuf,
+                       "-XX:ForegroundHeapGrowthMultiplier=");
+
     /*
      * JIT related options.
      */
@@ -744,6 +742,11 @@
                        "-Xjittransitionweight:");
 
     /*
+     * Madvise related options.
+     */
+    parseRuntimeOption("dalvik.vm.madvise-random", madviseRandomOptsBuf, "-XX:MadviseRandomAccess:");
+
+    /*
      * Profile related options.
      */
     parseRuntimeOption("dalvik.vm.hot-startup-method-samples", hotstartupsamplesOptsBuf,
@@ -964,8 +967,15 @@
     /*
      * Retrieve the build fingerprint and provide it to the runtime. That way, ANR dumps will
      * contain the fingerprint and can be parsed.
+     * Fingerprints are potentially longer than PROPERTY_VALUE_MAX, so parseRuntimeOption() cannot
+     * be used here.
+     * Do not ever re-assign fingerprintBuf as its c_str() value is stored in mOptions.
      */
-    parseRuntimeOption("ro.build.fingerprint", fingerprintBuf, "-Xfingerprint:");
+    std::string fingerprint = GetProperty("ro.build.fingerprint", "");
+    if (!fingerprint.empty()) {
+        fingerprintBuf = "-Xfingerprint:" + fingerprint;
+        addOption(fingerprintBuf.c_str());
+    }
 
     initArgs.version = JNI_VERSION_1_4;
     initArgs.options = mOptions.editArray();
@@ -1313,10 +1323,10 @@
     REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
     REG_JNI(register_android_os_SystemClock),
     REG_JNI(register_android_util_EventLog),
-    REG_JNI(register_android_util_StatsLog),
     REG_JNI(register_android_util_Log),
     REG_JNI(register_android_util_MemoryIntArray),
     REG_JNI(register_android_util_PathParser),
+    REG_JNI(register_android_util_StatsLog),
     REG_JNI(register_android_app_admin_SecurityLog),
     REG_JNI(register_android_content_AssetManager),
     REG_JNI(register_android_content_StringBlock),
@@ -1324,7 +1334,6 @@
     REG_JNI(register_android_text_AndroidCharacter),
     REG_JNI(register_android_text_Hyphenator),
     REG_JNI(register_android_text_StaticLayout),
-    REG_JNI(register_android_text_AndroidBidi),
     REG_JNI(register_android_view_InputDevice),
     REG_JNI(register_android_view_KeyCharacterMap),
     REG_JNI(register_android_os_Process),
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 635eed3..5498a93 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -682,6 +682,8 @@
 
     sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(&bitmap);
     if (!nativeBitmap) {
+        ALOGE("OOM allocating Bitmap with dimensions %i x %i", width, height);
+        doThrowOOME(env);
         return NULL;
     }
 
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index c8eef7f..1628220 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -23,13 +23,13 @@
 #include <vector>
 #include <cmath>
 
+#include <android-base/properties.h>
 #include <utils/Log.h>
 #include <utils/Errors.h>
 #include <utils/StrongPointer.h>
 #include <utils/RefBase.h>
 #include <utils/Vector.h>
 #include <utils/String8.h>
-#include <cutils/properties.h>
 #include <system/camera_metadata.h>
 #include <camera/CameraMetadata.h>
 #include <img_utils/DngUtils.h>
@@ -50,6 +50,7 @@
 
 using namespace android;
 using namespace img_utils;
+using android::base::GetProperty;
 
 #define BAIL_IF_INVALID_RET_BOOL(expr, jnienv, tagId, writer) \
     if ((expr) != OK) { \
@@ -1237,26 +1238,24 @@
 
     {
         // make
-        char manufacturer[PROPERTY_VALUE_MAX];
-
         // Use "" to represent unknown make as suggested in TIFF/EP spec.
-        property_get("ro.product.manufacturer", manufacturer, "");
-        uint32_t count = static_cast<uint32_t>(strlen(manufacturer)) + 1;
+        std::string manufacturer = GetProperty("ro.product.manufacturer", "");
+        uint32_t count = static_cast<uint32_t>(manufacturer.size()) + 1;
 
         BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_MAKE, count,
-                reinterpret_cast<uint8_t*>(manufacturer), TIFF_IFD_0), env, TAG_MAKE, writer);
+                reinterpret_cast<const uint8_t*>(manufacturer.c_str()), TIFF_IFD_0), env, TAG_MAKE,
+                writer);
     }
 
     {
         // model
-        char model[PROPERTY_VALUE_MAX];
-
         // Use "" to represent unknown model as suggested in TIFF/EP spec.
-        property_get("ro.product.model", model, "");
-        uint32_t count = static_cast<uint32_t>(strlen(model)) + 1;
+        std::string model = GetProperty("ro.product.model", "");
+        uint32_t count = static_cast<uint32_t>(model.size()) + 1;
 
         BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_MODEL, count,
-                reinterpret_cast<uint8_t*>(model), TIFF_IFD_0), env, TAG_MODEL, writer);
+                reinterpret_cast<const uint8_t*>(model.c_str()), TIFF_IFD_0), env, TAG_MODEL,
+                writer);
     }
 
     {
@@ -1277,11 +1276,11 @@
 
     {
         // software
-        char software[PROPERTY_VALUE_MAX];
-        property_get("ro.build.fingerprint", software, "");
-        uint32_t count = static_cast<uint32_t>(strlen(software)) + 1;
+        std::string software = GetProperty("ro.build.fingerprint", "");
+        uint32_t count = static_cast<uint32_t>(software.size()) + 1;
         BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_SOFTWARE, count,
-                reinterpret_cast<uint8_t*>(software), TIFF_IFD_0), env, TAG_SOFTWARE, writer);
+                reinterpret_cast<const uint8_t*>(software.c_str()), TIFF_IFD_0), env, TAG_SOFTWARE,
+                writer);
     }
 
     if (nativeContext->hasCaptureTime()) {
@@ -1613,20 +1612,15 @@
 
     {
         // Setup unique camera model tag
-        char model[PROPERTY_VALUE_MAX];
-        property_get("ro.product.model", model, "");
+        std::string model = GetProperty("ro.product.model", "");
+        std::string manufacturer = GetProperty("ro.product.manufacturer", "");
+        std::string brand = GetProperty("ro.product.brand", "");
 
-        char manufacturer[PROPERTY_VALUE_MAX];
-        property_get("ro.product.manufacturer", manufacturer, "");
-
-        char brand[PROPERTY_VALUE_MAX];
-        property_get("ro.product.brand", brand, "");
-
-        String8 cameraModel(model);
+        String8 cameraModel(model.c_str());
         cameraModel += "-";
-        cameraModel += manufacturer;
+        cameraModel += manufacturer.c_str();
         cameraModel += "-";
-        cameraModel += brand;
+        cameraModel += brand.c_str();
 
         BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_UNIQUECAMERAMODEL, cameraModel.size() + 1,
                 reinterpret_cast<const uint8_t*>(cameraModel.string()), TIFF_IFD_0), env,
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index a140b57..d3da21b 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -705,6 +705,8 @@
     MEMINFO_CACHED,
     MEMINFO_SHMEM,
     MEMINFO_SLAB,
+    MEMINFO_SLAB_RECLAIMABLE,
+    MEMINFO_SLAB_UNRECLAIMABLE,
     MEMINFO_SWAP_TOTAL,
     MEMINFO_SWAP_FREE,
     MEMINFO_ZRAM_TOTAL,
@@ -753,7 +755,7 @@
         return;
     }
 
-    int fd = open("/proc/meminfo", O_RDONLY);
+    int fd = open("/proc/meminfo", O_RDONLY | O_CLOEXEC);
 
     if (fd < 0) {
         ALOGW("Unable to open /proc/meminfo: %s\n", strerror(errno));
@@ -776,6 +778,8 @@
             "Cached:",
             "Shmem:",
             "Slab:",
+            "SReclaimable:",
+            "SUnreclaim:",
             "SwapTotal:",
             "SwapFree:",
             "ZRam:",
@@ -792,6 +796,8 @@
             7,
             6,
             5,
+            13,
+            11,
             10,
             9,
             5,
@@ -801,7 +807,7 @@
             12,
             0
     };
-    long mem[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+    long mem[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
     char* p = buffer;
     while (*p && numFound < (sizeof(tagsLen) / sizeof(tagsLen[0]))) {
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 59ca050..fe14d48 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -306,7 +306,7 @@
         jstring serviceNameObj) {
 
     using ::android::hidl::base::V1_0::IBase;
-    using ::android::hidl::manager::V1_0::IServiceManager;
+    using ::android::hardware::details::getRawServiceInternal;
 
     if (ifaceNameObj == NULL) {
         jniThrowException(env, "java/lang/NullPointerException", NULL);
@@ -317,22 +317,12 @@
         return NULL;
     }
 
-    auto manager = hardware::defaultServiceManager();
-
-    if (manager == nullptr) {
-        LOG(ERROR) << "Could not get hwservicemanager.";
-        signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
-        return NULL;
-    }
-
     const char *ifaceNameCStr = env->GetStringUTFChars(ifaceNameObj, NULL);
     if (ifaceNameCStr == NULL) {
         return NULL; // XXX exception already pending?
     }
     std::string ifaceName(ifaceNameCStr);
     env->ReleaseStringUTFChars(ifaceNameObj, ifaceNameCStr);
-    ::android::hardware::hidl_string ifaceNameHStr;
-    ifaceNameHStr.setToExternal(ifaceName.c_str(), ifaceName.size());
 
     const char *serviceNameCStr = env->GetStringUTFChars(serviceNameObj, NULL);
     if (serviceNameCStr == NULL) {
@@ -340,50 +330,9 @@
     }
     std::string serviceName(serviceNameCStr);
     env->ReleaseStringUTFChars(serviceNameObj, serviceNameCStr);
-    ::android::hardware::hidl_string serviceNameHStr;
-    serviceNameHStr.setToExternal(serviceName.c_str(), serviceName.size());
 
-    LOG(INFO) << "Looking for service "
-              << ifaceName
-              << "/"
-              << serviceName;
-
-    Return<IServiceManager::Transport> transportRet =
-            manager->getTransport(ifaceNameHStr, serviceNameHStr);
-
-    if (!transportRet.isOk()) {
-        signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
-        return NULL;
-    }
-
-    IServiceManager::Transport transport = transportRet;
-
-#ifdef __ANDROID_TREBLE__
-#ifdef __ANDROID_DEBUGGABLE__
-    const char* testingOverride = std::getenv("TREBLE_TESTING_OVERRIDE");
-    const bool vintfLegacy = (transport == IServiceManager::Transport::EMPTY)
-            && testingOverride && !strcmp(testingOverride, "true");
-#else // __ANDROID_TREBLE__ but not __ANDROID_DEBUGGABLE__
-    const bool vintfLegacy = false;
-#endif // __ANDROID_DEBUGGABLE__
-#else // not __ANDROID_TREBLE__
-    const bool vintfLegacy = (transport == IServiceManager::Transport::EMPTY);
-#endif // __ANDROID_TREBLE__";
-
-    if (transport != IServiceManager::Transport::HWBINDER && !vintfLegacy) {
-        LOG(ERROR) << "service " << ifaceName << " declares transport method "
-                   << toString(transport) << " but framework expects hwbinder.";
-        signalExceptionForError(env, NAME_NOT_FOUND, true /* canThrowRemoteException */);
-        return NULL;
-    }
-
-    Return<sp<hidl::base::V1_0::IBase>> ret = manager->get(ifaceNameHStr, serviceNameHStr);
-
-    if (!ret.isOk()) {
-        signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
-        return NULL;
-    }
-
+    // TODO(b/67981006): true /* retry */
+    sp<IBase> ret = getRawServiceInternal(ifaceName, serviceName, false /* retry */, false /* getStub */); 
     sp<hardware::IBinder> service = hardware::toBinder<hidl::base::V1_0::IBase>(ret);
 
     if (service == NULL) {
diff --git a/core/jni/android_text_AndroidBidi.cpp b/core/jni/android_text_AndroidBidi.cpp
deleted file mode 100644
index f72f0f0..0000000
--- a/core/jni/android_text_AndroidBidi.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/* //device/libs/android_runtime/android_text_AndroidBidi.cpp
-**
-** Copyright 2010, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "AndroidUnicode"
-
-#include <nativehelper/JNIHelp.h>
-#include "core_jni_helpers.h"
-#include "utils/misc.h"
-#include "utils/Log.h"
-#include "unicode/ubidi.h"
-#include <minikin/Emoji.h>
-
-namespace android {
-
-static jint runBidi(JNIEnv* env, jobject obj, jint dir, jcharArray chsArray,
-                    jbyteArray infoArray, jint n, jboolean haveInfo)
-{
-    // Parameters are checked on java side
-    // Failures from GetXXXArrayElements indicate a serious out-of-memory condition
-    // that we don't bother to report, we're probably dead anyway.
-    jint result = 0;
-    jchar* chs = env->GetCharArrayElements(chsArray, NULL);
-    if (chs != NULL) {
-        jbyte* info = env->GetByteArrayElements(infoArray, NULL);
-        if (info != NULL) {
-            UErrorCode status = U_ZERO_ERROR;
-            UBiDi* bidi = ubidi_openSized(n, 0, &status);
-            // Set callbacks to override bidi classes of new emoji
-            ubidi_setClassCallback(
-                    bidi, minikin::emojiBidiOverride, nullptr, nullptr, nullptr, &status);
-            ubidi_setPara(bidi, reinterpret_cast<const UChar*>(chs), n, dir, NULL, &status);
-            if (U_SUCCESS(status)) {
-                for (int i = 0; i < n; ++i) {
-                  info[i] = ubidi_getLevelAt(bidi, i);
-                }
-                result = ubidi_getParaLevel(bidi);
-            } else {
-                jniThrowException(env, "java/lang/RuntimeException", NULL);
-            }
-            ubidi_close(bidi);
-
-            env->ReleaseByteArrayElements(infoArray, info, 0);
-        }
-        env->ReleaseCharArrayElements(chsArray, chs, JNI_ABORT);
-    }
-    return result;
-}
-
-static const JNINativeMethod gMethods[] = {
-        { "runBidi", "(I[C[BIZ)I", (void*) runBidi }
-};
-
-int register_android_text_AndroidBidi(JNIEnv* env)
-{
-    return RegisterMethodsOrDie(env, "android/text/AndroidBidi", gMethods, NELEM(gMethods));
-}
-
-}
diff --git a/core/jni/android_text_Hyphenator.cpp b/core/jni/android_text_Hyphenator.cpp
index da025da..05bec28 100644
--- a/core/jni/android_text_Hyphenator.cpp
+++ b/core/jni/android_text_Hyphenator.cpp
@@ -14,24 +14,157 @@
  * limitations under the License.
  */
 
-#include <cstdint>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <algorithm>
+
 #include <core_jni_helpers.h>
 #include <minikin/Hyphenator.h>
-#include <nativehelper/ScopedUtfChars.h>
 
 namespace android {
 
-static jlong nBuildHyphenator(JNIEnv* env, jclass, jlong dataAddress, jstring lang,
-        jint minPrefix, jint minSuffix) {
-    const uint8_t* bytebuf = reinterpret_cast<const uint8_t*>(dataAddress);  // null allowed.
-    ScopedUtfChars language(env, lang);
-    minikin::Hyphenator* hyphenator = minikin::Hyphenator::loadBinary(
-            bytebuf, minPrefix, minSuffix, language.c_str(), language.size());
-    return reinterpret_cast<jlong>(hyphenator);
+static std::string buildFileName(const std::string& locale) {
+    constexpr char SYSTEM_HYPHENATOR_PREFIX[] = "/system/usr/hyphen-data/hyph-";
+    constexpr char SYSTEM_HYPHENATOR_SUFFIX[] = ".hyb";
+    std::string lowerLocale;
+    lowerLocale.reserve(locale.size());
+    std::transform(locale.begin(), locale.end(), std::back_inserter(lowerLocale), ::tolower);
+    return SYSTEM_HYPHENATOR_PREFIX + lowerLocale + SYSTEM_HYPHENATOR_SUFFIX;
+}
+
+static const uint8_t* mmapPatternFile(const std::string& locale) {
+    const std::string hyFilePath = buildFileName(locale);
+    const int fd = open(hyFilePath.c_str(), O_RDONLY);
+    if (fd == -1) {
+        return nullptr;  // Open failed.
+    }
+
+    struct stat st = {};
+    if (fstat(fd, &st) == -1) {  // Unlikely to happen.
+        close(fd);
+        return nullptr;
+    }
+
+    void* ptr = mmap(nullptr, st.st_size, PROT_READ, MAP_SHARED, fd, 0 /* offset */);
+    close(fd);
+    if (ptr == MAP_FAILED) {
+        return nullptr;
+    }
+    return reinterpret_cast<const uint8_t*>(ptr);
+}
+
+static void addHyphenatorWithoutPatternFile(const std::string& locale, int minPrefix,
+        int minSuffix) {
+    minikin::addHyphenator(locale, minikin::Hyphenator::loadBinary(
+            nullptr, minPrefix, minSuffix, locale));
+}
+
+static void addHyphenator(const std::string& locale, int minPrefix, int minSuffix) {
+    const uint8_t* ptr = mmapPatternFile(locale);
+    if (ptr == nullptr) {
+        ALOGE("Unable to find pattern file or unable to map it for %s", locale.c_str());
+        return;
+    }
+    minikin::addHyphenator(locale, minikin::Hyphenator::loadBinary(
+            ptr, minPrefix, minSuffix, locale));
+}
+
+static void addHyphenatorAlias(const std::string& from, const std::string& to) {
+    minikin::addHyphenatorAlias(from, to);
+}
+
+static void init() {
+    // TODO: Confirm that these are the best values. Various sources suggest (1, 1), but that
+    // appears too small.
+    constexpr int INDIC_MIN_PREFIX = 2;
+    constexpr int INDIC_MIN_SUFFIX = 2;
+
+    addHyphenator("as", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Assamese
+    addHyphenator("be", 2, 2); // Belarusian
+    addHyphenator("bg", 2, 2); // Bulgarian
+    addHyphenator("bn", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Bengali
+    addHyphenator("cu", 1, 2); // Church Slavonic
+    addHyphenator("cy", 2, 3); // Welsh
+    addHyphenator("da", 2, 2); // Danish
+    addHyphenator("de-1901", 2, 2); // German 1901 orthography
+    addHyphenator("de-1996", 2, 2); // German 1996 orthography
+    addHyphenator("de-CH-1901", 2, 2); // Swiss High German 1901 orthography
+    addHyphenator("en-GB", 2, 3); // British English
+    addHyphenator("en-US", 2, 3); // American English
+    addHyphenator("es", 2, 2); // Spanish
+    addHyphenator("et", 2, 3); // Estonian
+    addHyphenator("eu", 2, 2); // Basque
+    addHyphenator("fr", 2, 3); // French
+    addHyphenator("ga", 2, 3); // Irish
+    addHyphenator("gu", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Gujarati
+    addHyphenator("hi", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Hindi
+    addHyphenator("hr", 2, 2); // Croatian
+    addHyphenator("hu", 2, 2); // Hungarian
+    // texhyphen sources say Armenian may be (1, 2); but that it needs confirmation.
+    // Going with a more conservative value of (2, 2) for now.
+    addHyphenator("hy", 2, 2); // Armenian
+    addHyphenator("kn", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Kannada
+    addHyphenator("la", 2, 2); // Latin
+    addHyphenator("ml", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Malayalam
+    addHyphenator("mn-Cyrl", 2, 2); // Mongolian in Cyrillic script
+    addHyphenator("mr", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Marathi
+    addHyphenator("nb", 2, 2); // Norwegian Bokmål
+    addHyphenator("nn", 2, 2); // Norwegian Nynorsk
+    addHyphenator("or", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Oriya
+    addHyphenator("pa", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Punjabi
+    addHyphenator("pt", 2, 3); // Portuguese
+    addHyphenator("sl", 2, 2); // Slovenian
+    addHyphenator("ta", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Tamil
+    addHyphenator("te", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Telugu
+    addHyphenator("tk", 2, 2); // Turkmen
+    addHyphenator("und-Ethi", 1, 1); // Any language in Ethiopic script
+
+    // Following two hyphenators do not have pattern files but there is some special logic based on
+    // language.
+    addHyphenatorWithoutPatternFile("ca", 2, 2);  // Catalan
+    addHyphenatorWithoutPatternFile("pl", 2, 2);  // Polish
+
+    // English locales that fall back to en-US. The data is from CLDR. It's all English locales,
+    // minus the locales whose parent is en-001 (from supplementalData.xml, under <parentLocales>).
+    // TODO: Figure out how to get this from ICU.
+    addHyphenatorAlias("en-AS", "en-US"); // English (American Samoa)
+    addHyphenatorAlias("en-GU", "en-US"); // English (Guam)
+    addHyphenatorAlias("en-MH", "en-US"); // English (Marshall Islands)
+    addHyphenatorAlias("en-MP", "en-US"); // English (Northern Mariana Islands)
+    addHyphenatorAlias("en-PR", "en-US"); // English (Puerto Rico)
+    addHyphenatorAlias("en-UM", "en-US"); // English (United States Minor Outlying Islands)
+    addHyphenatorAlias("en-VI", "en-US"); // English (Virgin Islands)
+
+    // All English locales other than those falling back to en-US are mapped to en-GB.
+    addHyphenatorAlias("en", "en-GB");
+
+    // For German, we're assuming the 1996 (and later) orthography by default.
+    addHyphenatorAlias("de", "de-1996");
+    // Liechtenstein uses the Swiss hyphenation rules for the 1901 orthography.
+    addHyphenatorAlias("de-LI-1901", "de-CH-1901");
+
+    // Norwegian is very probably Norwegian Bokmål.
+    addHyphenatorAlias("no", "nb");
+
+    // Use mn-Cyrl. According to CLDR's likelySubtags.xml, mn is most likely to be mn-Cyrl.
+    addHyphenatorAlias("mn", "mn-Cyrl"); // Mongolian
+
+    // Fall back to Ethiopic script for languages likely to be written in Ethiopic.
+    // Data is from CLDR's likelySubtags.xml.
+    // TODO: Convert this to a mechanism using ICU4J's ULocale#addLikelySubtags().
+    addHyphenatorAlias("am", "und-Ethi"); // Amharic
+    addHyphenatorAlias("byn", "und-Ethi"); // Blin
+    addHyphenatorAlias("gez", "und-Ethi"); // Geʻez
+    addHyphenatorAlias("ti", "und-Ethi"); // Tigrinya
+    addHyphenatorAlias("wal", "und-Ethi"); // Wolaytta
+
 }
 
 static const JNINativeMethod gMethods[] = {
-    {"nBuildHyphenator", "(JLjava/lang/String;II)J", (void*) nBuildHyphenator},
+    {"nInit", "()V", (void*) init},
 };
 
 int register_android_text_Hyphenator(JNIEnv* env) {
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index 1f7277a..04e9dfd 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -195,49 +195,9 @@
     b->finish();
 }
 
-class ScopedNullableUtfString {
-public:
-    ScopedNullableUtfString(JNIEnv* env, jstring s) : mEnv(env), mStr(s) {
-        if (s == nullptr) {
-            mUtf8Chars = nullptr;
-        } else {
-            mUtf8Chars = mEnv->GetStringUTFChars(s, nullptr);
-        }
-    }
-
-    ~ScopedNullableUtfString() {
-        if (mUtf8Chars != nullptr) {
-            mEnv->ReleaseStringUTFChars(mStr, mUtf8Chars);
-        }
-    }
-
-    const char* get() const {
-        return mUtf8Chars;
-    }
-
-private:
-    JNIEnv* mEnv;
-    jstring mStr;
-    const char* mUtf8Chars;
-};
-
-static std::vector<minikin::Hyphenator*> makeHyphenators(JNIEnv* env, jlongArray hyphenators) {
-    std::vector<minikin::Hyphenator*> out;
-    if (hyphenators == nullptr) {
-        return out;
-    }
-    ScopedLongArrayRO longArray(env, hyphenators);
-    size_t size = longArray.size();
-    out.reserve(size);
-    for (size_t i = 0; i < size; i++) {
-        out.push_back(reinterpret_cast<minikin::Hyphenator*>(longArray[i]));
-    }
-    return out;
-}
-
 // Basically similar to Paint.getTextRunAdvances but with C++ interface
 static void nAddStyleRun(JNIEnv* env, jclass, jlong nativePtr, jlong nativePaint, jint start,
-        jint end, jboolean isRtl, jstring langTags, jlongArray hyphenators) {
+        jint end, jboolean isRtl) {
     minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr);
     Paint* paint = reinterpret_cast<Paint*>(nativePaint);
     const Typeface* typeface = paint->getAndroidTypeface();
@@ -246,16 +206,14 @@
     minikin::FontStyle style = MinikinUtils::prepareMinikinPaint(&minikinPaint, paint,
             typeface);
 
-    ScopedNullableUtfString langTagsString(env, langTags);
-    b->addStyleRun(&minikinPaint, resolvedTypeface->fFontCollection, style, start,
-            end, isRtl, langTagsString.get(), makeHyphenators(env, hyphenators));
+    b->addStyleRun(&minikinPaint, resolvedTypeface->fFontCollection, style, start, end, isRtl);
 }
 
-static void nAddReplacementRun(JNIEnv* env, jclass, jlong nativePtr,
-        jint start, jint end, jfloat width, jstring langTags, jlongArray hyphenators) {
+static void nAddReplacementRun(JNIEnv* env, jclass, jlong nativePtr, jlong nativePaint,
+        jint start, jint end, jfloat width) {
     minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr);
-    ScopedNullableUtfString langTagsString(env, langTags);
-    b->addReplacement(start, end, width, langTagsString.get(), makeHyphenators(env, hyphenators));
+    Paint* paint = reinterpret_cast<Paint*>(nativePaint);
+    b->addReplacement(start, end, width, paint->getMinikinLangListId());
 }
 
 static const JNINativeMethod gMethods[] = {
@@ -264,8 +222,8 @@
     {"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
     {"nFinishBuilder", "(J)V", (void*) nFinishBuilder},
     {"nSetupParagraph", "(J[CIFIF[IIIIZ[I[I[II)V", (void*) nSetupParagraph},
-    {"nAddStyleRun", "(JJIIZLjava/lang/String;[J)V", (void*) nAddStyleRun},
-    {"nAddReplacementRun", "(JIIFLjava/lang/String;[J)V", (void*) nAddReplacementRun},
+    {"nAddStyleRun", "(JJIIZ)V", (void*) nAddStyleRun},
+    {"nAddReplacementRun", "(JJIIF)V", (void*) nAddReplacementRun},
     {"nComputeLineBreaks", "(JLandroid/text/StaticLayout$LineBreaks;[I[F[F[F[II[F)I",
         (void*) nComputeLineBreaks}
 };
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 33c8304..dec6c02 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -219,7 +219,7 @@
         strcpy(cmdline, "unknown");
 
         sprintf(proc_path, "/proc/%d/cmdline", pid);
-        fd = open(proc_path, O_RDONLY);
+        fd = open(proc_path, O_RDONLY | O_CLOEXEC);
         if (fd >= 0) {
             int rc = read(fd, cmdline, sizeof(cmdline)-1);
             cmdline[rc] = 0;
@@ -555,7 +555,7 @@
         return false;
     }
 
-    int fd = open(text, O_WRONLY);
+    int fd = open(text, O_WRONLY | O_CLOEXEC);
     if (fd >= 0) {
         sprintf(text, "%" PRId32, pid);
         write(fd, text, strlen(text));
@@ -603,7 +603,7 @@
 
 static jlong getFreeMemoryImpl(const char* const sums[], const size_t sumsLen[], size_t num)
 {
-    int fd = open("/proc/meminfo", O_RDONLY);
+    int fd = open("/proc/meminfo", O_RDONLY | O_CLOEXEC);
 
     if (fd < 0) {
         ALOGW("Unable to open /proc/meminfo");
@@ -716,7 +716,7 @@
         sizesArray[i] = 0;
     }
 
-    int fd = open(file.string(), O_RDONLY);
+    int fd = open(file.string(), O_RDONLY | O_CLOEXEC);
 
     if (fd >= 0) {
         const size_t BUFFER_SIZE = 2048;
@@ -1023,7 +1023,7 @@
         jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
         return JNI_FALSE;
     }
-    int fd = open(file8, O_RDONLY);
+    int fd = open(file8, O_RDONLY | O_CLOEXEC);
 
     if (fd < 0) {
         if (kDebugProc) {
@@ -1157,7 +1157,7 @@
         char data[PATH_MAX];
         snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
 
-        int fd = open(path, O_RDONLY);
+        int fd = open(path, O_RDONLY | O_CLOEXEC);
         if (fd < 0) {
             continue;
         }
diff --git a/core/jni/android_util_StatsLog.cpp b/core/jni/android_util_StatsLog.cpp
deleted file mode 100644
index c992365..0000000
--- a/core/jni/android_util_StatsLog.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2007-2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <fcntl.h>
-#include <log/log_event_list.h>
-
-#include <log/log.h>
-
-#include <nativehelper/JNIHelp.h>
-#include "core_jni_helpers.h"
-#include "jni.h"
-
-#define UNUSED  __attribute__((__unused__))
-
-namespace android {
-
-static jclass gCollectionClass;
-static jmethodID gCollectionAddID;
-
-static jclass gIntegerClass;
-static jfieldID gIntegerValueID;
-
-static jclass gLongClass;
-static jfieldID gLongValueID;
-
-static jclass gFloatClass;
-static jfieldID gFloatValueID;
-
-static jclass gStringClass;
-
-/*
- * In class android.util.StatsLog:
- *  static native int writeInt(int tag, int value)
- */
-static jint android_util_StatsLog_write_Integer(JNIEnv* env UNUSED,
-                                                     jobject clazz UNUSED,
-                                                     jint tag, jint value)
-{
-    android_log_event_list ctx(tag);
-    ctx << (int32_t)value;
-    return ctx.write(LOG_ID_STATS);
-}
-
-/*
- * In class android.util.StatsLog:
- *  static native int writeLong(long tag, long value)
- */
-static jint android_util_StatsLog_write_Long(JNIEnv* env UNUSED,
-                                                  jobject clazz UNUSED,
-                                                  jint tag, jlong value)
-{
-    android_log_event_list ctx(tag);
-    ctx << (int64_t)value;
-    return ctx.write(LOG_ID_STATS);
-}
-
-/*
- * In class android.util.StatsLog:
- *  static native int writeFloat(long tag, float value)
- */
-static jint android_util_StatsLog_write_Float(JNIEnv* env UNUSED,
-                                                  jobject clazz UNUSED,
-                                                  jint tag, jfloat value)
-{
-    android_log_event_list ctx(tag);
-    ctx << (float)value;
-    return ctx.write(LOG_ID_STATS);
-}
-
-/*
- * In class android.util.StatsLog:
- *  static native int writeString(int tag, String value)
- */
-static jint android_util_StatsLog_write_String(JNIEnv* env,
-                                                    jobject clazz UNUSED,
-                                                    jint tag, jstring value) {
-    android_log_event_list ctx(tag);
-    // Don't throw NPE -- I feel like it's sort of mean for a logging function
-    // to be all crashy if you pass in NULL -- but make the NULL value explicit.
-    if (value != NULL) {
-        const char *str = env->GetStringUTFChars(value, NULL);
-        ctx << str;
-        env->ReleaseStringUTFChars(value, str);
-    } else {
-        ctx << "NULL";
-    }
-    return ctx.write(LOG_ID_STATS);
-}
-
-/*
- * In class android.util.StatsLog:
- *  static native int writeArray(long tag, Object... value)
- */
-static jint android_util_StatsLog_write_Array(JNIEnv* env, jobject clazz,
-                                                   jint tag, jobjectArray value) {
-    android_log_event_list ctx(tag);
-
-    if (value == NULL) {
-        ctx << "[NULL]";
-        return ctx.write(LOG_ID_STATS);
-    }
-
-    jsize copied = 0, num = env->GetArrayLength(value);
-    for (; copied < num && copied < 255; ++copied) {
-        if (ctx.status()) break;
-        jobject item = env->GetObjectArrayElement(value, copied);
-        if (item == NULL) {
-            ctx << "NULL";
-        } else if (env->IsInstanceOf(item, gStringClass)) {
-            const char *str = env->GetStringUTFChars((jstring) item, NULL);
-            ctx << str;
-            env->ReleaseStringUTFChars((jstring) item, str);
-        } else if (env->IsInstanceOf(item, gIntegerClass)) {
-            ctx << (int32_t)env->GetIntField(item, gIntegerValueID);
-        } else if (env->IsInstanceOf(item, gLongClass)) {
-            ctx << (int64_t)env->GetLongField(item, gLongValueID);
-        } else if (env->IsInstanceOf(item, gFloatClass)) {
-            ctx << (float)env->GetFloatField(item, gFloatValueID);
-        } else {
-            jniThrowException(env,
-                    "java/lang/IllegalArgumentException",
-                    "Invalid payload item type");
-            return -1;
-        }
-        env->DeleteLocalRef(item);
-    }
-    return ctx.write(LOG_ID_STATS);
-}
-
-/*
- * JNI registration.
- */
-static const JNINativeMethod gRegisterMethods[] = {
-    /* name, signature, funcPtr */
-    { "writeInt", "(II)I", (void*) android_util_StatsLog_write_Integer },
-    { "writeLong", "(IJ)I", (void*) android_util_StatsLog_write_Long },
-    { "writeFloat", "(IF)I", (void*) android_util_StatsLog_write_Float },
-    { "writeString",
-      "(ILjava/lang/String;)I",
-      (void*) android_util_StatsLog_write_String
-    },
-    { "writeArray",
-      "(I[Ljava/lang/Object;)I",
-      (void*) android_util_StatsLog_write_Array
-    },
-};
-
-static struct { const char *name; jclass *clazz; } gClasses[] = {
-    { "java/lang/Integer", &gIntegerClass },
-    { "java/lang/Long", &gLongClass },
-    { "java/lang/Float", &gFloatClass },
-    { "java/lang/String", &gStringClass },
-    { "java/util/Collection", &gCollectionClass },
-};
-
-static struct { jclass *c; const char *name, *ft; jfieldID *id; } gFields[] = {
-    { &gIntegerClass, "value", "I", &gIntegerValueID },
-    { &gLongClass, "value", "J", &gLongValueID },
-    { &gFloatClass, "value", "F", &gFloatValueID },
-};
-
-static struct { jclass *c; const char *name, *mt; jmethodID *id; } gMethods[] = {
-    { &gCollectionClass, "add", "(Ljava/lang/Object;)Z", &gCollectionAddID },
-};
-
-int register_android_util_StatsLog(JNIEnv* env) {
-    for (int i = 0; i < NELEM(gClasses); ++i) {
-        jclass clazz = FindClassOrDie(env, gClasses[i].name);
-        *gClasses[i].clazz = MakeGlobalRefOrDie(env, clazz);
-    }
-
-    for (int i = 0; i < NELEM(gFields); ++i) {
-        *gFields[i].id = GetFieldIDOrDie(env,
-                *gFields[i].c, gFields[i].name, gFields[i].ft);
-    }
-
-    for (int i = 0; i < NELEM(gMethods); ++i) {
-        *gMethods[i].id = GetMethodIDOrDie(env,
-                *gMethods[i].c, gMethods[i].name, gMethods[i].mt);
-    }
-
-    return RegisterMethodsOrDie(
-            env,
-            "android/util/StatsLog",
-            gRegisterMethods, NELEM(gRegisterMethods));
-}
-
-}; // namespace android
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index a9b849e..8ae9ada 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -98,6 +98,18 @@
 
 // ----------------------------------------------------------------------------
 
+static jlong nativeCreateTransaction(JNIEnv* env, jclass clazz) {
+    return reinterpret_cast<jlong>(new SurfaceComposerClient::Transaction);
+}
+
+static void releaseTransaction(SurfaceComposerClient::Transaction* t) {
+    delete t;
+}
+
+static jlong nativeGetNativeTransactionFinalizer(JNIEnv* env, jclass clazz) {
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&releaseTransaction));
+}
+
 static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
         jstring nameStr, jint w, jint h, jint format, jint flags, jlong parentObject,
         jint windowType, jint ownerUid) {
@@ -278,69 +290,72 @@
     }
 }
 
-static void nativeOpenTransaction(JNIEnv* env, jclass clazz) {
-    SurfaceComposerClient::openGlobalTransaction();
+static void nativeApplyTransaction(JNIEnv* env, jclass clazz, jlong transactionObj, jboolean sync) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+    transaction->apply(sync);
 }
 
-
-static void nativeCloseTransaction(JNIEnv* env, jclass clazz, jboolean sync) {
-    SurfaceComposerClient::closeGlobalTransaction(sync);
+static void nativeSetAnimationTransaction(JNIEnv* env, jclass clazz, jlong transactionObj) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+    transaction->setAnimationTransaction();
 }
 
-static void nativeSetAnimationTransaction(JNIEnv* env, jclass clazz) {
-    SurfaceComposerClient::setAnimationTransaction();
-}
+static void nativeSetLayer(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jlong nativeObject, jint zorder) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
 
-static void nativeSetLayer(JNIEnv* env, jclass clazz, jlong nativeObject, jint zorder) {
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
-    status_t err = ctrl->setLayer(zorder);
-    if (err < 0 && err != NO_INIT) {
-        doThrowIAE(env);
-    }
+    transaction->setLayer(ctrl, zorder);
 }
 
-static void nativeSetRelativeLayer(JNIEnv* env, jclass clazz, jlong nativeObject,
+static void nativeSetRelativeLayer(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jlong nativeObject,
         jobject relativeTo, jint zorder) {
+
     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
     sp<IBinder> handle = ibinderForJavaObject(env, relativeTo);
 
-    ctrl->setRelativeLayer(handle, zorder);
+    {
+        auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+        transaction->setRelativeLayer(ctrl, handle, zorder);
+    }
 }
 
-static void nativeSetPosition(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat x, jfloat y) {
+static void nativeSetPosition(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jlong nativeObject, jfloat x, jfloat y) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
-    status_t err = ctrl->setPosition(x, y);
-    if (err < 0 && err != NO_INIT) {
-        doThrowIAE(env);
-    }
+    transaction->setPosition(ctrl, x, y);
 }
 
 static void nativeSetGeometryAppliesWithResize(JNIEnv* env, jclass clazz,
+jlong transactionObj,
         jlong nativeObject) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
-    status_t err = ctrl->setGeometryAppliesWithResize();
-    if (err < 0 && err != NO_INIT) {
-        doThrowIAE(env);
-    }
+    transaction->setGeometryAppliesWithResize(ctrl);
 }
 
-static void nativeSetSize(JNIEnv* env, jclass clazz, jlong nativeObject, jint w, jint h) {
+static void nativeSetSize(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jlong nativeObject, jint w, jint h) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
-    status_t err = ctrl->setSize(w, h);
-    if (err < 0 && err != NO_INIT) {
-        doThrowIAE(env);
-    }
+    transaction->setSize(ctrl, w, h);
 }
 
-static void nativeSetFlags(JNIEnv* env, jclass clazz, jlong nativeObject, jint flags, jint mask) {
+static void nativeSetFlags(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jlong nativeObject, jint flags, jint mask) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
-    status_t err = ctrl->setFlags(flags, mask);
-    if (err < 0 && err != NO_INIT) {
-        doThrowIAE(env);
-    }
+    transaction->setFlags(ctrl, flags, mask);
 }
 
-static void nativeSetTransparentRegionHint(JNIEnv* env, jclass clazz, jlong nativeObject, jobject regionObj) {
+static void nativeSetTransparentRegionHint(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jlong nativeObject, jobject regionObj) {
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
     SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
     if (!region) {
@@ -359,65 +374,65 @@
         }
     }
 
-    status_t err = ctrl->setTransparentRegionHint(reg);
-    if (err < 0 && err != NO_INIT) {
-        doThrowIAE(env);
+    {
+        auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+        transaction->setTransparentRegionHint(ctrl, reg);
     }
 }
 
-static void nativeSetAlpha(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat alpha) {
+static void nativeSetAlpha(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jlong nativeObject, jfloat alpha) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
-    status_t err = ctrl->setAlpha(alpha);
-    if (err < 0 && err != NO_INIT) {
-        doThrowIAE(env);
-    }
+    transaction->setAlpha(ctrl, alpha);
 }
 
-static void nativeSetColor(JNIEnv* env, jclass clazz, jlong nativeObject, jfloatArray fColor) {
+static void nativeSetColor(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jlong nativeObject, jfloatArray fColor) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+
     float* floatColors = env->GetFloatArrayElements(fColor, 0);
     half3 color(floatColors[0], floatColors[1], floatColors[2]);
-    status_t err = ctrl->setColor(color);
-    if (err < 0 && err != NO_INIT) {
-        doThrowIAE(env);
-    }
+    transaction->setColor(ctrl, color);
 }
 
-static void nativeSetMatrix(JNIEnv* env, jclass clazz, jlong nativeObject,
+static void nativeSetMatrix(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jlong nativeObject,
         jfloat dsdx, jfloat dtdx, jfloat dtdy, jfloat dsdy) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
-    status_t err = ctrl->setMatrix(dsdx, dtdx, dtdy, dsdy);
-    if (err < 0 && err != NO_INIT) {
-        doThrowIAE(env);
-    }
+    transaction->setMatrix(ctrl, dsdx, dtdx, dtdy, dsdy);
 }
 
-static void nativeSetWindowCrop(JNIEnv* env, jclass clazz, jlong nativeObject,
+static void nativeSetWindowCrop(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jlong nativeObject,
         jint l, jint t, jint r, jint b) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
     Rect crop(l, t, r, b);
-    status_t err = ctrl->setCrop(crop);
-    if (err < 0 && err != NO_INIT) {
-        doThrowIAE(env);
-    }
+    transaction->setCrop(ctrl, crop);
 }
 
-static void nativeSetFinalCrop(JNIEnv* env, jclass clazz, jlong nativeObject,
+static void nativeSetFinalCrop(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jlong nativeObject,
         jint l, jint t, jint r, jint b) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
     Rect crop(l, t, r, b);
-    status_t err = ctrl->setFinalCrop(crop);
-    if (err < 0 && err != NO_INIT) {
-        doThrowIAE(env);
-    }
+    transaction->setFinalCrop(ctrl, crop);
 }
 
-static void nativeSetLayerStack(JNIEnv* env, jclass clazz, jlong nativeObject, jint layerStack) {
+static void nativeSetLayerStack(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jlong nativeObject, jint layerStack) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
-    status_t err = ctrl->setLayerStack(layerStack);
-    if (err < 0 && err != NO_INIT) {
-        doThrowIAE(env);
-    }
+    transaction->setLayerStack(ctrl, layerStack);
 }
 
 static jobject nativeGetBuiltInDisplay(JNIEnv* env, jclass clazz, jint id) {
@@ -440,6 +455,7 @@
 }
 
 static void nativeSetDisplaySurface(JNIEnv* env, jclass clazz,
+        jlong transactionObj,
         jobject tokenObj, jlong nativeSurfaceObject) {
     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
     if (token == NULL) return;
@@ -448,8 +464,14 @@
     if (sur != NULL) {
         bufferProducer = sur->getIGraphicBufferProducer();
     }
-    status_t err = SurfaceComposerClient::setDisplaySurface(token,
-            bufferProducer);
+
+
+    status_t err = NO_ERROR;
+    {
+        auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+        err = transaction->setDisplaySurface(token,
+                bufferProducer);
+    }
     if (err != NO_ERROR) {
         doThrowIAE(env, "Illegal Surface, could not enable async mode. Was this"
                 " Surface created with singleBufferMode?");
@@ -457,14 +479,20 @@
 }
 
 static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
+        jlong transactionObj,
         jobject tokenObj, jint layerStack) {
+
     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
     if (token == NULL) return;
 
-    SurfaceComposerClient::setDisplayLayerStack(token, layerStack);
+    {
+        auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+        transaction->setDisplayLayerStack(token, layerStack);
+    }
 }
 
 static void nativeSetDisplayProjection(JNIEnv* env, jclass clazz,
+        jlong transactionObj,
         jobject tokenObj, jint orientation,
         jint layerStackRect_left, jint layerStackRect_top, jint layerStackRect_right, jint layerStackRect_bottom,
         jint displayRect_left, jint displayRect_top, jint displayRect_right, jint displayRect_bottom) {
@@ -472,14 +500,23 @@
     if (token == NULL) return;
     Rect layerStackRect(layerStackRect_left, layerStackRect_top, layerStackRect_right, layerStackRect_bottom);
     Rect displayRect(displayRect_left, displayRect_top, displayRect_right, displayRect_bottom);
-    SurfaceComposerClient::setDisplayProjection(token, orientation, layerStackRect, displayRect);
+
+    {
+        auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+        transaction->setDisplayProjection(token, orientation, layerStackRect, displayRect);
+    }
 }
 
 static void nativeSetDisplaySize(JNIEnv* env, jclass clazz,
+        jlong transactionObj,
         jobject tokenObj, jint width, jint height) {
     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
     if (token == NULL) return;
-    SurfaceComposerClient::setDisplaySize(token, width, height);
+
+    {
+        auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+        transaction->setDisplaySize(token, width, height);
+    }
 }
 
 static jobjectArray nativeGetDisplayConfigs(JNIEnv* env, jclass clazz,
@@ -722,52 +759,73 @@
     return JNI_TRUE;
 }
 
-static void nativeDeferTransactionUntil(JNIEnv* env, jclass clazz, jlong nativeObject,
+static void nativeDeferTransactionUntil(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jlong nativeObject,
         jobject handleObject, jlong frameNumber) {
     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
     sp<IBinder> handle = ibinderForJavaObject(env, handleObject);
 
-    ctrl->deferTransactionUntil(handle, frameNumber);
+    {
+        auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+        transaction->deferTransactionUntil(ctrl, handle, frameNumber);
+    }
 }
 
-static void nativeDeferTransactionUntilSurface(JNIEnv* env, jclass clazz, jlong nativeObject,
+static void nativeDeferTransactionUntilSurface(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jlong nativeObject,
         jlong surfaceObject, jlong frameNumber) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
     sp<Surface> barrier = reinterpret_cast<Surface *>(surfaceObject);
 
-    ctrl->deferTransactionUntil(barrier, frameNumber);
+    transaction->deferTransactionUntil(ctrl, barrier, frameNumber);
 }
 
-static void nativeReparentChildren(JNIEnv* env, jclass clazz, jlong nativeObject,
+static void nativeReparentChildren(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jlong nativeObject,
         jobject newParentObject) {
+
     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
     sp<IBinder> handle = ibinderForJavaObject(env, newParentObject);
 
-    ctrl->reparentChildren(handle);
+    {
+        auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+        transaction->reparentChildren(ctrl, handle);
+    }
 }
 
-static void nativeReparent(JNIEnv* env, jclass clazz, jlong nativeObject,
+static void nativeReparent(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jlong nativeObject,
         jobject newParentObject) {
     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
     sp<IBinder> parentHandle = ibinderForJavaObject(env, newParentObject);
-    ctrl->reparent(parentHandle);
+
+    {
+        auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+        transaction->reparent(ctrl, parentHandle);
+    }
 }
 
-static void nativeSeverChildren(JNIEnv* env, jclass clazz, jlong nativeObject) {
+static void nativeSeverChildren(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jlong nativeObject) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
-    ctrl->detachChildren();
+    transaction->detachChildren(ctrl);
 }
 
-static void nativeSetOverrideScalingMode(JNIEnv* env, jclass clazz, jlong nativeObject,
+static void nativeSetOverrideScalingMode(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jlong nativeObject,
         jint scalingMode) {
-    auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
 
-    ctrl->setOverrideScalingMode(scalingMode);
+    auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    transaction->setOverrideScalingMode(ctrl, scalingMode);
 }
 
 static jobject nativeGetHandle(JNIEnv* env, jclass clazz, jlong nativeObject) {
     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
-
     return javaObjectForIBinder(env, ctrl->getHandle());
 }
 
@@ -802,37 +860,39 @@
             (void*)nativeScreenshotBitmap },
     {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;Landroid/graphics/Rect;IIIIZZ)V",
             (void*)nativeScreenshot },
-    {"nativeOpenTransaction", "()V",
-            (void*)nativeOpenTransaction },
-    {"nativeCloseTransaction", "(Z)V",
-            (void*)nativeCloseTransaction },
-    {"nativeSetAnimationTransaction", "()V",
+    {"nativeCreateTransaction", "()J",
+            (void*)nativeCreateTransaction },
+    {"nativeApplyTransaction", "(JZ)V",
+            (void*)nativeApplyTransaction },
+    {"nativeGetNativeTransactionFinalizer", "()J",
+            (void*)nativeGetNativeTransactionFinalizer },
+    {"nativeSetAnimationTransaction", "(J)V",
             (void*)nativeSetAnimationTransaction },
-    {"nativeSetLayer", "(JI)V",
+    {"nativeSetLayer", "(JJI)V",
             (void*)nativeSetLayer },
-    {"nativeSetRelativeLayer", "(JLandroid/os/IBinder;I)V",
+    {"nativeSetRelativeLayer", "(JJLandroid/os/IBinder;I)V",
             (void*)nativeSetRelativeLayer },
-    {"nativeSetPosition", "(JFF)V",
+    {"nativeSetPosition", "(JJFF)V",
             (void*)nativeSetPosition },
-    {"nativeSetGeometryAppliesWithResize", "(J)V",
+    {"nativeSetGeometryAppliesWithResize", "(JJ)V",
             (void*)nativeSetGeometryAppliesWithResize },
-    {"nativeSetSize", "(JII)V",
+    {"nativeSetSize", "(JJII)V",
             (void*)nativeSetSize },
-    {"nativeSetTransparentRegionHint", "(JLandroid/graphics/Region;)V",
+    {"nativeSetTransparentRegionHint", "(JJLandroid/graphics/Region;)V",
             (void*)nativeSetTransparentRegionHint },
-    {"nativeSetAlpha", "(JF)V",
+    {"nativeSetAlpha", "(JJF)V",
             (void*)nativeSetAlpha },
-    {"nativeSetColor", "(J[F)V",
+    {"nativeSetColor", "(JJ[F)V",
             (void*)nativeSetColor },
-    {"nativeSetMatrix", "(JFFFF)V",
+    {"nativeSetMatrix", "(JJFFFF)V",
             (void*)nativeSetMatrix },
-    {"nativeSetFlags", "(JII)V",
+    {"nativeSetFlags", "(JJII)V",
             (void*)nativeSetFlags },
-    {"nativeSetWindowCrop", "(JIIII)V",
+    {"nativeSetWindowCrop", "(JJIIII)V",
             (void*)nativeSetWindowCrop },
-    {"nativeSetFinalCrop", "(JIIII)V",
+    {"nativeSetFinalCrop", "(JJIIII)V",
             (void*)nativeSetFinalCrop },
-    {"nativeSetLayerStack", "(JI)V",
+    {"nativeSetLayerStack", "(JJI)V",
             (void*)nativeSetLayerStack },
     {"nativeGetBuiltInDisplay", "(I)Landroid/os/IBinder;",
             (void*)nativeGetBuiltInDisplay },
@@ -840,13 +900,13 @@
             (void*)nativeCreateDisplay },
     {"nativeDestroyDisplay", "(Landroid/os/IBinder;)V",
             (void*)nativeDestroyDisplay },
-    {"nativeSetDisplaySurface", "(Landroid/os/IBinder;J)V",
+    {"nativeSetDisplaySurface", "(JLandroid/os/IBinder;J)V",
             (void*)nativeSetDisplaySurface },
-    {"nativeSetDisplayLayerStack", "(Landroid/os/IBinder;I)V",
+    {"nativeSetDisplayLayerStack", "(JLandroid/os/IBinder;I)V",
             (void*)nativeSetDisplayLayerStack },
-    {"nativeSetDisplayProjection", "(Landroid/os/IBinder;IIIIIIIII)V",
+    {"nativeSetDisplayProjection", "(JLandroid/os/IBinder;IIIIIIIII)V",
             (void*)nativeSetDisplayProjection },
-    {"nativeSetDisplaySize", "(Landroid/os/IBinder;II)V",
+    {"nativeSetDisplaySize", "(JLandroid/os/IBinder;II)V",
             (void*)nativeSetDisplaySize },
     {"nativeGetDisplayConfigs", "(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$PhysicalDisplayInfo;",
             (void*)nativeGetDisplayConfigs },
@@ -872,17 +932,17 @@
             (void*)nativeGetAnimationFrameStats },
     {"nativeSetDisplayPowerMode", "(Landroid/os/IBinder;I)V",
             (void*)nativeSetDisplayPowerMode },
-    {"nativeDeferTransactionUntil", "(JLandroid/os/IBinder;J)V",
+    {"nativeDeferTransactionUntil", "(JJLandroid/os/IBinder;J)V",
             (void*)nativeDeferTransactionUntil },
-    {"nativeDeferTransactionUntilSurface", "(JJJ)V",
+    {"nativeDeferTransactionUntilSurface", "(JJJJ)V",
             (void*)nativeDeferTransactionUntilSurface },
-    {"nativeReparentChildren", "(JLandroid/os/IBinder;)V",
+    {"nativeReparentChildren", "(JJLandroid/os/IBinder;)V",
             (void*)nativeReparentChildren } ,
-    {"nativeReparent", "(JLandroid/os/IBinder;)V",
+    {"nativeReparent", "(JJLandroid/os/IBinder;)V",
             (void*)nativeReparent },
-    {"nativeSeverChildren", "(J)V",
+    {"nativeSeverChildren", "(JJ)V",
             (void*)nativeSeverChildren } ,
-    {"nativeSetOverrideScalingMode", "(JI)V",
+    {"nativeSetOverrideScalingMode", "(JJI)V",
             (void*)nativeSetOverrideScalingMode },
     {"nativeGetHandle", "(J)Landroid/os/IBinder;",
             (void*)nativeGetHandle },
diff --git a/core/proto/android/app/notification_channel.proto b/core/proto/android/app/notification_channel.proto
index bbc1956..0388547 100644
--- a/core/proto/android/app/notification_channel.proto
+++ b/core/proto/android/app/notification_channel.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 option java_package = "android.app";
 option java_multiple_files = true;
 
@@ -27,28 +26,28 @@
  * An android.app.NotificationChannel object.
  */
 message NotificationChannelProto {
-    string id = 1;
-    string name = 2;
-    string description = 3;
-    int32 importance = 4;
-    bool can_bypass_dnd = 5;
+    optional string id = 1;
+    optional string name = 2;
+    optional string description = 3;
+    optional int32 importance = 4;
+    optional bool can_bypass_dnd = 5;
     // Default is VISIBILITY_NO_OVERRIDE (-1000).
-    int32 lockscreen_visibility = 6;
-    string sound = 7;
-    bool use_lights = 8;
+    optional int32 lockscreen_visibility = 6;
+    optional string sound = 7;
+    optional bool use_lights = 8;
     // Default is 0.
-    int32 light_color = 9;
+    optional int32 light_color = 9;
     repeated int64 vibration = 10;
     // Bitwise representation of fields that have been changed by the user,
     // preventing the app from making changes to these fields.
-    int32 user_locked_fields = 11;
-    bool is_vibration_enabled = 12;
+    optional int32 user_locked_fields = 11;
+    optional bool is_vibration_enabled = 12;
     // Default is true.
-    bool show_badge = 13;
+    optional bool show_badge = 13;
     // Default is false.
-    bool is_deleted = 14;
-    string group = 15;
-    android.media.AudioAttributesProto audio_attributes = 16;
+    optional bool is_deleted = 14;
+    optional string group = 15;
+    optional android.media.AudioAttributesProto audio_attributes = 16;
     // If this is a blockable system notification channel.
-    bool is_blockable_system = 17;
+    optional bool is_blockable_system = 17;
 }
diff --git a/core/proto/android/app/notification_channel_group.proto b/core/proto/android/app/notification_channel_group.proto
index 9cb456f..89a540f 100644
--- a/core/proto/android/app/notification_channel_group.proto
+++ b/core/proto/android/app/notification_channel_group.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 option java_package = "android.app";
 option java_multiple_files = true;
 
@@ -27,9 +26,9 @@
  * An android.app.NotificationChannelGroup object.
  */
 message NotificationChannelGroupProto {
-    string id = 1;
-    string name = 2;
-    string description = 3;
-    bool is_blocked = 4;
+    optional string id = 1;
+    optional string name = 2;
+    optional string description = 3;
+    optional bool is_blocked = 4;
     repeated android.app.NotificationChannelProto channels = 5;
 }
diff --git a/core/proto/android/app/notificationmanager.proto b/core/proto/android/app/notificationmanager.proto
index 4dfd0cf..7d774ae 100644
--- a/core/proto/android/app/notificationmanager.proto
+++ b/core/proto/android/app/notificationmanager.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 option java_package = "android.app";
 option java_multiple_files = true;
 
@@ -48,8 +47,8 @@
         // Only starred contacts are prioritized.
         STARRED = 2;
     }
-    Sender priority_call_sender = 2;
-    Sender priority_message_sender = 3;
+    optional Sender priority_call_sender = 2;
+    optional Sender priority_message_sender = 3;
 
     enum SuppressedVisualEffect {
         SVE_UNKNOWN = 0;
diff --git a/core/proto/android/app/window_configuration.proto b/core/proto/android/app/window_configuration.proto
index 03910df..4d748e8 100644
--- a/core/proto/android/app/window_configuration.proto
+++ b/core/proto/android/app/window_configuration.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 option java_package = "android.app";
 option java_multiple_files = true;
 
@@ -25,7 +24,7 @@
 
 /** Proto representation for WindowConfiguration.java class. */
 message WindowConfigurationProto {
-  .android.graphics.RectProto app_bounds = 1;
-  int32 windowing_mode = 2;
-  int32 activity_type = 3;
+  optional .android.graphics.RectProto app_bounds = 1;
+  optional int32 windowing_mode = 2;
+  optional int32 activity_type = 3;
 }
diff --git a/core/proto/android/content/component_name.proto b/core/proto/android/content/component_name.proto
index 90f6ffb..fc0c8c5 100644
--- a/core/proto/android/content/component_name.proto
+++ b/core/proto/android/content/component_name.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 option java_package = "android.content";
 option java_multiple_files = true;
 
@@ -25,7 +24,7 @@
  * An android.content.ComponentName object.
  */
 message ComponentNameProto {
-    string package_name = 1;
-    string class_name = 2;
+    optional string package_name = 1;
+    optional string class_name = 2;
 }
 
diff --git a/core/proto/android/content/configuration.proto b/core/proto/android/content/configuration.proto
index 804e0b4..111b27f 100644
--- a/core/proto/android/content/configuration.proto
+++ b/core/proto/android/content/configuration.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 option java_package = "android.content";
 option java_multiple_files = true;
 
@@ -28,22 +27,22 @@
  * An android resource configuration.
  */
 message ConfigurationProto {
-  float font_scale = 1;
-  uint32 mcc = 2;
-  uint32 mnc = 3;
+  optional float font_scale = 1;
+  optional uint32 mcc = 2;
+  optional uint32 mnc = 3;
   repeated LocaleProto locales = 4;
-  uint32 screen_layout = 5;
-  uint32 touchscreen = 6;
-  uint32 keyboard_hidden = 7;
-  uint32 hard_keyboard_hidden = 8;
-  uint32 navigation = 9;
-  uint32 navigation_hidden = 10;
-  uint32 orientation = 11;
-  uint32 ui_mode = 12;
-  uint32 screen_width_dp = 13;
-  uint32 screen_height_dp = 14;
-  uint32 smallest_screen_width_dp = 15;
-  uint32 density_dpi = 16;
-  .android.app.WindowConfigurationProto window_configuration = 17;
+  optional uint32 screen_layout = 5;
+  optional uint32 touchscreen = 6;
+  optional uint32 keyboard_hidden = 7;
+  optional uint32 hard_keyboard_hidden = 8;
+  optional uint32 navigation = 9;
+  optional uint32 navigation_hidden = 10;
+  optional uint32 orientation = 11;
+  optional uint32 ui_mode = 12;
+  optional uint32 screen_width_dp = 13;
+  optional uint32 screen_height_dp = 14;
+  optional uint32 smallest_screen_width_dp = 15;
+  optional uint32 density_dpi = 16;
+  optional .android.app.WindowConfigurationProto window_configuration = 17;
 }
 
diff --git a/core/proto/android/content/featureinfo.proto b/core/proto/android/content/featureinfo.proto
new file mode 100644
index 0000000..a750120
--- /dev/null
+++ b/core/proto/android/content/featureinfo.proto
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+option java_package = "android.content.pm";
+option java_multiple_files = true;
+
+package android.content.pm;
+
+message FeatureInfoProto {
+    optional string name = 1;
+    optional int32 version = 2;
+    optional string gles_version = 3;
+    optional int32 flags = 4;
+}
diff --git a/core/proto/android/content/intent.proto b/core/proto/android/content/intent.proto
new file mode 100644
index 0000000..4f49744
--- /dev/null
+++ b/core/proto/android/content/intent.proto
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+option java_package = "android.content";
+option java_multiple_files = true;
+
+import "frameworks/base/core/proto/android/os/patternmatcher.proto";
+
+package android.content;
+
+// Next Tag: 13
+message IntentProto {
+    optional string action = 1;
+    repeated string categories = 2;
+    optional string data = 3;
+    optional string type = 4;
+    optional string flag = 5;
+    optional string package = 6;
+    optional string component = 7;
+    optional string source_bounds = 8;
+    optional string clip_data = 9;
+    optional string extras = 10;
+    optional int32 content_user_hint = 11;
+    optional string selector = 12;
+}
+
+// Next Tag: 11
+message IntentFilterProto {
+    repeated string actions = 1;
+    repeated string categories = 2;
+    repeated string data_schemes = 3;
+    repeated android.os.PatternMatcherProto data_scheme_specs = 4;
+    repeated AuthorityEntryProto data_authorities = 5;
+    repeated android.os.PatternMatcherProto data_paths = 6;
+    repeated string data_types = 7;
+    optional int32 priority = 8;
+    optional bool has_partial_types = 9;
+    optional bool get_auto_verify = 10;
+}
+
+message AuthorityEntryProto {
+    optional string host = 1;
+    optional bool wild = 2;
+    optional int32 port = 3;
+}
diff --git a/core/proto/android/content/locale.proto b/core/proto/android/content/locale.proto
index 961b10b..f0de31c 100644
--- a/core/proto/android/content/locale.proto
+++ b/core/proto/android/content/locale.proto
@@ -14,16 +14,15 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 option java_package = "android.content";
 option java_multiple_files = true;
 
 package android.content;
 
 message LocaleProto {
-  string language = 1;
-  string country = 2;
-  string variant = 3;
+  optional string language = 1;
+  optional string country = 2;
+  optional string variant = 3;
 }
 
diff --git a/core/proto/android/graphics/rect.proto b/core/proto/android/graphics/rect.proto
index a65d331..562ffce 100644
--- a/core/proto/android/graphics/rect.proto
+++ b/core/proto/android/graphics/rect.proto
@@ -14,16 +14,15 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 package android.graphics;
 
 option java_multiple_files = true;
 
 message RectProto {
-  int32 left = 1;
-  int32 top = 2;
-  int32 right = 3;
-  int32 bottom = 4;
+  optional int32 left = 1;
+  optional int32 top = 2;
+  optional int32 right = 3;
+  optional int32 bottom = 4;
 }
 
diff --git a/core/proto/android/media/audioattributes.proto b/core/proto/android/media/audioattributes.proto
index 3aa2792..860d608 100644
--- a/core/proto/android/media/audioattributes.proto
+++ b/core/proto/android/media/audioattributes.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 option java_package = "android.media";
 option java_multiple_files = true;
 
@@ -25,10 +24,10 @@
  * An android.media.AudioAttributes object.
  */
 message AudioAttributesProto {
-    Usage usage = 1;
-    ContentType content_type = 2;
+    optional Usage usage = 1;
+    optional ContentType content_type = 2;
     // Bit representation of set flags.
-    int32 flags = 3;
+    optional int32 flags = 3;
     repeated string tags = 4;
 }
 
diff --git a/core/proto/android/os/batterystats.proto b/core/proto/android/os/batterystats.proto
index 8d85038..38879c0 100644
--- a/core/proto/android/os/batterystats.proto
+++ b/core/proto/android/os/batterystats.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 option java_multiple_files = true;
 
 package android.os;
@@ -23,13 +22,13 @@
 import "frameworks/base/core/proto/android/telephony/signalstrength.proto";
 
 message BatteryStatsProto {
-  int32 report_version = 1;
-  int64 parcel_version = 2;
-  string start_platform_version = 3;
-  string end_platform_version = 4;
-  BatteryHistoryProto history = 5;
+  optional int32 report_version = 1;
+  optional int64 parcel_version = 2;
+  optional string start_platform_version = 3;
+  optional string end_platform_version = 4;
+  optional BatteryHistoryProto history = 5;
   repeated UidProto uids = 6;
-  SystemProto system = 7;
+  optional SystemProto system = 7;
 }
 
 message BatteryHistoryProto {
@@ -37,21 +36,21 @@
 
 message ControllerActivityProto {
   // Time (milliseconds) spent in the idle state.
-  int64 idle_duration_ms = 1;
+  optional int64 idle_duration_ms = 1;
   // Time (milliseconds) spent in the receive state.
-  int64 rx_duration_ms = 2;
+  optional int64 rx_duration_ms = 2;
   // Total power (mAh) consumed by the controller in all states. The value may
   // always be 0 if the device doesn't support power calculations.
-  int64 power_mah = 3;
+  optional int64 power_mah = 3;
 
   // Represents a transmit level, where each level may draw a different amount
   // of power. The levels themselves are controller-specific (and may possibly
   // be device specific...yet to be confirmed).
   message TxLevel {
     // Transmit level. Higher levels draw more power.
-    int32 level = 1;
+    optional int32 level = 1;
     // Time spent in this specific transmit level state.
-    int64 duration_ms = 2;
+    optional int64 duration_ms = 2;
   }
   repeated TxLevel tx = 4;
 }
@@ -62,65 +61,65 @@
     // In case of device time manually reset by users:
     //   start_clock_time_ms keeps the same value in the current collection
     //   period and changes for later collection periods.
-    int64 start_clock_time_ms = 1;
+    optional int64 start_clock_time_ms = 1;
     // #times the device has been started since start_clock_time_millis.
-    int64 start_count = 2;
+    optional int64 start_count = 2;
     // Total realtime duration (= SINCE_UNPLUGGED battery_realtime_millis.)
-    int64 total_realtime_ms = 3;
-    int64 total_uptime_ms = 4;
+    optional int64 total_realtime_ms = 3;
+    optional int64 total_uptime_ms = 4;
     // Realtime duration on battery.
-    int64 battery_realtime_ms = 5;
+    optional int64 battery_realtime_ms = 5;
     // Uptime duration (i.e., not suspend).
     // Uptime is anytime the CPUs were on. The radio and Wifi chip
     // can be running while the CPUs are off.
-    int64 battery_uptime_ms = 6;
+    optional int64 battery_uptime_ms = 6;
     // Total realtime duration measured with screen off or dozing.
-    int64 screen_off_realtime_ms = 7;
+    optional int64 screen_off_realtime_ms = 7;
     // Total uptime duration measured with screen off or dozing.
-    int64 screen_off_uptime_ms = 8;
+    optional int64 screen_off_uptime_ms = 8;
     // Total time the screen was dozing while the device was running on battery.
     // For historical reasons, screen_doze_duration_msec is a subset of
     // screen_off_realtime_msec.
-    int64 screen_doze_duration_ms = 9;
+    optional int64 screen_doze_duration_ms = 9;
     // The estimated real battery capacity, which may be less than the declared
     // battery capacity (for example, because of battery aging). This field is
     // less reliable than min(max)_learned_battery_capacity_uah, use those two
     // fields whenever possible.
-    int64 estimated_battery_capacity_mah = 10;
+    optional int64 estimated_battery_capacity_mah = 10;
     // The minimum learned battery capacity in uAh.
-    int64 min_learned_battery_capacity_uah = 11;
+    optional int64 min_learned_battery_capacity_uah = 11;
     // The maximum learned battery capacity in uAh.
-    int64 max_learned_battery_capacity_uah = 12;
+    optional int64 max_learned_battery_capacity_uah = 12;
   };
-  Battery battery = 1;
+  optional Battery battery = 1;
 
   message BatteryDischarge {
     // Discharged battery percentage points since the stats were last reset
     // after charging (lower bound approximation).
-    int32 lower_bound_since_charge = 1;
+    optional int32 lower_bound_since_charge = 1;
     // Upper bound approximation.
-    int32 upper_bound_since_charge = 2;
+    optional int32 upper_bound_since_charge = 2;
     // Discharged points while screen is on.
-    int32 screen_on_since_charge = 3;
+    optional int32 screen_on_since_charge = 3;
     // Discharged points while screen is off.
-    int32 screen_off_since_charge = 4;
+    optional int32 screen_off_since_charge = 4;
     // Discharged points while screen was dozing. For historical reasons,
     // screen_doze_since_charge is a subset of screen_off_since_charge.
-    int32 screen_doze_since_charge = 5;
+    optional int32 screen_doze_since_charge = 5;
     // Total amount of battery discharged in mAh. This will only be non-zero for
     // devices that report battery discharge via a coulomb counter.
-    int64 total_mah = 6;
+    optional int64 total_mah = 6;
     // Total amount of battery discharged while the screen was off in mAh.
     // This will only be non-zero for devices that report battery discharge
     // via a coulomb counter.
-    int64 total_mah_screen_off = 7;
+    optional int64 total_mah_screen_off = 7;
     // Total amount of battery discharged while the screen was dozing in mAh.
     // This will only be non-zero for devices that report battery discharge
     // via a coulomb counter. For historical reasons, total_mah_screen_doze is
     // a subset of total_mah_screen_off.
-    int64 total_mah_screen_doze = 8;
+    optional int64 total_mah_screen_doze = 8;
   };
-  BatteryDischarge battery_discharge = 2;
+  optional BatteryDischarge battery_discharge = 2;
 
   oneof time_remaining {
     // Approximation for how much time remains until the battery is fully
@@ -138,9 +137,9 @@
   // for the entire duration should be marked MIXED.
   message BatteryLevelStep {
     // How long the battery was at the current level.
-    int64 duration_ms = 1;
+    optional int64 duration_ms = 1;
     // Battery level
-    int32 level = 2;
+    optional int32 level = 2;
 
     // State of the display. A special enum is used rather than
     // DisplayProto.State because a MIXED value needs to be in the enum, and
@@ -156,7 +155,7 @@
     }
     // The state of the display for the entire battery level step. MIXED is used
     // if there were multiple states for this step.
-    DisplayState display_state = 3;
+    optional DisplayState display_state = 3;
 
     // Indicates status in power save mode.
     enum PowerSaveMode {
@@ -166,7 +165,7 @@
     }
     // Battery Saver mode for the entire battery level step. MIXED is used
     // if there were multiple states for this step.
-    PowerSaveMode power_save_mode = 4;
+    optional PowerSaveMode power_save_mode = 4;
 
     // Indicates status in idle mode.
     enum IdleMode {
@@ -176,7 +175,7 @@
     }
     // Doze mode for the entire battery level step. MIXED is used if there were
     // multiple states for this step.
-    IdleMode idle_mode = 5;
+    optional IdleMode idle_mode = 5;
   };
   // Battery level steps when the device was charging.
   repeated BatteryLevelStep charge_step = 5;
@@ -206,109 +205,109 @@
       HSPAP = 15;
       OTHER = 16;
     };
-    Name name = 1;
-    TimerProto total = 2;
+    optional Name name = 1;
+    optional TimerProto total = 2;
   };
   repeated DataConnection data_connection = 8;
 
-  ControllerActivityProto global_bluetooth_controller = 9;
-  ControllerActivityProto global_modem_controller = 10;
-  ControllerActivityProto global_wifi_controller = 11;
+  optional ControllerActivityProto global_bluetooth_controller = 9;
+  optional ControllerActivityProto global_modem_controller = 10;
+  optional ControllerActivityProto global_wifi_controller = 11;
 
   message GlobalNetwork {
     // Total Bytes received on mobile connections.
-    int64 mobile_bytes_rx = 1;
+    optional int64 mobile_bytes_rx = 1;
     // Total Bytes transmitted on mobile connections.
-    int64 mobile_bytes_tx = 2;
+    optional int64 mobile_bytes_tx = 2;
     // Total Bytes received on wifi connections.
-    int64 wifi_bytes_rx = 3;
+    optional int64 wifi_bytes_rx = 3;
     // Total Bytes transmitted on wifi connections.
-    int64 wifi_bytes_tx = 4;
+    optional int64 wifi_bytes_tx = 4;
     // Total Packets received on mobile connections.
-    int64 mobile_packets_rx = 5;
+    optional int64 mobile_packets_rx = 5;
     // Total Packets transmitted on mobile connections.
-    int64 mobile_packets_tx = 6;
+    optional int64 mobile_packets_tx = 6;
     // Total Packets received on wifi connections.
-    int64 wifi_packets_rx = 7;
+    optional int64 wifi_packets_rx = 7;
     // Total Packets transmitted on wifi connections.
-    int64 wifi_packets_tx = 8;
+    optional int64 wifi_packets_tx = 8;
     // Total Bytes received on bluetooth connections.
-    int64 bt_bytes_rx = 9;
+    optional int64 bt_bytes_rx = 9;
     // Total Bytes transmitted on bluetooth connections.
-    int64 bt_bytes_tx = 10;
+    optional int64 bt_bytes_tx = 10;
   };
-  GlobalNetwork global_network = 12;
+  optional GlobalNetwork global_network = 12;
 
   message GlobalWifi {
     // The amount of time that wifi has been on while the device was running on
     // battery.
-    int64 on_duration_ms = 1;
+    optional int64 on_duration_ms = 1;
     // The amount of time that wifi has been on and the driver has been in the
     // running state while the device was running on battery.
-    int64 running_duration_ms = 2;
+    optional int64 running_duration_ms = 2;
   }
-  GlobalWifi global_wifi = 13;
+  optional GlobalWifi global_wifi = 13;
 
   // Kernel wakelock metrics are only recorded when the device is unplugged
   // *and* the screen is off.
   message KernelWakelock {
-    string name = 1;
+    optional string name = 1;
     // Kernel wakelock stats aren't apportioned across all kernel wakelocks (as
     // app wakelocks stats are).
-    TimerProto total = 2;
+    optional TimerProto total = 2;
     // The kernel doesn't have the data to enable printing out current and max
     // durations.
   };
   repeated KernelWakelock kernel_wakelock = 14;
 
   message Misc {
-    int64 screen_on_duration_ms = 1;
-    int64 phone_on_duration_ms = 2;
-    int64 full_wakelock_total_duration_ms = 3;
+    optional int64 screen_on_duration_ms = 1;
+    optional int64 phone_on_duration_ms = 2;
+    optional int64 full_wakelock_total_duration_ms = 3;
     // The total elapsed time that a partial wakelock was held. This duration
     // does not double count wakelocks held at the same time.
-    int64 partial_wakelock_total_duration_ms = 4;
-    int64 mobile_radio_active_duration_ms = 5;
+    optional int64 partial_wakelock_total_duration_ms = 4;
+    optional int64 mobile_radio_active_duration_ms = 5;
     // The time that is the difference between the mobile radio time we saw
     // based on the elapsed timestamp when going down vs. the given time stamp
     // from the radio.
-    int64 mobile_radio_active_adjusted_time_ms = 6;
-    int32 mobile_radio_active_count = 7;
+    optional int64 mobile_radio_active_adjusted_time_ms = 6;
+    optional int32 mobile_radio_active_count = 7;
     // The amount of time that the mobile network has been active (in a high
     // power state) but not being able to blame on an app.
-    int32 mobile_radio_active_unknown_duration_ms = 8;
+    optional int32 mobile_radio_active_unknown_duration_ms = 8;
     // Total amount of time the device was in the interactive state.
-    int64 interactive_duration_ms = 9;
-    int64 battery_saver_mode_enabled_duration_ms = 10;
-    int32 num_connectivity_changes = 11;
+    optional int64 interactive_duration_ms = 9;
+    optional int64 battery_saver_mode_enabled_duration_ms = 10;
+    optional int32 num_connectivity_changes = 11;
     // Amount of time the device was in deep Doze.
-    int64 deep_doze_enabled_duration_ms = 12;
+    optional int64 deep_doze_enabled_duration_ms = 12;
     // How many times the device went into deep Doze mode.
-    int32 deep_doze_count = 13;
+    optional int32 deep_doze_count = 13;
     // Amount of time the device was idling in deep Doze. Idling time
     // encompasses "doze" time and the maintenance windows that allow apps to
     // operate.
-    int64 deep_doze_idling_duration_ms = 14;
+    optional int64 deep_doze_idling_duration_ms = 14;
     // How many times the device idling for deep Doze mode.
-    int32 deep_doze_idling_count = 15;
-    int64 longest_deep_doze_duration_ms = 16;
+    optional int32 deep_doze_idling_count = 15;
+    optional int64 longest_deep_doze_duration_ms = 16;
     // Amount of time the device was in Doze Light.
-    int64 light_doze_enabled_duration_ms = 17;
+    optional int64 light_doze_enabled_duration_ms = 17;
     // How many times the device went into Doze Light mode.
-    int32 light_doze_count = 18;
+    optional int32 light_doze_count = 18;
     // Amount of time the device was idling in Doze Light. Idling time
     // encompasses "doze" time and the maintenance windows that allow apps to
     // operate.
-    int64 light_doze_idling_duration_ms = 19;
+    optional int64 light_doze_idling_duration_ms = 19;
     // How many times the device idling for Doze Light mode.
-    int32 light_doze_idling_count = 20;
-    int64 longest_light_doze_duration_ms = 21;
+    optional int32 light_doze_idling_count = 20;
+    optional int64 longest_light_doze_duration_ms = 21;
   }
-  Misc misc = 15;
+  optional Misc misc = 15;
 
   message PhoneSignalStrength {
-    android.telephony.SignalStrengthProto.StrengthName name = 1;
-    TimerProto total = 2;
+    optional android.telephony.SignalStrengthProto.StrengthName name = 1;
+    optional TimerProto total = 2;
   };
   repeated PhoneSignalStrength phone_signal_strength = 16;
 
@@ -328,40 +327,40 @@
       CAMERA = 11;
       MEMORY = 12;
     };
-    Sipper name = 1;
+    optional Sipper name = 1;
     // UID, only valid for the USER sipper.
-    int32 uid = 2;
+    optional int32 uid = 2;
     // Estimated power use in mAh.
-    double computed_power_mah = 3;
+    optional double computed_power_mah = 3;
     // Starting in Oreo, Battery Settings has two modes to display the battery
     // info. The first is "app usage list". In this mode, items with should_hide
     // enabled are hidden.
-    bool should_hide = 4;
+    optional bool should_hide = 4;
     // Smeared power from screen usage. Screen usage power is split and smeared
     // among apps, based on activity time.
-    double screen_power_mah = 5;
+    optional double screen_power_mah = 5;
     // Smeared power using proportional method. Power usage from hidden sippers
     // is smeared to all apps proportionally (except for screen usage).
-    double proportional_smear_mah = 6;
+    optional double proportional_smear_mah = 6;
   };
   repeated PowerUseItem power_use_item = 17;
 
   message PowerUseSummary {
-    double battery_capacity_mah = 1;
-    double computed_power_mah = 2;
+    optional double battery_capacity_mah = 1;
+    optional double computed_power_mah = 2;
     // Lower bound of actual power drained.
-    double min_drained_power_mah = 3;
+    optional double min_drained_power_mah = 3;
     // Upper bound of actual power drained.
-    double max_drained_power_mah = 4;
+    optional double max_drained_power_mah = 4;
   };
-  PowerUseSummary power_use_summary = 18;
+  optional PowerUseSummary power_use_summary = 18;
 
   message ResourcePowerManager {
-    string name = 1;
-    TimerProto total = 2;
-    TimerProto screen_off = 3;
+    optional string name = 1;
+    optional TimerProto total = 2;
+    optional TimerProto screen_off = 3;
   }
-  ResourcePowerManager resource_power_manager = 19;
+  optional ResourcePowerManager resource_power_manager = 19;
 
   message ScreenBrightness {
     enum Name {
@@ -371,17 +370,17 @@
       LIGHT = 3;
       BRIGHT = 4;
     };
-    Name name = 1;
-    TimerProto total = 2;
+    optional Name name = 1;
+    optional TimerProto total = 2;
   };
   repeated ScreenBrightness screen_brightness = 20;
 
   // Duration and number of times trying to acquire a signal
-  TimerProto signal_scanning = 21;
+  optional TimerProto signal_scanning = 21;
 
   message WakeupReason {
-    string name = 1;
-    TimerProto total = 2;
+    optional string name = 1;
+    optional TimerProto total = 2;
   };
   repeated WakeupReason wakeup_reason = 22;
 
@@ -393,8 +392,8 @@
       GOOD = 3;
       GREAT = 4;
     };
-    Name name = 1;
-    TimerProto total = 2;
+    optional Name name = 1;
+    optional TimerProto total = 2;
   };
   repeated WifiSignalStrength wifi_signal_strength = 23;
 
@@ -409,8 +408,8 @@
       ON_CONNECTED_STA_P2P = 6;
       SOFT_AP = 7;
     };
-    Name name = 1;
-    TimerProto total = 2;
+    optional Name name = 1;
+    optional TimerProto total = 2;
   };
   repeated WifiState wifi_state = 24;
 
@@ -430,19 +429,19 @@
       DORMANT = 11;
       UNINITIALIZED = 12;
     };
-    Name name = 1;
-    TimerProto total = 2;
+    optional Name name = 1;
+    optional TimerProto total = 2;
   };
   repeated WifiSupplicantState wifi_supplicant_state = 25;
 }
 
 message TimerProto {
-  int64 duration_ms = 1;
-  int64 count = 2;
+  optional int64 duration_ms = 1;
+  optional int64 count = 2;
 }
 
 message UidProto {
   // Combination of app ID and user ID.
-  int32 uid = 1;
+  optional int32 uid = 1;
   repeated string package_names = 2;
 }
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index b3a606f..5a5454e 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 option java_multiple_files = true;
 option java_outer_classname = "IncidentProtoMetadata";
 
@@ -32,6 +31,7 @@
 import "frameworks/base/core/proto/android/service/power.proto";
 import "frameworks/base/core/proto/android/service/print.proto";
 import "frameworks/base/core/proto/android/service/procstats.proto";
+import "frameworks/base/core/proto/android/server/activitymanagerservice.proto";
 import "frameworks/base/core/proto/android/providers/settings.proto";
 import "frameworks/base/core/proto/android/os/incidentheader.proto";
 import "frameworks/base/core/proto/android/os/kernelwake.proto";
@@ -51,61 +51,78 @@
     //SystemProperties system_properties = 1000;
 
     // Linux services
-    Procrank procrank = 2000 [
+    optional Procrank procrank = 2000 [
         (section).type = SECTION_COMMAND,
         (section).args = "/system/xbin/procrank"
     ];
 
-    PageTypeInfo page_type_info = 2001 [
+    optional PageTypeInfo page_type_info = 2001 [
         (section).type = SECTION_FILE,
         (section).args = "/proc/pagetypeinfo"
     ];
 
-    KernelWakeSources kernel_wake_sources = 2002 [
+    optional KernelWakeSources kernel_wake_sources = 2002 [
         (section).type = SECTION_FILE,
         (section).args = "/d/wakeup_sources"
     ];
 
 
     // System Services
-    android.service.fingerprint.FingerprintServiceDumpProto fingerprint = 3000 [
+    optional android.service.fingerprint.FingerprintServiceDumpProto fingerprint = 3000 [
         (section).type = SECTION_DUMPSYS,
         (section).args = "fingerprint --proto --incident"
     ];
 
-    android.service.NetworkStatsServiceDumpProto netstats = 3001 [
+    optional android.service.NetworkStatsServiceDumpProto netstats = 3001 [
         (section).type = SECTION_DUMPSYS,
         (section).args = "netstats --proto"
     ];
 
-    android.providers.settings.SettingsServiceDumpProto settings = 3002;
-    android.service.appwidget.AppWidgetServiceDumpProto appwidget = 3003;
-    android.service.notification.NotificationServiceDumpProto notification = 3004 [
+    optional android.providers.settings.SettingsServiceDumpProto settings = 3002;
+    optional android.service.appwidget.AppWidgetServiceDumpProto appwidget = 3003;
+    optional android.service.notification.NotificationServiceDumpProto notification = 3004 [
         (section).type = SECTION_DUMPSYS,
         (section).args = "notification --proto"
     ];
 
-    android.service.batterystats.BatteryStatsServiceDumpProto batterystats = 3005 [
+    optional android.service.batterystats.BatteryStatsServiceDumpProto batterystats = 3005 [
         (section).type = SECTION_DUMPSYS,
         (section).args = "batterystats --proto"
     ];
 
-    android.service.battery.BatteryServiceDumpProto battery = 3006 [
+    optional android.service.battery.BatteryServiceDumpProto battery = 3006 [
         (section).type = SECTION_DUMPSYS,
         (section).args = "battery --proto"
     ];
 
-    android.service.diskstats.DiskStatsServiceDumpProto diskstats = 3007 [
+    optional android.service.diskstats.DiskStatsServiceDumpProto diskstats = 3007 [
         (section).type = SECTION_DUMPSYS,
         (section).args = "diskstats --proto"
     ];
 
-    android.service.pm.PackageServiceDumpProto package = 3008;
-    android.service.power.PowerServiceDumpProto power = 3009;
-    android.service.print.PrintServiceDumpProto print = 3010;
+    optional android.service.pm.PackageServiceDumpProto package = 3008 [
+        (section).type = SECTION_DUMPSYS,
+        (section).args = "package --proto"
+    ];
 
-    android.service.procstats.ProcessStatsServiceDumpProto procstats = 3011 [
+    optional android.service.power.PowerServiceDumpProto power = 3009;
+    optional android.service.print.PrintServiceDumpProto print = 3010;
+
+    optional android.service.procstats.ProcessStatsServiceDumpProto procstats = 3011 [
         (section).type = SECTION_DUMPSYS,
         (section).args = "procstats --proto"
     ];
+
+    optional com.android.server.am.proto.ActivityStackSupervisorProto activities = 3012 [
+        (section).type = SECTION_DUMPSYS,
+        (section).args = "activity --proto activities"
+    ];
+
+    optional com.android.server.am.proto.BroadcastProto broadcasts = 3013 [
+        (section).type = SECTION_DUMPSYS,
+        (section).args = "activity --proto broadcasts"
+    ];
+
+    optional com.android.server.am.proto.ServiceProto amservices = 3014;
+    optional com.android.server.am.proto.ProcessProto amprocesses = 3015;
 }
diff --git a/core/proto/android/os/incidentheader.proto b/core/proto/android/os/incidentheader.proto
index 55a0616..ce924da 100644
--- a/core/proto/android/os/incidentheader.proto
+++ b/core/proto/android/os/incidentheader.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 option java_multiple_files = true;
 option java_outer_classname = "IncidentHeaderProtoMetadata";
 
@@ -29,6 +28,6 @@
         CAUSE_CRASH = 3;
     }
 
-    Cause cause = 1;
+    optional Cause cause = 1;
 }
 
diff --git a/core/proto/android/os/kernelwake.proto b/core/proto/android/os/kernelwake.proto
index e0b62aa..12649e1 100644
--- a/core/proto/android/os/kernelwake.proto
+++ b/core/proto/android/os/kernelwake.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 option java_multiple_files = true;
 option java_outer_classname = "WakeupSourcesProto";
 
@@ -29,23 +28,23 @@
 // Next Tag: 11
 message WakeupSourceProto {
     // Name of the event which triggers application processor
-    string name = 1;
+    optional string name = 1;
 
-    int32 active_count = 2;
+    optional int32 active_count = 2;
 
-    int32 event_count = 3;
+    optional int32 event_count = 3;
 
-    int32 wakeup_count = 4;
+    optional int32 wakeup_count = 4;
 
-    int32 expire_count = 5;
+    optional int32 expire_count = 5;
 
-    int64 active_since = 6;
+    optional int64 active_since = 6;
 
-    int64 total_time = 7;
+    optional int64 total_time = 7;
 
-    int64 max_time = 8;
+    optional int64 max_time = 8;
 
-    int64 last_change = 9;
+    optional int64 last_change = 9;
 
-    int64 prevent_suspend_time = 10;
+    optional int64 prevent_suspend_time = 10;
 }
diff --git a/core/proto/android/os/looper.proto b/core/proto/android/os/looper.proto
index 9fcc781..ef84bb1 100644
--- a/core/proto/android/os/looper.proto
+++ b/core/proto/android/os/looper.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 package android.os;
 
 option java_multiple_files = true;
@@ -23,8 +22,8 @@
 import "frameworks/base/core/proto/android/os/messagequeue.proto";
 
 message LooperProto {
-    string thread_name = 1;
-    int64 thread_id = 2;
-    int32 identity_hash_code = 3;
-    android.os.MessageQueueProto queue = 4;
+    optional string thread_name = 1;
+    optional int64 thread_id = 2;
+    optional int32 identity_hash_code = 3;
+    optional android.os.MessageQueueProto queue = 4;
 }
diff --git a/core/proto/android/os/message.proto b/core/proto/android/os/message.proto
index 604935d..38e27a1 100644
--- a/core/proto/android/os/message.proto
+++ b/core/proto/android/os/message.proto
@@ -14,24 +14,23 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 package android.os;
 
 option java_multiple_files = true;
 
 message MessageProto {
-    int64 when = 1;
+    optional int64 when = 1;
     // Name of callback class.
-    string callback = 2;
+    optional string callback = 2;
     // User-defined message code so that the recipient can identify what this
     // message is about.
-    int32 what = 3;
-    int32 arg1 = 4;
-    int32 arg2 = 5;
+    optional int32 what = 3;
+    optional int32 arg1 = 4;
+    optional int32 arg2 = 5;
     // String representation of an arbitrary object to send to the recipient.
-    string obj = 6;
+    optional string obj = 6;
     // Name of target class.
-    string target = 7;
-    int32 barrier = 8;
+    optional string target = 7;
+    optional int32 barrier = 8;
 }
diff --git a/core/proto/android/os/messagequeue.proto b/core/proto/android/os/messagequeue.proto
index 9bff13e..5d4bff0 100644
--- a/core/proto/android/os/messagequeue.proto
+++ b/core/proto/android/os/messagequeue.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 package android.os;
 
 option java_multiple_files = true;
@@ -24,6 +23,6 @@
 
 message MessageQueueProto {
     repeated android.os.MessageProto messages = 1;
-    bool is_polling_locked = 2;
-    bool is_quitting = 3;
+    optional bool is_polling_locked = 2;
+    optional bool is_quitting = 3;
 }
diff --git a/core/proto/android/os/pagetypeinfo.proto b/core/proto/android/os/pagetypeinfo.proto
index fbb4ee5..f82ea76 100644
--- a/core/proto/android/os/pagetypeinfo.proto
+++ b/core/proto/android/os/pagetypeinfo.proto
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-syntax = "proto3";
+syntax = "proto2";
 
 option java_multiple_files = true;
 option java_outer_classname = "PageTypeInfoProto";
@@ -38,9 +37,9 @@
  */
 message PageTypeInfo {
 
-    int32 page_block_order = 1;
+    optional int32 page_block_order = 1;
 
-    int32 pages_per_block = 2;
+    optional int32 pages_per_block = 2;
 
     repeated MigrateTypeProto migrate_types = 3;
 
@@ -50,11 +49,11 @@
 // Next tag: 5
 message MigrateTypeProto {
 
-    int32 node = 1;
+    optional int32 node = 1;
 
-    string zone = 2;
+    optional string zone = 2;
 
-    string type = 3;
+    optional string type = 3;
 
     // order level starts from 0 for 4KB to page_block_order defined above, e.g. 10 for 4096KB
     repeated int32 free_pages_count = 4;
@@ -63,19 +62,19 @@
 // Next tag: 9
 message BlockProto {
 
-    int32 node = 1;
+    optional int32 node = 1;
 
-    string zone = 2;
+    optional string zone = 2;
 
-    int32 unmovable = 3;
+    optional int32 unmovable = 3;
 
-    int32 reclaimable = 4;
+    optional int32 reclaimable = 4;
 
-    int32 movable = 5;
+    optional int32 movable = 5;
 
-    int32 cma = 6;
+    optional int32 cma = 6;
 
-    int32 reserve = 7;
+    optional int32 reserve = 7;
 
-    int32 isolate = 8;
+    optional int32 isolate = 8;
 }
diff --git a/core/proto/android/os/patternmatcher.proto b/core/proto/android/os/patternmatcher.proto
new file mode 100644
index 0000000..d30315b
--- /dev/null
+++ b/core/proto/android/os/patternmatcher.proto
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+option java_multiple_files = true;
+
+package android.os;
+
+message PatternMatcherProto {
+    optional string pattern = 1;
+
+    enum Type {
+        TYPE_LITERAL = 0;
+        TYPE_PREFIX = 1;
+        TYPE_SIMPLE_GLOB = 2;
+        TYPE_ADVANCED_GLOB = 3;
+    }
+    optional Type type = 2;
+
+    // This data is too much for dump
+    // repeated int32 parsed_pattern = 3;
+}
diff --git a/core/proto/android/os/procrank.proto b/core/proto/android/os/procrank.proto
index c7dbf4d..ab6a6a3 100644
--- a/core/proto/android/os/procrank.proto
+++ b/core/proto/android/os/procrank.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 option java_multiple_files = true;
 option java_outer_classname = "ProcrankProto";
 
@@ -27,56 +26,56 @@
     repeated ProcessProto processes = 1;
 
     // Summary
-    SummaryProto summary = 2;
+    optional SummaryProto summary = 2;
 }
 
 // Next Tag: 11
 message ProcessProto {
     // ID of the process
-    int32 pid = 1;
+    optional int32 pid = 1;
 
     // virtual set size, unit KB
-    int64 vss = 2;
+    optional int64 vss = 2;
 
     // resident set size, unit KB
-    int64 rss = 3;
+    optional int64 rss = 3;
 
     // proportional set size, unit KB
-    int64 pss = 4;
+    optional int64 pss = 4;
 
     // unique set size, unit KB
-    int64 uss = 5;
+    optional int64 uss = 5;
 
     // swap size, unit KB
-    int64 swap = 6;
+    optional int64 swap = 6;
 
     // proportional swap size, unit KB
-    int64 pswap = 7;
+    optional int64 pswap = 7;
 
     // unique swap size, unit KB
-    int64 uswap = 8;
+    optional int64 uswap = 8;
 
     // zswap size, unit KB
-    int64 zswap = 9;
+    optional int64 zswap = 9;
 
     // process command
-    string cmdline = 10;
+    optional string cmdline = 10;
 }
 
 // Next Tag: 3
 message SummaryProto {
-    ProcessProto total = 1;
+    optional ProcessProto total = 1;
 
-    ZramProto zram = 2;
+    optional ZramProto zram = 2;
 
-    RamProto ram = 3;
+    optional RamProto ram = 3;
 }
 
 // TODO: sync on how to use these values
 message ZramProto {
-    string raw_text = 1;
+    optional string raw_text = 1;
 }
 
 message RamProto {
-    string raw_text = 1;
+    optional string raw_text = 1;
 }
diff --git a/core/proto/android/os/worksource.proto b/core/proto/android/os/worksource.proto
index c2aa5cb..c60edfc 100644
--- a/core/proto/android/os/worksource.proto
+++ b/core/proto/android/os/worksource.proto
@@ -14,16 +14,15 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 package android.os;
 
 option java_multiple_files = true;
 
 message WorkSourceProto {
     message WorkSourceContentProto {
-        int32 uid = 1;
-        string name = 2;
+        optional int32 uid = 1;
+        optional string name = 2;
     }
 
     repeated WorkSourceContentProto work_source_contents = 1;
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index 3db4df0..f092713 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 package android.providers.settings;
 
 option java_multiple_files = true;
@@ -26,587 +25,587 @@
     repeated UserSettingsProto user_settings = 1;
 
     // Global settings
-    GlobalSettingsProto global_settings = 2;
+    optional GlobalSettingsProto global_settings = 2;
 }
 
 message UserSettingsProto {
     // Should be 0, 10, 11, 12, etc. where 0 is the owner.
-    int32 user_id = 1;
+    optional int32 user_id = 1;
 
     // The secure settings for this user
-    SecureSettingsProto secure_settings = 2;
+    optional SecureSettingsProto secure_settings = 2;
 
     // The system settings for this user
-    SystemSettingsProto system_settings = 3;
+    optional SystemSettingsProto system_settings = 3;
 }
 
 message GlobalSettingsProto {
     // Historical operations
     repeated SettingsOperationProto historical_op = 1;
 
-    SettingProto add_users_when_locked = 2;
-    SettingProto enable_accessibility_global_gesture_enabled = 3;
-    SettingProto airplane_mode_on = 4;
-    SettingProto theater_mode_on = 5;
-    SettingProto radio_bluetooth = 6;
-    SettingProto radio_wifi = 7;
-    SettingProto radio_wimax = 8;
-    SettingProto radio_cell = 9;
-    SettingProto radio_nfc = 10;
-    SettingProto airplane_mode_radios = 11;
-    SettingProto airplane_mode_toggleable_radios = 12;
-    SettingProto bluetooth_disabled_profiles = 13;
-    SettingProto bluetooth_interoperability_list = 14;
-    SettingProto wifi_sleep_policy = 15;
-    SettingProto auto_time = 16;
-    SettingProto auto_time_zone = 17;
-    SettingProto car_dock_sound = 18;
-    SettingProto car_undock_sound = 19;
-    SettingProto desk_dock_sound = 20;
-    SettingProto desk_undock_sound = 21;
-    SettingProto dock_sounds_enabled = 22;
-    SettingProto dock_sounds_enabled_when_accessibility = 23;
-    SettingProto lock_sound = 24;
-    SettingProto unlock_sound = 25;
-    SettingProto trusted_sound = 26;
-    SettingProto low_battery_sound = 27;
-    SettingProto power_sounds_enabled = 28;
-    SettingProto wireless_charging_started_sound = 29;
-    SettingProto charging_sounds_enabled = 30;
-    SettingProto stay_on_while_plugged_in = 31;
-    SettingProto bugreport_in_power_menu = 32;
-    SettingProto adb_enabled = 33;
-    SettingProto debug_view_attributes = 34;
-    SettingProto assisted_gps_enabled = 35;
-    SettingProto bluetooth_on = 36;
-    SettingProto cdma_cell_broadcast_sms = 37;
-    SettingProto cdma_roaming_mode = 38;
-    SettingProto cdma_subscription_mode = 39;
-    SettingProto data_activity_timeout_mobile = 40;
-    SettingProto data_activity_timeout_wifi = 41;
-    SettingProto data_roaming = 42;
-    SettingProto mdc_initial_max_retry = 43;
-    SettingProto force_allow_on_external = 44;
-    SettingProto development_force_resizable_activities = 45;
-    SettingProto development_enable_freeform_windows_support = 46;
-    SettingProto development_settings_enabled = 47;
-    SettingProto device_provisioned = 48;
-    SettingProto device_provisioning_mobile_data_enabled = 49;
-    SettingProto display_size_forced = 50;
-    SettingProto display_scaling_force = 51;
-    SettingProto download_max_bytes_over_mobile = 52;
-    SettingProto download_recommended_max_bytes_over_mobile = 53;
-    SettingProto hdmi_control_enabled = 54;
-    SettingProto hdmi_system_audio_control_enabled = 55;
-    SettingProto hdmi_control_auto_wakeup_enabled = 56;
-    SettingProto hdmi_control_auto_device_off_enabled = 57;
-    SettingProto mhl_input_switching_enabled = 58;
-    SettingProto mhl_power_charge_enabled = 59;
-    SettingProto mobile_data = 60;
-    SettingProto mobile_data_always_on = 61;
-    SettingProto connectivity_metrics_buffer_size = 62;
-    SettingProto netstats_enabled = 63;
-    SettingProto netstats_poll_interval = 64;
-    SettingProto netstats_time_cache_max_age = 65;
-    SettingProto netstats_global_alert_bytes = 66;
-    SettingProto netstats_sample_enabled = 67;
-    SettingProto netstats_dev_bucket_duration = 68;
-    SettingProto netstats_dev_persist_bytes = 69;
-    SettingProto netstats_dev_rotate_age = 70;
-    SettingProto netstats_dev_delete_age = 71;
-    SettingProto netstats_uid_bucket_duration = 72;
-    SettingProto netstats_uid_persist_bytes = 73;
-    SettingProto netstats_uid_rotate_age = 74;
-    SettingProto netstats_uid_delete_age = 75;
-    SettingProto netstats_uid_tag_bucket_duration = 76;
-    SettingProto netstats_uid_tag_persist_bytes = 77;
-    SettingProto netstats_uid_tag_rotate_age = 78;
-    SettingProto netstats_uid_tag_delete_age = 79;
-    SettingProto network_preference = 80;
-    SettingProto network_scorer_app = 81;
-    SettingProto nitz_update_diff = 82;
-    SettingProto nitz_update_spacing = 83;
-    SettingProto ntp_server = 84;
-    SettingProto ntp_timeout = 85;
-    SettingProto storage_benchmark_interval = 86;
-    SettingProto dns_resolver_sample_validity_seconds = 87;
-    SettingProto dns_resolver_success_threshold_percent = 88;
-    SettingProto dns_resolver_min_samples = 89;
-    SettingProto dns_resolver_max_samples = 90;
-    SettingProto ota_disable_automatic_update = 91;
-    SettingProto package_verifier_enable = 92;
-    SettingProto package_verifier_timeout = 93;
-    SettingProto package_verifier_default_response = 94;
-    SettingProto package_verifier_setting_visible = 95;
-    SettingProto package_verifier_include_adb = 96;
-    SettingProto fstrim_mandatory_interval = 97;
-    SettingProto pdp_watchdog_poll_interval_ms = 98;
-    SettingProto pdp_watchdog_long_poll_interval_ms = 99;
-    SettingProto pdp_watchdog_error_poll_interval_ms = 100;
-    SettingProto pdp_watchdog_trigger_packet_count = 101;
-    SettingProto pdp_watchdog_error_poll_count = 102;
-    SettingProto pdp_watchdog_max_pdp_reset_fail_count = 103;
-    SettingProto setup_prepaid_data_service_url = 105;
-    SettingProto setup_prepaid_detection_target_url = 106;
-    SettingProto setup_prepaid_detection_redir_host = 107;
-    SettingProto sms_outgoing_check_interval_ms = 108;
-    SettingProto sms_outgoing_check_max_count = 109;
-    SettingProto sms_short_code_confirmation = 110;
-    SettingProto sms_short_code_rule = 111;
-    SettingProto tcp_default_init_rwnd = 112;
-    SettingProto tether_supported = 113;
-    SettingProto tether_dun_required = 114;
-    SettingProto tether_dun_apn = 115;
-    SettingProto carrier_app_whitelist = 116;
-    SettingProto usb_mass_storage_enabled = 117;
-    SettingProto use_google_mail = 118;
-    SettingProto webview_data_reduction_proxy_key = 119;
-    SettingProto webview_fallback_logic_enabled = 120;
-    SettingProto webview_provider = 121;
-    SettingProto webview_multiprocess = 122;
-    SettingProto network_switch_notification_daily_limit = 123;
-    SettingProto network_switch_notification_rate_limit_millis = 124;
-    SettingProto network_avoid_bad_wifi = 125;
-    SettingProto wifi_display_on = 126;
-    SettingProto wifi_display_certification_on = 127;
-    SettingProto wifi_display_wps_config = 128;
-    SettingProto wifi_networks_available_notification_on = 129;
-    SettingProto wimax_networks_available_notification_on = 130;
-    SettingProto wifi_networks_available_repeat_delay = 131;
-    SettingProto wifi_country_code = 132;
-    SettingProto wifi_framework_scan_interval_ms = 133;
-    SettingProto wifi_idle_ms = 134;
-    SettingProto wifi_num_open_networks_kept = 135;
-    SettingProto wifi_on = 136;
-    SettingProto wifi_scan_always_available = 137;
-    SettingProto wifi_wakeup_enabled = 138;
-    SettingProto network_recommendations_enabled = 139;
-    SettingProto ble_scan_always_available = 140;
-    SettingProto wifi_saved_state = 141;
-    SettingProto wifi_supplicant_scan_interval_ms = 142;
-    SettingProto wifi_enhanced_auto_join = 143;
-    SettingProto wifi_network_show_rssi = 144;
-    SettingProto wifi_scan_interval_when_p2p_connected_ms = 145;
-    SettingProto wifi_watchdog_on = 146;
-    SettingProto wifi_watchdog_poor_network_test_enabled = 147;
-    SettingProto wifi_suspend_optimizations_enabled = 148;
-    SettingProto wifi_verbose_logging_enabled = 149;
-    SettingProto wifi_max_dhcp_retry_count = 150;
-    SettingProto wifi_mobile_data_transition_wakelock_timeout_ms = 151;
-    SettingProto wifi_device_owner_configs_lockdown = 152;
-    SettingProto wifi_frequency_band = 153;
-    SettingProto wifi_p2p_device_name = 154;
-    SettingProto wifi_reenable_delay_ms = 155;
-    SettingProto wifi_ephemeral_out_of_range_timeout_ms = 156;
-    SettingProto data_stall_alarm_non_aggressive_delay_in_ms = 157;
-    SettingProto data_stall_alarm_aggressive_delay_in_ms = 158;
-    SettingProto provisioning_apn_alarm_delay_in_ms = 159;
-    SettingProto gprs_register_check_period_ms = 160;
-    SettingProto wtf_is_fatal = 161;
-    SettingProto mode_ringer = 162;
-    SettingProto overlay_display_devices = 163;
-    SettingProto battery_discharge_duration_threshold = 164;
-    SettingProto battery_discharge_threshold = 165;
-    SettingProto send_action_app_error = 166;
-    SettingProto dropbox_age_seconds = 167;
-    SettingProto dropbox_max_files = 168;
-    SettingProto dropbox_quota_kb = 169;
-    SettingProto dropbox_quota_percent = 170;
-    SettingProto dropbox_reserve_percent = 171;
-    SettingProto dropbox_tag_prefix = 172;
-    SettingProto error_logcat_prefix = 173;
-    SettingProto sys_free_storage_log_interval = 174;
-    SettingProto disk_free_change_reporting_threshold = 175;
-    SettingProto sys_storage_threshold_percentage = 176;
-    SettingProto sys_storage_threshold_max_bytes = 177;
-    SettingProto sys_storage_full_threshold_bytes = 178;
-    SettingProto sync_max_retry_delay_in_seconds = 179;
-    SettingProto connectivity_change_delay = 180;
-    SettingProto connectivity_sampling_interval_in_seconds = 181;
-    SettingProto pac_change_delay = 182;
-    SettingProto captive_portal_mode = 183;
-    SettingProto captive_portal_server = 184;
-    SettingProto captive_portal_https_url = 185;
-    SettingProto captive_portal_http_url = 186;
-    SettingProto captive_portal_fallback_url = 187;
-    SettingProto captive_portal_use_https = 188;
-    SettingProto captive_portal_user_agent = 189;
-    SettingProto nsd_on = 190;
-    SettingProto set_install_location = 191;
-    SettingProto default_install_location = 192;
-    SettingProto inet_condition_debounce_up_delay = 193;
-    SettingProto inet_condition_debounce_down_delay = 194;
-    SettingProto read_external_storage_enforced_default = 195;
-    SettingProto http_proxy = 196;
-    SettingProto global_http_proxy_host = 197;
-    SettingProto global_http_proxy_port = 198;
-    SettingProto global_http_proxy_exclusion_list = 199;
-    SettingProto global_http_proxy_pac = 200;
-    SettingProto set_global_http_proxy = 201;
-    SettingProto default_dns_server = 202;
-    SettingProto bluetooth_headset_priority_prefix = 203;
-    SettingProto bluetooth_a2dp_sink_priority_prefix = 204;
-    SettingProto bluetooth_a2dp_src_priority_prefix = 205;
-    SettingProto bluetooth_input_device_priority_prefix = 206;
-    SettingProto bluetooth_map_priority_prefix = 207;
-    SettingProto bluetooth_map_client_priority_prefix = 208;
-    SettingProto bluetooth_pbap_client_priority_prefix = 209;
-    SettingProto bluetooth_sap_priority_prefix = 210;
-    SettingProto bluetooth_pan_priority_prefix = 211;
-    SettingProto device_idle_constants = 212;
-    SettingProto device_idle_constants_watch = 213;
-    SettingProto app_idle_constants = 214;
-    SettingProto alarm_manager_constants = 215;
-    SettingProto job_scheduler_constants = 216;
-    SettingProto shortcut_manager_constants = 217;
-    SettingProto window_animation_scale = 218;
-    SettingProto transition_animation_scale = 219;
-    SettingProto animator_duration_scale = 220;
-    SettingProto fancy_ime_animations = 221;
-    SettingProto compatibility_mode = 222;
-    SettingProto emergency_tone = 223;
-    SettingProto call_auto_retry = 224;
-    SettingProto emergency_affordance_needed = 225;
-    SettingProto preferred_network_mode = 226;
-    SettingProto debug_app = 227;
-    SettingProto wait_for_debugger = 228;
-    SettingProto low_power_mode = 229;
-    SettingProto low_power_mode_trigger_level = 230;
-    SettingProto always_finish_activities = 231;
-    SettingProto dock_audio_media_enabled = 232;
-    SettingProto encoded_surround_output = 233;
-    SettingProto audio_safe_volume_state = 234;
-    SettingProto tzinfo_update_content_url = 235;
-    SettingProto tzinfo_update_metadata_url = 236;
-    SettingProto selinux_update_content_url = 237;
-    SettingProto selinux_update_metadata_url = 238;
-    SettingProto sms_short_codes_update_content_url = 239;
-    SettingProto sms_short_codes_update_metadata_url = 240;
-    SettingProto apn_db_update_content_url = 241;
-    SettingProto apn_db_update_metadata_url = 242;
-    SettingProto cert_pin_update_content_url = 243;
-    SettingProto cert_pin_update_metadata_url = 244;
-    SettingProto intent_firewall_update_content_url = 245;
-    SettingProto intent_firewall_update_metadata_url = 246;
-    SettingProto selinux_status = 247;
-    SettingProto development_force_rtl = 248;
-    SettingProto low_battery_sound_timeout = 249;
-    SettingProto wifi_bounce_delay_override_ms = 250;
-    SettingProto policy_control = 251;
-    SettingProto zen_mode = 252;
-    SettingProto zen_mode_ringer_level = 253;
-    SettingProto zen_mode_config_etag = 254;
-    SettingProto heads_up_notifications_enabled = 255;
-    SettingProto device_name = 256;
-    SettingProto network_scoring_provisioned = 257;
-    SettingProto require_password_to_decrypt = 258;
-    SettingProto enhanced_4g_mode_enabled = 259;
-    SettingProto vt_ims_enabled = 260;
-    SettingProto wfc_ims_enabled = 261;
-    SettingProto wfc_ims_mode = 262;
-    SettingProto wfc_ims_roaming_mode = 263;
-    SettingProto wfc_ims_roaming_enabled = 264;
-    SettingProto lte_service_forced = 265;
-    SettingProto ephemeral_cookie_max_size_bytes = 266;
-    SettingProto enable_ephemeral_feature = 267;
-    SettingProto installed_instant_app_min_cache_period = 268;
-    SettingProto allow_user_switching_when_system_user_locked = 269;
-    SettingProto boot_count = 270;
-    SettingProto safe_boot_disallowed = 271;
-    SettingProto device_demo_mode = 272;
-    SettingProto database_downgrade_reason = 274;
-    SettingProto contacts_database_wal_enabled = 275;
-    SettingProto multi_sim_voice_call_subscription = 276;
-    SettingProto multi_sim_voice_prompt = 277;
-    SettingProto multi_sim_data_call_subscription = 278;
-    SettingProto multi_sim_sms_subscription = 279;
-    SettingProto multi_sim_sms_prompt = 280;
-    SettingProto new_contact_aggregator = 281;
-    SettingProto contact_metadata_sync_enabled = 282;
-    SettingProto enable_cellular_on_boot = 283;
-    SettingProto max_notification_enqueue_rate = 284;
-    SettingProto cell_on = 285;
-    SettingProto network_recommendations_package = 286;
-    SettingProto bluetooth_a2dp_supports_optional_codecs_prefix = 287;
-    SettingProto bluetooth_a2dp_optional_codecs_enabled_prefix = 288;
-    SettingProto installed_instant_app_max_cache_period = 289;
-    SettingProto uninstalled_instant_app_min_cache_period = 290;
-    SettingProto uninstalled_instant_app_max_cache_period = 291;
-    SettingProto unused_static_shared_lib_min_cache_period = 292;
+    optional SettingProto add_users_when_locked = 2;
+    optional SettingProto enable_accessibility_global_gesture_enabled = 3;
+    optional SettingProto airplane_mode_on = 4;
+    optional SettingProto theater_mode_on = 5;
+    optional SettingProto radio_bluetooth = 6;
+    optional SettingProto radio_wifi = 7;
+    optional SettingProto radio_wimax = 8;
+    optional SettingProto radio_cell = 9;
+    optional SettingProto radio_nfc = 10;
+    optional SettingProto airplane_mode_radios = 11;
+    optional SettingProto airplane_mode_toggleable_radios = 12;
+    optional SettingProto bluetooth_disabled_profiles = 13;
+    optional SettingProto bluetooth_interoperability_list = 14;
+    optional SettingProto wifi_sleep_policy = 15;
+    optional SettingProto auto_time = 16;
+    optional SettingProto auto_time_zone = 17;
+    optional SettingProto car_dock_sound = 18;
+    optional SettingProto car_undock_sound = 19;
+    optional SettingProto desk_dock_sound = 20;
+    optional SettingProto desk_undock_sound = 21;
+    optional SettingProto dock_sounds_enabled = 22;
+    optional SettingProto dock_sounds_enabled_when_accessibility = 23;
+    optional SettingProto lock_sound = 24;
+    optional SettingProto unlock_sound = 25;
+    optional SettingProto trusted_sound = 26;
+    optional SettingProto low_battery_sound = 27;
+    optional SettingProto power_sounds_enabled = 28;
+    optional SettingProto wireless_charging_started_sound = 29;
+    optional SettingProto charging_sounds_enabled = 30;
+    optional SettingProto stay_on_while_plugged_in = 31;
+    optional SettingProto bugreport_in_power_menu = 32;
+    optional SettingProto adb_enabled = 33;
+    optional SettingProto debug_view_attributes = 34;
+    optional SettingProto assisted_gps_enabled = 35;
+    optional SettingProto bluetooth_on = 36;
+    optional SettingProto cdma_cell_broadcast_sms = 37;
+    optional SettingProto cdma_roaming_mode = 38;
+    optional SettingProto cdma_subscription_mode = 39;
+    optional SettingProto data_activity_timeout_mobile = 40;
+    optional SettingProto data_activity_timeout_wifi = 41;
+    optional SettingProto data_roaming = 42;
+    optional SettingProto mdc_initial_max_retry = 43;
+    optional SettingProto force_allow_on_external = 44;
+    optional SettingProto development_force_resizable_activities = 45;
+    optional SettingProto development_enable_freeform_windows_support = 46;
+    optional SettingProto development_settings_enabled = 47;
+    optional SettingProto device_provisioned = 48;
+    optional SettingProto device_provisioning_mobile_data_enabled = 49;
+    optional SettingProto display_size_forced = 50;
+    optional SettingProto display_scaling_force = 51;
+    optional SettingProto download_max_bytes_over_mobile = 52;
+    optional SettingProto download_recommended_max_bytes_over_mobile = 53;
+    optional SettingProto hdmi_control_enabled = 54;
+    optional SettingProto hdmi_system_audio_control_enabled = 55;
+    optional SettingProto hdmi_control_auto_wakeup_enabled = 56;
+    optional SettingProto hdmi_control_auto_device_off_enabled = 57;
+    optional SettingProto mhl_input_switching_enabled = 58;
+    optional SettingProto mhl_power_charge_enabled = 59;
+    optional SettingProto mobile_data = 60;
+    optional SettingProto mobile_data_always_on = 61;
+    optional SettingProto connectivity_metrics_buffer_size = 62;
+    optional SettingProto netstats_enabled = 63;
+    optional SettingProto netstats_poll_interval = 64;
+    optional SettingProto netstats_time_cache_max_age = 65;
+    optional SettingProto netstats_global_alert_bytes = 66;
+    optional SettingProto netstats_sample_enabled = 67;
+    optional SettingProto netstats_dev_bucket_duration = 68;
+    optional SettingProto netstats_dev_persist_bytes = 69;
+    optional SettingProto netstats_dev_rotate_age = 70;
+    optional SettingProto netstats_dev_delete_age = 71;
+    optional SettingProto netstats_uid_bucket_duration = 72;
+    optional SettingProto netstats_uid_persist_bytes = 73;
+    optional SettingProto netstats_uid_rotate_age = 74;
+    optional SettingProto netstats_uid_delete_age = 75;
+    optional SettingProto netstats_uid_tag_bucket_duration = 76;
+    optional SettingProto netstats_uid_tag_persist_bytes = 77;
+    optional SettingProto netstats_uid_tag_rotate_age = 78;
+    optional SettingProto netstats_uid_tag_delete_age = 79;
+    optional SettingProto network_preference = 80;
+    optional SettingProto network_scorer_app = 81;
+    optional SettingProto nitz_update_diff = 82;
+    optional SettingProto nitz_update_spacing = 83;
+    optional SettingProto ntp_server = 84;
+    optional SettingProto ntp_timeout = 85;
+    optional SettingProto storage_benchmark_interval = 86;
+    optional SettingProto dns_resolver_sample_validity_seconds = 87;
+    optional SettingProto dns_resolver_success_threshold_percent = 88;
+    optional SettingProto dns_resolver_min_samples = 89;
+    optional SettingProto dns_resolver_max_samples = 90;
+    optional SettingProto ota_disable_automatic_update = 91;
+    optional SettingProto package_verifier_enable = 92;
+    optional SettingProto package_verifier_timeout = 93;
+    optional SettingProto package_verifier_default_response = 94;
+    optional SettingProto package_verifier_setting_visible = 95;
+    optional SettingProto package_verifier_include_adb = 96;
+    optional SettingProto fstrim_mandatory_interval = 97;
+    optional SettingProto pdp_watchdog_poll_interval_ms = 98;
+    optional SettingProto pdp_watchdog_long_poll_interval_ms = 99;
+    optional SettingProto pdp_watchdog_error_poll_interval_ms = 100;
+    optional SettingProto pdp_watchdog_trigger_packet_count = 101;
+    optional SettingProto pdp_watchdog_error_poll_count = 102;
+    optional SettingProto pdp_watchdog_max_pdp_reset_fail_count = 103;
+    optional SettingProto setup_prepaid_data_service_url = 105;
+    optional SettingProto setup_prepaid_detection_target_url = 106;
+    optional SettingProto setup_prepaid_detection_redir_host = 107;
+    optional SettingProto sms_outgoing_check_interval_ms = 108;
+    optional SettingProto sms_outgoing_check_max_count = 109;
+    optional SettingProto sms_short_code_confirmation = 110;
+    optional SettingProto sms_short_code_rule = 111;
+    optional SettingProto tcp_default_init_rwnd = 112;
+    optional SettingProto tether_supported = 113;
+    optional SettingProto tether_dun_required = 114;
+    optional SettingProto tether_dun_apn = 115;
+    optional SettingProto carrier_app_whitelist = 116;
+    optional SettingProto usb_mass_storage_enabled = 117;
+    optional SettingProto use_google_mail = 118;
+    optional SettingProto webview_data_reduction_proxy_key = 119;
+    optional SettingProto webview_fallback_logic_enabled = 120;
+    optional SettingProto webview_provider = 121;
+    optional SettingProto webview_multiprocess = 122;
+    optional SettingProto network_switch_notification_daily_limit = 123;
+    optional SettingProto network_switch_notification_rate_limit_millis = 124;
+    optional SettingProto network_avoid_bad_wifi = 125;
+    optional SettingProto wifi_display_on = 126;
+    optional SettingProto wifi_display_certification_on = 127;
+    optional SettingProto wifi_display_wps_config = 128;
+    optional SettingProto wifi_networks_available_notification_on = 129;
+    optional SettingProto wimax_networks_available_notification_on = 130;
+    optional SettingProto wifi_networks_available_repeat_delay = 131;
+    optional SettingProto wifi_country_code = 132;
+    optional SettingProto wifi_framework_scan_interval_ms = 133;
+    optional SettingProto wifi_idle_ms = 134;
+    optional SettingProto wifi_num_open_networks_kept = 135;
+    optional SettingProto wifi_on = 136;
+    optional SettingProto wifi_scan_always_available = 137;
+    optional SettingProto wifi_wakeup_enabled = 138;
+    optional SettingProto network_recommendations_enabled = 139;
+    optional SettingProto ble_scan_always_available = 140;
+    optional SettingProto wifi_saved_state = 141;
+    optional SettingProto wifi_supplicant_scan_interval_ms = 142;
+    optional SettingProto wifi_enhanced_auto_join = 143;
+    optional SettingProto wifi_network_show_rssi = 144;
+    optional SettingProto wifi_scan_interval_when_p2p_connected_ms = 145;
+    optional SettingProto wifi_watchdog_on = 146;
+    optional SettingProto wifi_watchdog_poor_network_test_enabled = 147;
+    optional SettingProto wifi_suspend_optimizations_enabled = 148;
+    optional SettingProto wifi_verbose_logging_enabled = 149;
+    optional SettingProto wifi_max_dhcp_retry_count = 150;
+    optional SettingProto wifi_mobile_data_transition_wakelock_timeout_ms = 151;
+    optional SettingProto wifi_device_owner_configs_lockdown = 152;
+    optional SettingProto wifi_frequency_band = 153;
+    optional SettingProto wifi_p2p_device_name = 154;
+    optional SettingProto wifi_reenable_delay_ms = 155;
+    optional SettingProto wifi_ephemeral_out_of_range_timeout_ms = 156;
+    optional SettingProto data_stall_alarm_non_aggressive_delay_in_ms = 157;
+    optional SettingProto data_stall_alarm_aggressive_delay_in_ms = 158;
+    optional SettingProto provisioning_apn_alarm_delay_in_ms = 159;
+    optional SettingProto gprs_register_check_period_ms = 160;
+    optional SettingProto wtf_is_fatal = 161;
+    optional SettingProto mode_ringer = 162;
+    optional SettingProto overlay_display_devices = 163;
+    optional SettingProto battery_discharge_duration_threshold = 164;
+    optional SettingProto battery_discharge_threshold = 165;
+    optional SettingProto send_action_app_error = 166;
+    optional SettingProto dropbox_age_seconds = 167;
+    optional SettingProto dropbox_max_files = 168;
+    optional SettingProto dropbox_quota_kb = 169;
+    optional SettingProto dropbox_quota_percent = 170;
+    optional SettingProto dropbox_reserve_percent = 171;
+    optional SettingProto dropbox_tag_prefix = 172;
+    optional SettingProto error_logcat_prefix = 173;
+    optional SettingProto sys_free_storage_log_interval = 174;
+    optional SettingProto disk_free_change_reporting_threshold = 175;
+    optional SettingProto sys_storage_threshold_percentage = 176;
+    optional SettingProto sys_storage_threshold_max_bytes = 177;
+    optional SettingProto sys_storage_full_threshold_bytes = 178;
+    optional SettingProto sync_max_retry_delay_in_seconds = 179;
+    optional SettingProto connectivity_change_delay = 180;
+    optional SettingProto connectivity_sampling_interval_in_seconds = 181;
+    optional SettingProto pac_change_delay = 182;
+    optional SettingProto captive_portal_mode = 183;
+    optional SettingProto captive_portal_server = 184;
+    optional SettingProto captive_portal_https_url = 185;
+    optional SettingProto captive_portal_http_url = 186;
+    optional SettingProto captive_portal_fallback_url = 187;
+    optional SettingProto captive_portal_use_https = 188;
+    optional SettingProto captive_portal_user_agent = 189;
+    optional SettingProto nsd_on = 190;
+    optional SettingProto set_install_location = 191;
+    optional SettingProto default_install_location = 192;
+    optional SettingProto inet_condition_debounce_up_delay = 193;
+    optional SettingProto inet_condition_debounce_down_delay = 194;
+    optional SettingProto read_external_storage_enforced_default = 195;
+    optional SettingProto http_proxy = 196;
+    optional SettingProto global_http_proxy_host = 197;
+    optional SettingProto global_http_proxy_port = 198;
+    optional SettingProto global_http_proxy_exclusion_list = 199;
+    optional SettingProto global_http_proxy_pac = 200;
+    optional SettingProto set_global_http_proxy = 201;
+    optional SettingProto default_dns_server = 202;
+    optional SettingProto bluetooth_headset_priority_prefix = 203;
+    optional SettingProto bluetooth_a2dp_sink_priority_prefix = 204;
+    optional SettingProto bluetooth_a2dp_src_priority_prefix = 205;
+    optional SettingProto bluetooth_input_device_priority_prefix = 206;
+    optional SettingProto bluetooth_map_priority_prefix = 207;
+    optional SettingProto bluetooth_map_client_priority_prefix = 208;
+    optional SettingProto bluetooth_pbap_client_priority_prefix = 209;
+    optional SettingProto bluetooth_sap_priority_prefix = 210;
+    optional SettingProto bluetooth_pan_priority_prefix = 211;
+    optional SettingProto device_idle_constants = 212;
+    optional SettingProto device_idle_constants_watch = 213;
+    optional SettingProto app_idle_constants = 214;
+    optional SettingProto alarm_manager_constants = 215;
+    optional SettingProto job_scheduler_constants = 216;
+    optional SettingProto shortcut_manager_constants = 217;
+    optional SettingProto window_animation_scale = 218;
+    optional SettingProto transition_animation_scale = 219;
+    optional SettingProto animator_duration_scale = 220;
+    optional SettingProto fancy_ime_animations = 221;
+    optional SettingProto compatibility_mode = 222;
+    optional SettingProto emergency_tone = 223;
+    optional SettingProto call_auto_retry = 224;
+    optional SettingProto emergency_affordance_needed = 225;
+    optional SettingProto preferred_network_mode = 226;
+    optional SettingProto debug_app = 227;
+    optional SettingProto wait_for_debugger = 228;
+    optional SettingProto low_power_mode = 229;
+    optional SettingProto low_power_mode_trigger_level = 230;
+    optional SettingProto always_finish_activities = 231;
+    optional SettingProto dock_audio_media_enabled = 232;
+    optional SettingProto encoded_surround_output = 233;
+    optional SettingProto audio_safe_volume_state = 234;
+    optional SettingProto tzinfo_update_content_url = 235;
+    optional SettingProto tzinfo_update_metadata_url = 236;
+    optional SettingProto selinux_update_content_url = 237;
+    optional SettingProto selinux_update_metadata_url = 238;
+    optional SettingProto sms_short_codes_update_content_url = 239;
+    optional SettingProto sms_short_codes_update_metadata_url = 240;
+    optional SettingProto apn_db_update_content_url = 241;
+    optional SettingProto apn_db_update_metadata_url = 242;
+    optional SettingProto cert_pin_update_content_url = 243;
+    optional SettingProto cert_pin_update_metadata_url = 244;
+    optional SettingProto intent_firewall_update_content_url = 245;
+    optional SettingProto intent_firewall_update_metadata_url = 246;
+    optional SettingProto selinux_status = 247;
+    optional SettingProto development_force_rtl = 248;
+    optional SettingProto low_battery_sound_timeout = 249;
+    optional SettingProto wifi_bounce_delay_override_ms = 250;
+    optional SettingProto policy_control = 251;
+    optional SettingProto zen_mode = 252;
+    optional SettingProto zen_mode_ringer_level = 253;
+    optional SettingProto zen_mode_config_etag = 254;
+    optional SettingProto heads_up_notifications_enabled = 255;
+    optional SettingProto device_name = 256;
+    optional SettingProto network_scoring_provisioned = 257;
+    optional SettingProto require_password_to_decrypt = 258;
+    optional SettingProto enhanced_4g_mode_enabled = 259;
+    optional SettingProto vt_ims_enabled = 260;
+    optional SettingProto wfc_ims_enabled = 261;
+    optional SettingProto wfc_ims_mode = 262;
+    optional SettingProto wfc_ims_roaming_mode = 263;
+    optional SettingProto wfc_ims_roaming_enabled = 264;
+    optional SettingProto lte_service_forced = 265;
+    optional SettingProto ephemeral_cookie_max_size_bytes = 266;
+    optional SettingProto enable_ephemeral_feature = 267;
+    optional SettingProto installed_instant_app_min_cache_period = 268;
+    optional SettingProto allow_user_switching_when_system_user_locked = 269;
+    optional SettingProto boot_count = 270;
+    optional SettingProto safe_boot_disallowed = 271;
+    optional SettingProto device_demo_mode = 272;
+    optional SettingProto database_downgrade_reason = 274;
+    optional SettingProto contacts_database_wal_enabled = 275;
+    optional SettingProto multi_sim_voice_call_subscription = 276;
+    optional SettingProto multi_sim_voice_prompt = 277;
+    optional SettingProto multi_sim_data_call_subscription = 278;
+    optional SettingProto multi_sim_sms_subscription = 279;
+    optional SettingProto multi_sim_sms_prompt = 280;
+    optional SettingProto new_contact_aggregator = 281;
+    optional SettingProto contact_metadata_sync_enabled = 282;
+    optional SettingProto enable_cellular_on_boot = 283;
+    optional SettingProto max_notification_enqueue_rate = 284;
+    optional SettingProto cell_on = 285;
+    optional SettingProto network_recommendations_package = 286;
+    optional SettingProto bluetooth_a2dp_supports_optional_codecs_prefix = 287;
+    optional SettingProto bluetooth_a2dp_optional_codecs_enabled_prefix = 288;
+    optional SettingProto installed_instant_app_max_cache_period = 289;
+    optional SettingProto uninstalled_instant_app_min_cache_period = 290;
+    optional SettingProto uninstalled_instant_app_max_cache_period = 291;
+    optional SettingProto unused_static_shared_lib_min_cache_period = 292;
 }
 
 message SecureSettingsProto {
     // Historical operations
     repeated SettingsOperationProto historical_op = 1;
 
-    SettingProto android_id = 2;
-    SettingProto default_input_method = 3;
-    SettingProto selected_input_method_subtype = 4;
-    SettingProto input_methods_subtype_history = 5;
-    SettingProto input_method_selector_visibility = 6;
-    SettingProto voice_interaction_service = 7;
-    SettingProto autofill_service = 8;
-    SettingProto bluetooth_hci_log = 9;
-    SettingProto user_setup_complete = 10;
-    SettingProto completed_category_prefix = 11;
-    SettingProto enabled_input_methods = 12;
-    SettingProto disabled_system_input_methods = 13;
-    SettingProto show_ime_with_hard_keyboard = 14;
-    SettingProto always_on_vpn_app = 15;
-    SettingProto always_on_vpn_lockdown = 16;
-    SettingProto install_non_market_apps = 17;
-    SettingProto location_mode = 18;
-    SettingProto location_previous_mode = 19;
-    SettingProto lock_to_app_exit_locked = 20;
-    SettingProto lock_screen_lock_after_timeout = 21;
-    SettingProto lock_screen_allow_remote_input = 22;
-    SettingProto show_note_about_notification_hiding = 23;
-    SettingProto trust_agents_initialized = 24;
-    SettingProto parental_control_enabled = 25;
-    SettingProto parental_control_last_update = 26;
-    SettingProto parental_control_redirect_url = 27;
-    SettingProto settings_classname = 28;
-    SettingProto accessibility_enabled = 29;
-    SettingProto touch_exploration_enabled = 30;
-    SettingProto enabled_accessibility_services = 31;
-    SettingProto touch_exploration_granted_accessibility_services = 32;
-    SettingProto accessibility_speak_password = 33;
-    SettingProto accessibility_high_text_contrast_enabled = 34;
-    SettingProto accessibility_script_injection = 35;
-    SettingProto accessibility_screen_reader_url = 36;
-    SettingProto accessibility_web_content_key_bindings = 37;
-    SettingProto accessibility_display_magnification_enabled = 38;
-    SettingProto accessibility_display_magnification_scale = 39;
-    SettingProto accessibility_soft_keyboard_mode = 40;
-    SettingProto accessibility_captioning_enabled = 41;
-    SettingProto accessibility_captioning_locale = 42;
-    SettingProto accessibility_captioning_preset = 43;
-    SettingProto accessibility_captioning_background_color = 44;
-    SettingProto accessibility_captioning_foreground_color = 45;
-    SettingProto accessibility_captioning_edge_type = 46;
-    SettingProto accessibility_captioning_edge_color = 47;
-    SettingProto accessibility_captioning_window_color = 48;
-    SettingProto accessibility_captioning_typeface = 49;
-    SettingProto accessibility_captioning_font_scale = 50;
-    SettingProto accessibility_display_inversion_enabled = 51;
-    SettingProto accessibility_display_daltonizer_enabled = 52;
-    SettingProto accessibility_display_daltonizer = 53;
-    SettingProto accessibility_autoclick_enabled = 54;
-    SettingProto accessibility_autoclick_delay = 55;
-    SettingProto accessibility_large_pointer_icon = 56;
-    SettingProto long_press_timeout = 57;
-    SettingProto multi_press_timeout = 58;
-    SettingProto enabled_print_services = 59;
-    SettingProto disabled_print_services = 60;
-    SettingProto display_density_forced = 61;
-    SettingProto tts_default_rate = 62;
-    SettingProto tts_default_pitch = 63;
-    SettingProto tts_default_synth = 64;
-    SettingProto tts_default_locale = 65;
-    SettingProto tts_enabled_plugins = 66;
-    SettingProto connectivity_release_pending_intent_delay_ms = 67;
-    SettingProto allowed_geolocation_origins = 68;
-    SettingProto preferred_tty_mode = 69;
-    SettingProto enhanced_voice_privacy_enabled = 70;
-    SettingProto tty_mode_enabled = 71;
-    SettingProto backup_enabled = 72;
-    SettingProto backup_auto_restore = 73;
-    SettingProto backup_provisioned = 74;
-    SettingProto backup_transport = 75;
-    SettingProto last_setup_shown = 76;
-    SettingProto search_global_search_activity = 77;
-    SettingProto search_num_promoted_sources = 78;
-    SettingProto search_max_results_to_display = 79;
-    SettingProto search_max_results_per_source = 80;
-    SettingProto search_web_results_override_limit = 81;
-    SettingProto search_promoted_source_deadline_millis = 82;
-    SettingProto search_source_timeout_millis = 83;
-    SettingProto search_prefill_millis = 84;
-    SettingProto search_max_stat_age_millis = 85;
-    SettingProto search_max_source_event_age_millis = 86;
-    SettingProto search_min_impressions_for_source_ranking = 87;
-    SettingProto search_min_clicks_for_source_ranking = 88;
-    SettingProto search_max_shortcuts_returned = 89;
-    SettingProto search_query_thread_core_pool_size = 90;
-    SettingProto search_query_thread_max_pool_size = 91;
-    SettingProto search_shortcut_refresh_core_pool_size = 92;
-    SettingProto search_shortcut_refresh_max_pool_size = 93;
-    SettingProto search_thread_keepalive_seconds = 94;
-    SettingProto search_per_source_concurrent_query_limit = 95;
-    SettingProto mount_play_notification_snd = 96;
-    SettingProto mount_ums_autostart = 97;
-    SettingProto mount_ums_prompt = 98;
-    SettingProto mount_ums_notify_enabled = 99;
-    SettingProto anr_show_background = 100;
-    SettingProto voice_recognition_service = 101;
-    SettingProto package_verifier_user_consent = 102;
-    SettingProto selected_spell_checker = 103;
-    SettingProto selected_spell_checker_subtype = 104;
-    SettingProto spell_checker_enabled = 105;
-    SettingProto incall_power_button_behavior = 106;
-    SettingProto incall_back_button_behavior = 107;
-    SettingProto wake_gesture_enabled = 108;
-    SettingProto doze_enabled = 109;
-    SettingProto doze_always_on = 110;
-    SettingProto doze_pulse_on_pick_up = 111;
-    SettingProto doze_pulse_on_double_tap = 112;
-    SettingProto ui_night_mode = 113;
-    SettingProto screensaver_enabled = 114;
-    SettingProto screensaver_components = 115;
-    SettingProto screensaver_activate_on_dock = 116;
-    SettingProto screensaver_activate_on_sleep = 117;
-    SettingProto screensaver_default_component = 118;
-    SettingProto nfc_payment_default_component = 119;
-    SettingProto nfc_payment_foreground = 120;
-    SettingProto sms_default_application = 121;
-    SettingProto dialer_default_application = 122;
-    SettingProto emergency_assistance_application = 123;
-    SettingProto assist_structure_enabled = 124;
-    SettingProto assist_screenshot_enabled = 125;
-    SettingProto assist_disclosure_enabled = 126;
-    SettingProto enabled_notification_assistant = 127;
-    SettingProto enabled_notification_listeners = 128;
-    SettingProto enabled_notification_policy_access_packages = 129;
-    SettingProto sync_parent_sounds = 130;
-    SettingProto immersive_mode_confirmations = 131;
-    SettingProto print_service_search_uri = 132;
-    SettingProto payment_service_search_uri = 133;
-    SettingProto skip_first_use_hints = 134;
-    SettingProto unsafe_volume_music_active_ms = 135;
-    SettingProto lock_screen_show_notifications = 136;
-    SettingProto tv_input_hidden_inputs = 137;
-    SettingProto tv_input_custom_labels = 138;
-    SettingProto usb_audio_automatic_routing_disabled = 139;
-    SettingProto sleep_timeout = 140;
-    SettingProto double_tap_to_wake = 141;
-    SettingProto assistant = 142;
-    SettingProto camera_gesture_disabled = 143;
-    SettingProto camera_double_tap_power_gesture_disabled = 144;
-    SettingProto camera_double_twist_to_flip_enabled = 145;
-    SettingProto night_display_activated = 146;
-    SettingProto night_display_auto_mode = 147;
-    SettingProto night_display_custom_start_time = 148;
-    SettingProto night_display_custom_end_time = 149;
-    SettingProto brightness_use_twilight = 150;
-    SettingProto enabled_vr_listeners = 151;
-    SettingProto vr_display_mode = 152;
-    SettingProto carrier_apps_handled = 153;
-    SettingProto managed_profile_contact_remote_search = 154;
-    SettingProto automatic_storage_manager_enabled = 155;
-    SettingProto automatic_storage_manager_days_to_retain = 156;
-    SettingProto automatic_storage_manager_bytes_cleared = 157;
-    SettingProto automatic_storage_manager_last_run = 158;
-    SettingProto system_navigation_keys_enabled = 159;
-    SettingProto downloads_backup_enabled = 160;
-    SettingProto downloads_backup_allow_metered = 161;
-    SettingProto downloads_backup_charging_only = 162;
-    SettingProto automatic_storage_manager_downloads_days_to_retain = 163;
-    SettingProto qs_tiles = 164;
-    SettingProto demo_user_setup_complete = 165;
-    SettingProto instant_apps_enabled = 166;
-    SettingProto device_paired = 167;
-    SettingProto notification_badging = 168;
-    SettingProto backup_manager_constants = 169;
+    optional SettingProto android_id = 2;
+    optional SettingProto default_input_method = 3;
+    optional SettingProto selected_input_method_subtype = 4;
+    optional SettingProto input_methods_subtype_history = 5;
+    optional SettingProto input_method_selector_visibility = 6;
+    optional SettingProto voice_interaction_service = 7;
+    optional SettingProto autofill_service = 8;
+    optional SettingProto bluetooth_hci_log = 9;
+    optional SettingProto user_setup_complete = 10;
+    optional SettingProto completed_category_prefix = 11;
+    optional SettingProto enabled_input_methods = 12;
+    optional SettingProto disabled_system_input_methods = 13;
+    optional SettingProto show_ime_with_hard_keyboard = 14;
+    optional SettingProto always_on_vpn_app = 15;
+    optional SettingProto always_on_vpn_lockdown = 16;
+    optional SettingProto install_non_market_apps = 17;
+    optional SettingProto location_mode = 18;
+    optional SettingProto location_previous_mode = 19;
+    optional SettingProto lock_to_app_exit_locked = 20;
+    optional SettingProto lock_screen_lock_after_timeout = 21;
+    optional SettingProto lock_screen_allow_remote_input = 22;
+    optional SettingProto show_note_about_notification_hiding = 23;
+    optional SettingProto trust_agents_initialized = 24;
+    optional SettingProto parental_control_enabled = 25;
+    optional SettingProto parental_control_last_update = 26;
+    optional SettingProto parental_control_redirect_url = 27;
+    optional SettingProto settings_classname = 28;
+    optional SettingProto accessibility_enabled = 29;
+    optional SettingProto touch_exploration_enabled = 30;
+    optional SettingProto enabled_accessibility_services = 31;
+    optional SettingProto touch_exploration_granted_accessibility_services = 32;
+    optional SettingProto accessibility_speak_password = 33;
+    optional SettingProto accessibility_high_text_contrast_enabled = 34;
+    optional SettingProto accessibility_script_injection = 35;
+    optional SettingProto accessibility_screen_reader_url = 36;
+    optional SettingProto accessibility_web_content_key_bindings = 37;
+    optional SettingProto accessibility_display_magnification_enabled = 38;
+    optional SettingProto accessibility_display_magnification_scale = 39;
+    optional SettingProto accessibility_soft_keyboard_mode = 40;
+    optional SettingProto accessibility_captioning_enabled = 41;
+    optional SettingProto accessibility_captioning_locale = 42;
+    optional SettingProto accessibility_captioning_preset = 43;
+    optional SettingProto accessibility_captioning_background_color = 44;
+    optional SettingProto accessibility_captioning_foreground_color = 45;
+    optional SettingProto accessibility_captioning_edge_type = 46;
+    optional SettingProto accessibility_captioning_edge_color = 47;
+    optional SettingProto accessibility_captioning_window_color = 48;
+    optional SettingProto accessibility_captioning_typeface = 49;
+    optional SettingProto accessibility_captioning_font_scale = 50;
+    optional SettingProto accessibility_display_inversion_enabled = 51;
+    optional SettingProto accessibility_display_daltonizer_enabled = 52;
+    optional SettingProto accessibility_display_daltonizer = 53;
+    optional SettingProto accessibility_autoclick_enabled = 54;
+    optional SettingProto accessibility_autoclick_delay = 55;
+    optional SettingProto accessibility_large_pointer_icon = 56;
+    optional SettingProto long_press_timeout = 57;
+    optional SettingProto multi_press_timeout = 58;
+    optional SettingProto enabled_print_services = 59;
+    optional SettingProto disabled_print_services = 60;
+    optional SettingProto display_density_forced = 61;
+    optional SettingProto tts_default_rate = 62;
+    optional SettingProto tts_default_pitch = 63;
+    optional SettingProto tts_default_synth = 64;
+    optional SettingProto tts_default_locale = 65;
+    optional SettingProto tts_enabled_plugins = 66;
+    optional SettingProto connectivity_release_pending_intent_delay_ms = 67;
+    optional SettingProto allowed_geolocation_origins = 68;
+    optional SettingProto preferred_tty_mode = 69;
+    optional SettingProto enhanced_voice_privacy_enabled = 70;
+    optional SettingProto tty_mode_enabled = 71;
+    optional SettingProto backup_enabled = 72;
+    optional SettingProto backup_auto_restore = 73;
+    optional SettingProto backup_provisioned = 74;
+    optional SettingProto backup_transport = 75;
+    optional SettingProto last_setup_shown = 76;
+    optional SettingProto search_global_search_activity = 77;
+    optional SettingProto search_num_promoted_sources = 78;
+    optional SettingProto search_max_results_to_display = 79;
+    optional SettingProto search_max_results_per_source = 80;
+    optional SettingProto search_web_results_override_limit = 81;
+    optional SettingProto search_promoted_source_deadline_millis = 82;
+    optional SettingProto search_source_timeout_millis = 83;
+    optional SettingProto search_prefill_millis = 84;
+    optional SettingProto search_max_stat_age_millis = 85;
+    optional SettingProto search_max_source_event_age_millis = 86;
+    optional SettingProto search_min_impressions_for_source_ranking = 87;
+    optional SettingProto search_min_clicks_for_source_ranking = 88;
+    optional SettingProto search_max_shortcuts_returned = 89;
+    optional SettingProto search_query_thread_core_pool_size = 90;
+    optional SettingProto search_query_thread_max_pool_size = 91;
+    optional SettingProto search_shortcut_refresh_core_pool_size = 92;
+    optional SettingProto search_shortcut_refresh_max_pool_size = 93;
+    optional SettingProto search_thread_keepalive_seconds = 94;
+    optional SettingProto search_per_source_concurrent_query_limit = 95;
+    optional SettingProto mount_play_notification_snd = 96;
+    optional SettingProto mount_ums_autostart = 97;
+    optional SettingProto mount_ums_prompt = 98;
+    optional SettingProto mount_ums_notify_enabled = 99;
+    optional SettingProto anr_show_background = 100;
+    optional SettingProto voice_recognition_service = 101;
+    optional SettingProto package_verifier_user_consent = 102;
+    optional SettingProto selected_spell_checker = 103;
+    optional SettingProto selected_spell_checker_subtype = 104;
+    optional SettingProto spell_checker_enabled = 105;
+    optional SettingProto incall_power_button_behavior = 106;
+    optional SettingProto incall_back_button_behavior = 107;
+    optional SettingProto wake_gesture_enabled = 108;
+    optional SettingProto doze_enabled = 109;
+    optional SettingProto doze_always_on = 110;
+    optional SettingProto doze_pulse_on_pick_up = 111;
+    optional SettingProto doze_pulse_on_double_tap = 112;
+    optional SettingProto ui_night_mode = 113;
+    optional SettingProto screensaver_enabled = 114;
+    optional SettingProto screensaver_components = 115;
+    optional SettingProto screensaver_activate_on_dock = 116;
+    optional SettingProto screensaver_activate_on_sleep = 117;
+    optional SettingProto screensaver_default_component = 118;
+    optional SettingProto nfc_payment_default_component = 119;
+    optional SettingProto nfc_payment_foreground = 120;
+    optional SettingProto sms_default_application = 121;
+    optional SettingProto dialer_default_application = 122;
+    optional SettingProto emergency_assistance_application = 123;
+    optional SettingProto assist_structure_enabled = 124;
+    optional SettingProto assist_screenshot_enabled = 125;
+    optional SettingProto assist_disclosure_enabled = 126;
+    optional SettingProto enabled_notification_assistant = 127;
+    optional SettingProto enabled_notification_listeners = 128;
+    optional SettingProto enabled_notification_policy_access_packages = 129;
+    optional SettingProto sync_parent_sounds = 130;
+    optional SettingProto immersive_mode_confirmations = 131;
+    optional SettingProto print_service_search_uri = 132;
+    optional SettingProto payment_service_search_uri = 133;
+    optional SettingProto skip_first_use_hints = 134;
+    optional SettingProto unsafe_volume_music_active_ms = 135;
+    optional SettingProto lock_screen_show_notifications = 136;
+    optional SettingProto tv_input_hidden_inputs = 137;
+    optional SettingProto tv_input_custom_labels = 138;
+    optional SettingProto usb_audio_automatic_routing_disabled = 139;
+    optional SettingProto sleep_timeout = 140;
+    optional SettingProto double_tap_to_wake = 141;
+    optional SettingProto assistant = 142;
+    optional SettingProto camera_gesture_disabled = 143;
+    optional SettingProto camera_double_tap_power_gesture_disabled = 144;
+    optional SettingProto camera_double_twist_to_flip_enabled = 145;
+    optional SettingProto night_display_activated = 146;
+    optional SettingProto night_display_auto_mode = 147;
+    optional SettingProto night_display_custom_start_time = 148;
+    optional SettingProto night_display_custom_end_time = 149;
+    optional SettingProto brightness_use_twilight = 150;
+    optional SettingProto enabled_vr_listeners = 151;
+    optional SettingProto vr_display_mode = 152;
+    optional SettingProto carrier_apps_handled = 153;
+    optional SettingProto managed_profile_contact_remote_search = 154;
+    optional SettingProto automatic_storage_manager_enabled = 155;
+    optional SettingProto automatic_storage_manager_days_to_retain = 156;
+    optional SettingProto automatic_storage_manager_bytes_cleared = 157;
+    optional SettingProto automatic_storage_manager_last_run = 158;
+    optional SettingProto system_navigation_keys_enabled = 159;
+    optional SettingProto downloads_backup_enabled = 160;
+    optional SettingProto downloads_backup_allow_metered = 161;
+    optional SettingProto downloads_backup_charging_only = 162;
+    optional SettingProto automatic_storage_manager_downloads_days_to_retain = 163;
+    optional SettingProto qs_tiles = 164;
+    optional SettingProto demo_user_setup_complete = 165;
+    optional SettingProto instant_apps_enabled = 166;
+    optional SettingProto device_paired = 167;
+    optional SettingProto notification_badging = 168;
+    optional SettingProto backup_manager_constants = 169;
 }
 
 message SystemSettingsProto {
     // Historical operations
     repeated SettingsOperationProto historical_op = 1;
 
-    SettingProto end_button_behavior = 2;
-    SettingProto advanced_settings = 3;
-    SettingProto bluetooth_discoverability = 4;
-    SettingProto bluetooth_discoverability_timeout = 5;
-    SettingProto font_scale = 6;
-    SettingProto system_locales = 7;
-    SettingProto screen_off_timeout = 8;
-    SettingProto screen_brightness = 9;
-    SettingProto screen_brightness_for_vr = 10;
-    SettingProto screen_brightness_mode = 11;
-    SettingProto screen_auto_brightness_adj = 12;
-    SettingProto mode_ringer_streams_affected = 13;
-    SettingProto mute_streams_affected = 14;
-    SettingProto vibrate_on = 15;
-    SettingProto vibrate_input_devices = 16;
-    SettingProto volume_ring = 17;
-    SettingProto volume_system = 18;
-    SettingProto volume_voice = 19;
-    SettingProto volume_music = 20;
-    SettingProto volume_alarm = 21;
-    SettingProto volume_notification = 22;
-    SettingProto volume_bluetooth_sco = 23;
-    SettingProto volume_master = 24;
-    SettingProto master_mono = 25;
-    SettingProto vibrate_in_silent = 26;
-    SettingProto append_for_last_audible = 27;
-    SettingProto ringtone = 28;
-    SettingProto ringtone_cache = 29;
-    SettingProto notification_sound = 30;
-    SettingProto notification_sound_cache = 31;
-    SettingProto alarm_alert = 32;
-    SettingProto alarm_alert_cache = 33;
-    SettingProto media_button_receiver = 34;
-    SettingProto text_auto_replace = 35;
-    SettingProto text_auto_caps = 36;
-    SettingProto text_auto_punctuate = 37;
-    SettingProto text_show_password = 38;
-    SettingProto show_gtalk_service_status = 39;
-    SettingProto time_12_24 = 40;
-    SettingProto date_format = 41;
-    SettingProto setup_wizard_has_run = 42;
-    SettingProto accelerometer_rotation = 43;
-    SettingProto user_rotation = 44;
-    SettingProto hide_rotation_lock_toggle_for_accessibility = 45;
-    SettingProto vibrate_when_ringing = 46;
-    SettingProto dtmf_tone_when_dialing = 47;
-    SettingProto dtmf_tone_type_when_dialing = 48;
-    SettingProto hearing_aid = 49;
-    SettingProto tty_mode = 50;
-    SettingProto sound_effects_enabled = 51;
-    SettingProto haptic_feedback_enabled = 52;
-    SettingProto notification_light_pulse = 53;
-    SettingProto pointer_location = 54;
-    SettingProto show_touches = 55;
-    SettingProto window_orientation_listener_log = 56;
-    SettingProto lockscreen_sounds_enabled = 57;
-    SettingProto lockscreen_disabled = 58;
-    SettingProto sip_receive_calls = 59;
-    SettingProto sip_call_options = 60;
-    SettingProto sip_always = 61;
-    SettingProto sip_address_only = 62;
-    SettingProto pointer_speed = 63;
-    SettingProto lock_to_app_enabled = 64;
-    SettingProto egg_mode = 65;
-    SettingProto when_to_make_wifi_calls = 66;
+    optional SettingProto end_button_behavior = 2;
+    optional SettingProto advanced_settings = 3;
+    optional SettingProto bluetooth_discoverability = 4;
+    optional SettingProto bluetooth_discoverability_timeout = 5;
+    optional SettingProto font_scale = 6;
+    optional SettingProto system_locales = 7;
+    optional SettingProto screen_off_timeout = 8;
+    optional SettingProto screen_brightness = 9;
+    optional SettingProto screen_brightness_for_vr = 10;
+    optional SettingProto screen_brightness_mode = 11;
+    optional SettingProto screen_auto_brightness_adj = 12;
+    optional SettingProto mode_ringer_streams_affected = 13;
+    optional SettingProto mute_streams_affected = 14;
+    optional SettingProto vibrate_on = 15;
+    optional SettingProto vibrate_input_devices = 16;
+    optional SettingProto volume_ring = 17;
+    optional SettingProto volume_system = 18;
+    optional SettingProto volume_voice = 19;
+    optional SettingProto volume_music = 20;
+    optional SettingProto volume_alarm = 21;
+    optional SettingProto volume_notification = 22;
+    optional SettingProto volume_bluetooth_sco = 23;
+    optional SettingProto volume_master = 24;
+    optional SettingProto master_mono = 25;
+    optional SettingProto vibrate_in_silent = 26;
+    optional SettingProto append_for_last_audible = 27;
+    optional SettingProto ringtone = 28;
+    optional SettingProto ringtone_cache = 29;
+    optional SettingProto notification_sound = 30;
+    optional SettingProto notification_sound_cache = 31;
+    optional SettingProto alarm_alert = 32;
+    optional SettingProto alarm_alert_cache = 33;
+    optional SettingProto media_button_receiver = 34;
+    optional SettingProto text_auto_replace = 35;
+    optional SettingProto text_auto_caps = 36;
+    optional SettingProto text_auto_punctuate = 37;
+    optional SettingProto text_show_password = 38;
+    optional SettingProto show_gtalk_service_status = 39;
+    optional SettingProto time_12_24 = 40;
+    optional SettingProto date_format = 41;
+    optional SettingProto setup_wizard_has_run = 42;
+    optional SettingProto accelerometer_rotation = 43;
+    optional SettingProto user_rotation = 44;
+    optional SettingProto hide_rotation_lock_toggle_for_accessibility = 45;
+    optional SettingProto vibrate_when_ringing = 46;
+    optional SettingProto dtmf_tone_when_dialing = 47;
+    optional SettingProto dtmf_tone_type_when_dialing = 48;
+    optional SettingProto hearing_aid = 49;
+    optional SettingProto tty_mode = 50;
+    optional SettingProto sound_effects_enabled = 51;
+    optional SettingProto haptic_feedback_enabled = 52;
+    optional SettingProto notification_light_pulse = 53;
+    optional SettingProto pointer_location = 54;
+    optional SettingProto show_touches = 55;
+    optional SettingProto window_orientation_listener_log = 56;
+    optional SettingProto lockscreen_sounds_enabled = 57;
+    optional SettingProto lockscreen_disabled = 58;
+    optional SettingProto sip_receive_calls = 59;
+    optional SettingProto sip_call_options = 60;
+    optional SettingProto sip_always = 61;
+    optional SettingProto sip_address_only = 62;
+    optional SettingProto pointer_speed = 63;
+    optional SettingProto lock_to_app_enabled = 64;
+    optional SettingProto egg_mode = 65;
+    optional SettingProto when_to_make_wifi_calls = 66;
 }
 
 message SettingProto {
     // ID of the setting
-    string id = 1;
+    optional string id = 1;
 
     // Name of the setting
-    string name = 2;
+    optional string name = 2;
 
     // Package name of the setting
-    string pkg = 3;
+    optional string pkg = 3;
 
     // Value of this setting
-    string value = 4;
+    optional string value = 4;
 
     // Default value of this setting
-    string default_value = 5;
+    optional string default_value = 5;
 
     // Whether the default is set by the system
-    bool default_from_system = 6;
+    optional bool default_from_system = 6;
 }
 
 message SettingsOperationProto {
     // When the operation happened
-    int64 timestamp = 1;
+    optional int64 timestamp = 1;
 
     // Type of the operation
-    string operation = 2;
+    optional string operation = 2;
 
     // Name of the setting that was affected (optional)
-    string setting = 3;
+    optional string setting = 3;
 }
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index d5ecacc..788ac8f 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -14,71 +14,161 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
+import "frameworks/base/core/proto/android/content/intent.proto";
+import "frameworks/base/core/proto/android/server/intentresolver.proto";
 import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
 import "frameworks/base/core/proto/android/graphics/rect.proto";
+import "frameworks/base/core/proto/android/os/looper.proto";
 
 package com.android.server.am.proto;
 
 option java_multiple_files = true;
 
 message ActivityManagerServiceProto {
-  ActivityStackSupervisorProto activities = 1;
+  optional ActivityStackSupervisorProto activities = 1;
+
+  optional BroadcastProto broadcasts = 2;
+
+  optional ServiceProto services = 3;
+
+  optional ProcessProto processes = 4;
 }
 
 message ActivityStackSupervisorProto {
-  .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
+  optional .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
   repeated ActivityDisplayProto displays = 2;
-  KeyguardControllerProto keyguard_controller = 3;
-  int32 focused_stack_id = 4;
-  .com.android.server.wm.proto.IdentifierProto resumed_activity = 5;
+  optional KeyguardControllerProto keyguard_controller = 3;
+  optional int32 focused_stack_id = 4;
+  optional .com.android.server.wm.proto.IdentifierProto resumed_activity = 5;
 }
 
 /* represents ActivityStackSupervisor.ActivityDisplay */
 message ActivityDisplayProto {
-  .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
-  int32 id = 2;
+  optional .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
+  optional int32 id = 2;
   repeated ActivityStackProto stacks = 3;
 }
 
 message ActivityStackProto {
-  .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
-  int32 id = 2;
+  optional .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
+  optional int32 id = 2;
   repeated TaskRecordProto tasks = 3;
-  .com.android.server.wm.proto.IdentifierProto resumed_activity = 4;
-  int32 display_id = 5;
-  bool fullscreen = 6;
-  .android.graphics.RectProto bounds = 7;
+  optional .com.android.server.wm.proto.IdentifierProto resumed_activity = 4;
+  optional int32 display_id = 5;
+  optional bool fullscreen = 6;
+  optional .android.graphics.RectProto bounds = 7;
 }
 
 message TaskRecordProto {
-  .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
-  int32 id = 2;
+  optional .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
+  optional int32 id = 2;
   repeated ActivityRecordProto activities = 3;
-  int32 stack_id = 4;
-  .android.graphics.RectProto last_non_fullscreen_bounds = 5;
-  string real_activity = 6;
-  string orig_activity = 7;
-  int32 activity_type = 8;
-  int32 return_to_type = 9;
-  int32 resize_mode = 10;
-  bool fullscreen = 11;
-  .android.graphics.RectProto bounds = 12;
-  int32 min_width = 13;
-  int32 min_height = 14;
+  optional int32 stack_id = 4;
+  optional .android.graphics.RectProto last_non_fullscreen_bounds = 5;
+  optional string real_activity = 6;
+  optional string orig_activity = 7;
+  optional int32 activity_type = 8;
+  optional int32 return_to_type = 9;
+  optional int32 resize_mode = 10;
+  optional bool fullscreen = 11;
+  optional .android.graphics.RectProto bounds = 12;
+  optional int32 min_width = 13;
+  optional int32 min_height = 14;
 }
 
 message ActivityRecordProto {
-  .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
-  .com.android.server.wm.proto.IdentifierProto identifier = 2;
-  string state = 3;
-  bool visible = 4;
-  bool front_of_task = 5;
-  int32 proc_id = 6;
+  optional .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
+  optional .com.android.server.wm.proto.IdentifierProto identifier = 2;
+  optional string state = 3;
+  optional bool visible = 4;
+  optional bool front_of_task = 5;
+  optional int32 proc_id = 6;
 }
 
 message KeyguardControllerProto {
-  bool keyguard_showing = 1;
-  bool keyguard_occluded = 2;
-}
\ No newline at end of file
+  optional bool keyguard_showing = 1;
+  optional bool keyguard_occluded = 2;
+}
+
+message BroadcastProto {
+  repeated ReceiverListProto  receiver_list = 1;
+
+  optional .com.android.server.IntentResolverProto receiver_resolver = 2;
+
+  repeated BroadcastQueueProto broadcast_queue = 3;
+
+  repeated StickyBroadcastProto sticky_broadcasts = 4;
+
+  message MainHandler {
+    optional string handler = 1;
+    optional .android.os.LooperProto looper = 2;
+  }
+  optional MainHandler handler = 5;
+}
+
+message ReceiverListProto {
+  optional ProcessRecordProto app = 1;
+  optional int32 pid = 2;
+  optional int32 uid = 3;
+  optional int32 user = 4;
+  optional BroadcastRecordProto current = 5;
+  optional bool linked_to_death = 6;
+  repeated BroadcastFilterProto filters = 7;
+  optional string hex_hash = 8; // this hash is used to find the object in IntentResolver
+}
+
+message ProcessRecordProto {
+  optional int32 pid = 1;
+  optional string process_name = 2;
+  optional int32 uid = 3;
+  optional int32 user_id = 4;
+  optional int32 app_id = 5;
+  optional int32 isolated_app_id = 6;
+}
+
+message BroadcastRecordProto {
+  optional int32 user_id = 1;
+  optional string intent_action = 2;
+}
+
+message BroadcastFilterProto {
+  optional .android.content.IntentFilterProto intent_filter = 1;
+  optional string required_permission = 2;
+  optional string hex_hash = 3; // used to find the object in IntentResolver
+  optional int32 owning_user_id = 4;
+}
+
+message BroadcastQueueProto {
+  optional string queue_name = 1;
+  repeated BroadcastRecordProto parallel_broadcasts = 2;
+  repeated BroadcastRecordProto ordered_broadcasts = 3;
+  optional BroadcastRecordProto pending_broadcast = 4;
+  repeated BroadcastRecordProto historical_broadcasts = 5;
+
+  message BroadcastSummary {
+    optional .android.content.IntentProto intent = 1;
+    optional int64 enqueue_clock_time_ms = 2;
+    optional int64 dispatch_clock_time_ms = 3;
+    optional int64 finish_clock_time_ms = 4;
+  }
+  repeated BroadcastSummary historical_broadcasts_summary = 6;
+}
+
+message StickyBroadcastProto {
+  optional int32 user = 1;
+
+  message StickyAction {
+    optional string name = 1;
+    repeated .android.content.IntentProto intents = 2;
+  }
+  repeated StickyAction actions = 2;
+}
+
+message ServiceProto {
+  // TODO: "dumpsys activity --proto services"
+}
+
+message ProcessProto {
+  // TODO: "dumpsys activity --proto processes"
+}
diff --git a/core/proto/android/server/intentresolver.proto b/core/proto/android/server/intentresolver.proto
new file mode 100644
index 0000000..60c060c
--- /dev/null
+++ b/core/proto/android/server/intentresolver.proto
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+option java_multiple_files = true;
+
+package com.android.server;
+
+message IntentResolverProto {
+
+    message ArrayMapEntry {
+        optional string key = 1;
+        repeated string values = 2;
+    }
+
+    repeated ArrayMapEntry full_mime_types = 1;
+    repeated ArrayMapEntry base_mime_types = 2;
+    repeated ArrayMapEntry wild_mime_types = 3;
+    repeated ArrayMapEntry schemes = 4;
+    repeated ArrayMapEntry non_data_actions = 5;
+    repeated ArrayMapEntry mime_typed_actions = 6;
+}
+
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index d177f1c..064523a 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 import "frameworks/base/core/proto/android/content/configuration.proto";
 import "frameworks/base/core/proto/android/graphics/rect.proto";
 import "frameworks/base/core/proto/android/view/displayinfo.proto";
@@ -26,21 +25,21 @@
 option java_multiple_files = true;
 
 message WindowManagerServiceProto {
-  WindowManagerPolicyProto policy = 1;
+  optional WindowManagerPolicyProto policy = 1;
   /* window hierarchy root */
-  RootWindowContainerProto root_window_container = 2;
-  IdentifierProto focused_window = 3;
-  string focused_app = 4;
-  IdentifierProto input_method_window = 5;
-  bool display_frozen = 6;
-  int32 rotation = 7;
-  int32 last_orientation = 8;
-  AppTransitionProto app_transition = 9;
+  optional RootWindowContainerProto root_window_container = 2;
+  optional IdentifierProto focused_window = 3;
+  optional string focused_app = 4;
+  optional IdentifierProto input_method_window = 5;
+  optional bool display_frozen = 6;
+  optional int32 rotation = 7;
+  optional int32 last_orientation = 8;
+  optional AppTransitionProto app_transition = 9;
 }
 
 /* represents DisplayContent */
 message RootWindowContainerProto {
-  WindowContainerProto window_container = 1;
+  optional WindowContainerProto window_container = 1;
   repeated DisplayProto displays = 2;
   /* window references in top down z order */
   repeated IdentifierProto windows = 3;
@@ -48,7 +47,7 @@
 
 /* represents PhoneWindowManager */
 message WindowManagerPolicyProto {
-  .android.graphics.RectProto stable_bounds = 1;
+  optional .android.graphics.RectProto stable_bounds = 1;
 }
 
 /* represents AppTransition */
@@ -59,7 +58,7 @@
     APP_STATE_RUNNING = 2;
     APP_STATE_TIMEOUT = 3;
   }
-  AppState app_transition_state = 1;
+  optional AppState app_transition_state = 1;
   /* definitions for constants found in {@link com.android.server.wm.AppTransition} */
   enum TransitionType {
     TRANSIT_NONE = 0;
@@ -83,124 +82,124 @@
     TRANSIT_KEYGUARD_OCCLUDE = 22;
     TRANSIT_KEYGUARD_UNOCCLUDE = 23;
   }
-  TransitionType last_used_app_transition = 2;
+  optional TransitionType last_used_app_transition = 2;
 }
 
 /* represents DisplayContent */
 message DisplayProto {
-  WindowContainerProto window_container = 1;
-  int32 id = 2;
+  optional WindowContainerProto window_container = 1;
+  optional int32 id = 2;
   repeated StackProto stacks = 3;
-  DockedStackDividerControllerProto docked_stack_divider_controller = 4;
-  PinnedStackControllerProto pinned_stack_controller = 5;
+  optional DockedStackDividerControllerProto docked_stack_divider_controller = 4;
+  optional PinnedStackControllerProto pinned_stack_controller = 5;
   /* non app windows */
   repeated WindowTokenProto above_app_windows = 6;
   repeated WindowTokenProto below_app_windows = 7;
   repeated WindowTokenProto ime_windows = 8;
-  int32 dpi = 9;
-  .android.view.DisplayInfoProto display_info = 10;
-  int32 rotation = 11;
-  ScreenRotationAnimationProto screen_rotation_animation = 12;
+  optional int32 dpi = 9;
+  optional .android.view.DisplayInfoProto display_info = 10;
+  optional int32 rotation = 11;
+  optional ScreenRotationAnimationProto screen_rotation_animation = 12;
 }
 
 
 /* represents DockedStackDividerController */
 message DockedStackDividerControllerProto {
-  bool minimized_dock = 1;
+  optional bool minimized_dock = 1;
 }
 
 /* represents PinnedStackController */
 message PinnedStackControllerProto {
-  .android.graphics.RectProto default_bounds = 1;
-  .android.graphics.RectProto movement_bounds = 2;
+  optional .android.graphics.RectProto default_bounds = 1;
+  optional .android.graphics.RectProto movement_bounds = 2;
 }
 
 /* represents TaskStack */
 message StackProto {
-  WindowContainerProto window_container = 1;
-  int32 id = 2;
+  optional WindowContainerProto window_container = 1;
+  optional int32 id = 2;
   repeated TaskProto tasks = 3;
-  bool fills_parent = 4;
-  .android.graphics.RectProto bounds = 5;
-  bool animation_background_surface_is_dimming = 6;
+  optional bool fills_parent = 4;
+  optional .android.graphics.RectProto bounds = 5;
+  optional bool animation_background_surface_is_dimming = 6;
 }
 
 /* represents Task */
 message TaskProto {
-  WindowContainerProto window_container = 1;
-  int32 id = 2;
+  optional WindowContainerProto window_container = 1;
+  optional int32 id = 2;
   repeated AppWindowTokenProto app_window_tokens = 3;
-  bool fills_parent = 4;
-  .android.graphics.RectProto bounds = 5;
-  .android.graphics.RectProto temp_inset_bounds = 6;
+  optional bool fills_parent = 4;
+  optional .android.graphics.RectProto bounds = 5;
+  optional .android.graphics.RectProto temp_inset_bounds = 6;
 }
 
 /* represents AppWindowToken */
 message AppWindowTokenProto {
   /* obtained from ActivityRecord */
-  string name = 1;
-  WindowTokenProto window_token = 2;
+  optional string name = 1;
+  optional WindowTokenProto window_token = 2;
 }
 
 /* represents WindowToken */
 message WindowTokenProto {
-  WindowContainerProto window_container = 1;
-  int32 hash_code = 2;
+  optional WindowContainerProto window_container = 1;
+  optional int32 hash_code = 2;
   repeated WindowStateProto windows = 3;
 }
 
 /* represents WindowState */
 message WindowStateProto {
-  WindowContainerProto window_container = 1;
-  IdentifierProto identifier = 2;
-  int32 display_id = 3;
-  int32 stack_id = 4;
-  .android.view.WindowLayoutParamsProto attributes = 5;
-  .android.graphics.RectProto given_content_insets = 6;
-  .android.graphics.RectProto frame = 7;
-  .android.graphics.RectProto containing_frame = 8;
-  .android.graphics.RectProto parent_frame = 9;
-  .android.graphics.RectProto content_frame = 10;
-  .android.graphics.RectProto content_insets = 11;
-  .android.graphics.RectProto surface_insets = 12;
-  WindowStateAnimatorProto animator = 13;
-  bool animating_exit = 14;
+  optional WindowContainerProto window_container = 1;
+  optional IdentifierProto identifier = 2;
+  optional int32 display_id = 3;
+  optional int32 stack_id = 4;
+  optional .android.view.WindowLayoutParamsProto attributes = 5;
+  optional .android.graphics.RectProto given_content_insets = 6;
+  optional .android.graphics.RectProto frame = 7;
+  optional .android.graphics.RectProto containing_frame = 8;
+  optional .android.graphics.RectProto parent_frame = 9;
+  optional .android.graphics.RectProto content_frame = 10;
+  optional .android.graphics.RectProto content_insets = 11;
+  optional .android.graphics.RectProto surface_insets = 12;
+  optional WindowStateAnimatorProto animator = 13;
+  optional bool animating_exit = 14;
   repeated WindowStateProto child_windows = 15;
 }
 
 message IdentifierProto {
-  int32 hash_code = 1;
-  int32 user_id = 2;
-  string title = 3;
+  optional int32 hash_code = 1;
+  optional int32 user_id = 2;
+  optional string title = 3;
 }
 
 /* represents WindowStateAnimator */
 message WindowStateAnimatorProto {
-  .android.graphics.RectProto last_clip_rect = 1;
-  WindowSurfaceControllerProto surface = 2;
+  optional .android.graphics.RectProto last_clip_rect = 1;
+  optional WindowSurfaceControllerProto surface = 2;
 }
 
 /* represents WindowSurfaceController */
 message WindowSurfaceControllerProto {
-  bool shown = 1;
-  int32 layer = 2;
+  optional bool shown = 1;
+  optional int32 layer = 2;
 }
 
 /* represents ScreenRotationAnimation */
 message ScreenRotationAnimationProto {
-  bool started = 1;
-  bool animation_running = 2;
+  optional bool started = 1;
+  optional bool animation_running = 2;
 }
 
 /* represents WindowContainer */
 message WindowContainerProto {
-  ConfigurationContainerProto configuration_container = 1;
-  int32 orientation = 2;
+  optional ConfigurationContainerProto configuration_container = 1;
+  optional int32 orientation = 2;
 }
 
 /* represents ConfigurationContainer */
 message ConfigurationContainerProto {
-  .android.content.ConfigurationProto override_configuration = 1;
-  .android.content.ConfigurationProto full_configuration = 2;
-  .android.content.ConfigurationProto merged_override_configuration = 3;
+  optional .android.content.ConfigurationProto override_configuration = 1;
+  optional .android.content.ConfigurationProto full_configuration = 2;
+  optional .android.content.ConfigurationProto merged_override_configuration = 3;
 }
diff --git a/core/proto/android/service/appwidget.proto b/core/proto/android/service/appwidget.proto
index 1f04f71..3f46d2b 100644
--- a/core/proto/android/service/appwidget.proto
+++ b/core/proto/android/service/appwidget.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 package android.service.appwidget;
 
 option java_multiple_files = true;
@@ -28,13 +27,13 @@
 
 // represents a bound widget
 message WidgetProto {
-  bool isCrossProfile = 1; // true if host and provider belong to diff users
-  bool isHostStopped = 2; // true if host has not called startListening yet
-  string hostPackage = 3;
-  string providerPackage = 4;
-  string providerClass = 5;
-  int32 minWidth = 6;
-  int32 minHeight = 7;
-  int32 maxWidth = 8;
-  int32 maxHeight = 9;
+  optional bool isCrossProfile = 1; // true if host and provider belong to diff users
+  optional bool isHostStopped = 2; // true if host has not called startListening yet
+  optional string hostPackage = 3;
+  optional string providerPackage = 4;
+  optional string providerClass = 5;
+  optional int32 minWidth = 6;
+  optional int32 minHeight = 7;
+  optional int32 maxWidth = 8;
+  optional int32 maxHeight = 9;
 }
diff --git a/core/proto/android/service/battery.proto b/core/proto/android/service/battery.proto
index 33ad682b..998a808 100644
--- a/core/proto/android/service/battery.proto
+++ b/core/proto/android/service/battery.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 package android.service.battery;
 
 option java_multiple_files = true;
@@ -48,29 +47,29 @@
     }
 
     // If true: UPDATES STOPPED -- use 'reset' to restart
-    bool are_updates_stopped = 1;
+    optional bool are_updates_stopped = 1;
     // Plugged status of power sources
-    BatteryPlugged plugged = 2;
+    optional BatteryPlugged plugged = 2;
     // Max current in microamperes
-    int32 max_charging_current = 3;
+    optional int32 max_charging_current = 3;
     // Max voltage
-    int32 max_charging_voltage = 4;
+    optional int32 max_charging_voltage = 4;
     // Battery capacity in microampere-hours
-    int32 charge_counter = 5;
+    optional int32 charge_counter = 5;
     // Charging status
-    BatteryStatus status = 6;
+    optional BatteryStatus status = 6;
     // Battery health
-    BatteryHealth health = 7;
+    optional BatteryHealth health = 7;
     // True if the battery is present
-    bool is_present = 8;
+    optional bool is_present = 8;
     // Charge level, from 0 through "scale" inclusive
-    int32 level = 9;
+    optional int32 level = 9;
     // The maximum value for the charge level
-    int32 scale = 10;
+    optional int32 scale = 10;
     // Battery voltage in millivolts
-    int32 voltage = 11;
+    optional int32 voltage = 11;
     // Battery temperature in tenths of a degree Centigrade
-    int32 temperature = 12;
+    optional int32 temperature = 12;
     // The type of battery installed, e.g. "Li-ion"
-    string technology = 13;
+    optional string technology = 13;
 }
diff --git a/core/proto/android/service/batterystats.proto b/core/proto/android/service/batterystats.proto
index 4e989b7..54d3f40 100644
--- a/core/proto/android/service/batterystats.proto
+++ b/core/proto/android/service/batterystats.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 package android.service.batterystats;
 
 option java_multiple_files = true;
@@ -24,5 +23,5 @@
 import "frameworks/base/core/proto/android/os/batterystats.proto";
 
 message BatteryStatsServiceDumpProto {
-  android.os.BatteryStatsProto batterystats = 1;
+  optional android.os.BatteryStatsProto batterystats = 1;
 }
diff --git a/core/proto/android/service/diskstats.proto b/core/proto/android/service/diskstats.proto
index 4057e45..f725e8a 100644
--- a/core/proto/android/service/diskstats.proto
+++ b/core/proto/android/service/diskstats.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 package android.service.diskstats;
 
 option java_multiple_files = true;
@@ -33,51 +32,51 @@
         ENCRYPTION_FILE_BASED = 3;
     }
     // Whether the latency test resulted in an error
-    bool has_test_error = 1;
+    optional bool has_test_error = 1;
     // If the test errored, error message is contained here
-    string error_message = 2;
+    optional string error_message = 2;
     // 512B write latency in milliseconds, if the test was successful
-    int32 write_512b_latency_millis = 3;
+    optional int32 write_512b_latency_millis = 3;
     // Free Space in the major partitions
     repeated DiskStatsFreeSpaceProto partitions_free_space = 4;
     // Is the device using file-based encryption, full disk encryption or other
-    EncryptionType encryption = 5;
+    optional EncryptionType encryption = 5;
     // Cached values of folder sizes, etc.
-    DiskStatsCachedValuesProto cached_folder_sizes = 6;
+    optional DiskStatsCachedValuesProto cached_folder_sizes = 6;
 }
 
 message DiskStatsCachedValuesProto {
     // Total app code size, in kilobytes
-    int64 agg_apps_size = 1;
+    optional int64 agg_apps_size = 1;
     // Total app cache size, in kilobytes
-    int64 agg_apps_cache_size = 2;
+    optional int64 agg_apps_cache_size = 2;
     // Size of image files, in kilobytes
-    int64 photos_size = 3;
+    optional int64 photos_size = 3;
     // Size of video files, in kilobytes
-    int64 videos_size = 4;
+    optional int64 videos_size = 4;
     // Size of audio files, in kilobytes
-    int64 audio_size = 5;
+    optional int64 audio_size = 5;
     // Size of downloads, in kilobytes
-    int64 downloads_size = 6;
+    optional int64 downloads_size = 6;
     // Size of system directory, in kilobytes
-    int64 system_size = 7;
+    optional int64 system_size = 7;
     // Size of other files, in kilobytes
-    int64 other_size = 8;
+    optional int64 other_size = 8;
     // Sizes of individual packages
     repeated DiskStatsAppSizesProto app_sizes = 9;
     // Total app data size, in kilobytes
-    int64 agg_apps_data_size = 10;
+    optional int64 agg_apps_data_size = 10;
 }
 
 message DiskStatsAppSizesProto {
     // Name of the package
-    string package_name = 1;
+    optional string package_name = 1;
     // App's code size in kilobytes
-    int64 app_size = 2;
+    optional int64 app_size = 2;
     // App's cache size in kilobytes
-    int64 cache_size = 3;
+    optional int64 cache_size = 3;
     // App's data size in kilobytes
-    int64 app_data_size = 4;
+    optional int64 app_data_size = 4;
 }
 
 message DiskStatsFreeSpaceProto {
@@ -90,9 +89,9 @@
         FOLDER_SYSTEM = 2;
     }
     // Which folder?
-    Folder folder = 1;
+    optional Folder folder = 1;
     // Available space, in kilobytes
-    int64 available_space = 2;
+    optional int64 available_space = 2;
     // Total space, in kilobytes
-    int64 total_space = 3;
+    optional int64 total_space = 3;
 }
diff --git a/core/proto/android/service/fingerprint.proto b/core/proto/android/service/fingerprint.proto
index f88b762..0826ad5 100644
--- a/core/proto/android/service/fingerprint.proto
+++ b/core/proto/android/service/fingerprint.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 package android.service.fingerprint;
 
 option java_multiple_files = true;
@@ -28,33 +27,33 @@
 
 message FingerprintUserStatsProto {
     // Should be 0, 10, 11, 12, etc. where 0 is the owner.
-    int32 user_id = 1;
+    optional int32 user_id = 1;
 
     // The number of fingerprints registered to this user.
-    int32 num_fingerprints = 2;
+    optional int32 num_fingerprints = 2;
 
     // Normal fingerprint authentications (e.g. lockscreen).
-    FingerprintActionStatsProto normal = 3;
+    optional FingerprintActionStatsProto normal = 3;
 
     // Crypto authentications (e.g. to unlock password storage, make secure
     // purchases, etc).
-    FingerprintActionStatsProto crypto = 4;
+    optional FingerprintActionStatsProto crypto = 4;
 }
 
 message FingerprintActionStatsProto {
     // Number of accepted fingerprints.
-    int32 accept = 1;
+    optional int32 accept = 1;
 
     // Number of rejected fingerprints.
-    int32 reject = 2;
+    optional int32 reject = 2;
 
     // Total number of acquisitions. Should be >= accept+reject due to poor
     // image acquisition in some cases (too fast, too slow, dirty sensor, etc.)
-    int32 acquire = 3;
+    optional int32 acquire = 3;
 
     // Total number of lockouts.
-    int32 lockout = 4;
+    optional int32 lockout = 4;
 
     // Total number of permanent lockouts.
-    int32 lockout_permanent = 5;
+    optional int32 lockout_permanent = 5;
 }
diff --git a/core/proto/android/service/graphicsstats.proto b/core/proto/android/service/graphicsstats.proto
index b8679b0..ee9d6fc 100644
--- a/core/proto/android/service/graphicsstats.proto
+++ b/core/proto/android/service/graphicsstats.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 package android.service;
 
 option java_multiple_files = true;
@@ -29,19 +28,19 @@
 message GraphicsStatsProto {
 
     // The package name of the app
-    string package_name = 1;
+    optional string package_name = 1;
 
     // The version code of the app
-    int32 version_code = 2;
+    optional int32 version_code = 2;
 
     // The start & end timestamps in UTC as
     // milliseconds since January 1, 1970
     // Compatible with java.util.Date#setTime()
-    int64 stats_start = 3;
-    int64 stats_end = 4;
+    optional int64 stats_start = 3;
+    optional int64 stats_end = 4;
 
     // The aggregated statistics for the package
-    GraphicsStatsJankSummaryProto summary = 5;
+    optional GraphicsStatsJankSummaryProto summary = 5;
 
     // The frame time histogram for the package
     repeated GraphicsStatsHistogramBucketProto histogram = 6;
@@ -49,31 +48,31 @@
 
 message GraphicsStatsJankSummaryProto {
     // Distinct frame count.
-    int32 total_frames = 1;
+    optional int32 total_frames = 1;
 
     // Number of frames with slow render time. Frames are considered janky if
     // they took more than a vsync interval (typically 16.667ms) to be rendered.
-    int32 janky_frames = 2;
+    optional int32 janky_frames = 2;
 
     // Number of "missed vsync" events.
-    int32 missed_vsync_count = 3;
+    optional int32 missed_vsync_count = 3;
 
     // Number of "high input latency" events.
-    int32 high_input_latency_count = 4;
+    optional int32 high_input_latency_count = 4;
 
     // Number of "slow UI thread" events.
-    int32 slow_ui_thread_count = 5;
+    optional int32 slow_ui_thread_count = 5;
 
     // Number of "slow bitmap upload" events.
-    int32 slow_bitmap_upload_count = 6;
+    optional int32 slow_bitmap_upload_count = 6;
 
     // Number of "slow draw" events.
-    int32 slow_draw_count = 7;
+    optional int32 slow_draw_count = 7;
 }
 
 message GraphicsStatsHistogramBucketProto {
     // Lower bound of render time in milliseconds.
-    int32 render_millis = 1;
+    optional int32 render_millis = 1;
     // Number of frames in the bucket.
-    int32 frame_count = 2;
+    optional int32 frame_count = 2;
 }
diff --git a/core/proto/android/service/netstats.proto b/core/proto/android/service/netstats.proto
index 5a577b1..23613fd 100644
--- a/core/proto/android/service/netstats.proto
+++ b/core/proto/android/service/netstats.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 package android.service;
 
 option java_multiple_files = true;
@@ -28,23 +27,23 @@
     repeated NetworkInterfaceProto active_uid_interfaces = 2;
 
     // Device level network stats, which may include non-IP layer traffic.
-    NetworkStatsRecorderProto dev_stats = 3;
+    optional NetworkStatsRecorderProto dev_stats = 3;
 
     // IP-layer traffic stats.
-    NetworkStatsRecorderProto xt_stats = 4;
+    optional NetworkStatsRecorderProto xt_stats = 4;
 
     // Per-UID network stats.
-    NetworkStatsRecorderProto uid_stats = 5;
+    optional NetworkStatsRecorderProto uid_stats = 5;
 
     // Per-UID, per-tag network stats, excluding the default tag (i.e. tag=0).
-    NetworkStatsRecorderProto uid_tag_stats = 6;
+    optional NetworkStatsRecorderProto uid_tag_stats = 6;
 }
 
 // Corresponds to NetworkStatsService.mActiveIfaces/mActiveUidIfaces.
 message NetworkInterfaceProto {
-    string interface = 1;
+    optional string interface = 1;
 
-    NetworkIdentitySetProto identities = 2;
+    optional NetworkIdentitySetProto identities = 2;
 }
 
 // Corresponds to NetworkIdentitySet.
@@ -55,22 +54,22 @@
 // Corresponds to NetworkIdentity.
 message NetworkIdentityProto {
     // Constats from ConnectivityManager.TYPE_*.
-    int32 type = 1;
+    optional int32 type = 1;
 
-    string subscriber_id = 2;
+    optional string subscriber_id = 2;
 
-    string network_id = 3;
+    optional string network_id = 3;
 
-    bool roaming = 4;
+    optional bool roaming = 4;
 
-    bool metered = 5;
+    optional bool metered = 5;
 }
 
 // Corresponds to NetworkStatsRecorder.
 message NetworkStatsRecorderProto {
-    int64 pending_total_bytes = 1;
+    optional int64 pending_total_bytes = 1;
 
-    NetworkStatsCollectionProto complete_history = 2;
+    optional NetworkStatsCollectionProto complete_history = 2;
 }
 
 // Corresponds to NetworkStatsCollection.
@@ -80,26 +79,26 @@
 
 // Corresponds to NetworkStatsCollection.mStats.
 message NetworkStatsCollectionStatsProto {
-    NetworkStatsCollectionKeyProto key = 1;
+    optional NetworkStatsCollectionKeyProto key = 1;
 
-    NetworkStatsHistoryProto history = 2;
+    optional NetworkStatsHistoryProto history = 2;
 }
 
 // Corresponds to NetworkStatsCollection.Key.
 message NetworkStatsCollectionKeyProto {
-    NetworkIdentitySetProto identity = 1;
+    optional NetworkIdentitySetProto identity = 1;
 
-    int32 uid = 2;
+    optional int32 uid = 2;
 
-    int32 set = 3;
+    optional int32 set = 3;
 
-    int32 tag = 4;
+    optional int32 tag = 4;
 }
 
 // Corresponds to NetworkStatsHistory.
 message NetworkStatsHistoryProto {
     // Duration for this bucket in milliseconds.
-    int64 bucket_duration_ms = 1;
+    optional int64 bucket_duration_ms = 1;
 
     repeated NetworkStatsHistoryBucketProto buckets = 2;
 }
@@ -107,15 +106,15 @@
 // Corresponds to each bucket in NetworkStatsHistory.
 message NetworkStatsHistoryBucketProto {
     // Bucket start time in milliseconds since epoch.
-    int64 bucket_start_ms = 1;
+    optional int64 bucket_start_ms = 1;
 
-    int64 rx_bytes = 2;
+    optional int64 rx_bytes = 2;
 
-    int64 rx_packets = 3;
+    optional int64 rx_packets = 3;
 
-    int64 tx_bytes = 4;
+    optional int64 tx_bytes = 4;
 
-    int64 tx_packets = 5;
+    optional int64 tx_packets = 5;
 
-    int64 operations = 6;
+    optional int64 operations = 6;
 }
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
index d8cb1a7..7a0e152 100644
--- a/core/proto/android/service/notification.proto
+++ b/core/proto/android/service/notification.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 package android.service.notification;
 
 option java_multiple_files = true;
@@ -29,54 +28,60 @@
 message NotificationServiceDumpProto {
     repeated NotificationRecordProto records = 1;
 
-    ZenModeProto zen = 2;
+    optional ZenModeProto zen = 2;
 
-    ManagedServicesProto notification_listeners = 3;
+    optional ManagedServicesProto notification_listeners = 3;
 
-    int32 listener_hints = 4;
+    optional int32 listener_hints = 4;
 
     repeated ListenersDisablingEffectsProto listeners_disabling_effects = 5;
 
-    ManagedServicesProto notification_assistants = 6;
+    optional ManagedServicesProto notification_assistants = 6;
 
-    ManagedServicesProto condition_providers = 7;
+    optional ManagedServicesProto condition_providers = 7;
 
-    RankingHelperProto ranking_config = 8;
+    optional RankingHelperProto ranking_config = 8;
 }
 
 message NotificationRecordProto {
-    string key = 1;
-    State state = 2;
-    int32 flags = 3;
-    string channelId = 4;
-    string sound = 5;
-    int32 sound_usage = 6;
-    bool can_vibrate = 7;
-    bool can_show_light = 8;
-    string group_key = 9;
-    int32 importance = 10;
+    optional string key = 1;
+
+    enum State {
+        ENQUEUED = 0;
+        POSTED = 1;
+        SNOOZED = 2;
+    }
+    optional State state = 2;
+    optional int32 flags = 3;
+    optional string channelId = 4;
+    optional string sound = 5;
+    optional int32 sound_usage = 6;
+    optional bool can_vibrate = 7;
+    optional bool can_show_light = 8;
+    optional string group_key = 9;
+    optional int32 importance = 10;
 }
 
 message ListenersDisablingEffectsProto {
-    int32 hint = 1;
+    optional int32 hint = 1;
     repeated ManagedServiceInfoProto listeners = 2;
 }
 
 message ManagedServiceInfoProto {
-    android.content.ComponentNameProto component = 1;
-    int32 user_id = 2;
-    string service = 3;
-    bool is_system = 4;
-    bool is_guest = 5;
+    optional android.content.ComponentNameProto component = 1;
+    optional int32 user_id = 2;
+    optional string service = 3;
+    optional bool is_system = 4;
+    optional bool is_guest = 5;
 }
 
 message ManagedServicesProto {
-    string caption = 1;
+    optional string caption = 1;
 
     message ServiceProto {
         repeated string name = 1;
-        int32 user_id = 2;
-        bool is_primary = 3;
+        optional int32 user_id = 2;
+        optional bool is_primary = 3;
     }
     repeated ServiceProto approved = 2;
 
@@ -94,17 +99,17 @@
     repeated string notification_signal_extractors = 1;
 
     message RecordProto {
-        string package = 1;
+        optional string package = 1;
         // Default value is UNKNOWN_UID = USER_NULL = -10000.
-        int32 uid = 2;
+        optional int32 uid = 2;
         // Default is IMPORTANCE_UNSPECIFIED (-1000).
-        int32 importance = 3;
+        optional int32 importance = 3;
         // Default is PRIORITY_DEFAULT (0).
-        int32 priority = 4;
+        optional int32 priority = 4;
         // Default is VISIBILITY_NO_OVERRIDE (-1000).
-        int32 visibility = 5;
+        optional int32 visibility = 5;
         // Default is true.
-        bool show_badge = 6;
+        optional bool show_badge = 6;
         repeated android.app.NotificationChannelProto channels = 7;
         repeated android.app.NotificationChannelGroupProto channel_groups = 8;
     }
@@ -112,25 +117,16 @@
     repeated RecordProto records_restored_without_uid = 3;
 }
 
-enum State {
-    ENQUEUED = 0;
-
-    POSTED = 1;
-
-    SNOOZED = 2;
-}
-
 message ZenModeProto {
-    ZenMode zen_mode = 1;
+    enum ZenMode {
+        ZEN_MODE_OFF = 0;
+        ZEN_MODE_IMPORTANT_INTERRUPTIONS = 1;
+        ZEN_MODE_NO_INTERRUPTIONS = 2;
+        ZEN_MODE_ALARMS = 3;
+    }
+    optional ZenMode zen_mode = 1;
     repeated string enabled_active_conditions = 2;
-    int32 suppressed_effects = 3;
+    optional int32 suppressed_effects = 3;
     repeated string suppressors = 4;
-    android.app.PolicyProto policy = 5;
-}
-
-enum ZenMode {
-    ZEN_MODE_OFF = 0;
-    ZEN_MODE_IMPORTANT_INTERRUPTIONS = 1;
-    ZEN_MODE_NO_INTERRUPTIONS = 2;
-    ZEN_MODE_ALARMS = 3;
+    optional android.app.PolicyProto policy = 5;
 }
diff --git a/core/proto/android/service/package.proto b/core/proto/android/service/package.proto
index 326b0eb..aa1a575 100644
--- a/core/proto/android/service/package.proto
+++ b/core/proto/android/service/package.proto
@@ -14,43 +14,40 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 package android.service.pm;
 
+import "frameworks/base/core/proto/android/content/featureinfo.proto";
+
 option java_multiple_files = true;
 option java_outer_classname = "PackageServiceProto";
 
 message PackageServiceDumpProto {
     message PackageShortProto {
         // Name of package. e.g. "com.android.providers.telephony".
-        string name = 1;
+        optional string name = 1;
         // UID for this package as assigned by Android OS.
-        int32 uid = 2;
+        optional int32 uid = 2;
     }
     message SharedLibraryProto {
-        string name = 1;
+        optional string name = 1;
         // True if library path is not null (jar), false otherwise (apk)
-        bool is_jar = 2;
+        optional bool is_jar = 2;
         // Should be filled if is_jar is true
-        string path = 3;
+        optional string path = 3;
         // Should be filled if is_jar is false
-        string apk = 4;
-    }
-    message FeatureProto {
-        string name = 1;
-        int32 version = 2;
+        optional string apk = 4;
     }
     message SharedUserProto {
-        int32 user_id = 1;
-        string name = 2;
+        optional int32 user_id = 1;
+        optional string name = 2;
     }
 
     // Installed packages.
-    PackageShortProto required_verifier_package = 1;
-    PackageShortProto verifier_package = 2;
+    optional PackageShortProto required_verifier_package = 1;
+    optional PackageShortProto verifier_package = 2;
     repeated SharedLibraryProto shared_libraries = 3;
-    repeated FeatureProto features = 4;
+    repeated android.content.pm.FeatureInfoProto features = 4;
     repeated PackageProto packages = 5;
     repeated SharedUserProto shared_users = 6;
     // Messages from the settings problem file
@@ -59,8 +56,8 @@
 
 message PackageProto {
     message SplitProto {
-        string name = 1;
-        int32 revision_code = 2;
+        optional string name = 1;
+        optional int32 revision_code = 2;
     }
     message UserInfoProto {
         enum InstallType {
@@ -87,32 +84,32 @@
             COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED = 4;
         }
 
-        int32 id = 1;
-        InstallType install_type = 2;
+        optional int32 id = 1;
+        optional InstallType install_type = 2;
         // Is the app restricted by owner / admin
-        bool is_hidden = 3;
-        bool is_suspended = 4;
-        bool is_stopped = 5;
-        bool is_launched = 6;
-        EnabledState enabled_state = 7;
-        string last_disabled_app_caller = 8;
+        optional bool is_hidden = 3;
+        optional bool is_suspended = 4;
+        optional bool is_stopped = 5;
+        optional bool is_launched = 6;
+        optional EnabledState enabled_state = 7;
+        optional string last_disabled_app_caller = 8;
     }
 
     // Name of package. e.g. "com.android.providers.telephony".
-    string name = 1;
+    optional string name = 1;
     // UID for this package as assigned by Android OS.
-    int32 uid = 2;
+    optional int32 uid = 2;
     // Package's reported version.
-    int32 version_code = 3;
+    optional int32 version_code = 3;
     // Package's reported version string (what's displayed to the user).
-    string version_string = 4;
+    optional string version_string = 4;
     // UTC timestamp of install
-    int64 install_time_ms = 5;
+    optional int64 install_time_ms = 5;
     // Millisecond UTC timestamp of latest update adjusted to Google's server clock.
-    int64 update_time_ms = 6;
+    optional int64 update_time_ms = 6;
     // From "dumpsys package" - name of package which installed this one.
     // Typically "" if system app or "com.android.vending" if Play Store.
-    string installer_name = 7;
+    optional string installer_name = 7;
     // Split APKs.
     repeated SplitProto splits = 8;
     // Per-user package info.
diff --git a/core/proto/android/service/power.proto b/core/proto/android/service/power.proto
index 1830dbf..5d53847 100644
--- a/core/proto/android/service/power.proto
+++ b/core/proto/android/service/power.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 package android.service.power;
 
 option java_multiple_files = true;
@@ -27,23 +26,23 @@
 
 message PowerServiceDumpProto {
     message ConstantsProto {
-        bool is_no_cached_wake_locks = 1;
+        optional bool is_no_cached_wake_locks = 1;
     }
     message ActiveWakeLocksProto {
-        bool is_cpu = 1;
-        bool is_screen_bright = 2;
-        bool is_screen_dim = 3;
-        bool is_button_bright = 4;
-        bool is_proximity_screen_off = 5;
+        optional bool is_cpu = 1;
+        optional bool is_screen_bright = 2;
+        optional bool is_screen_dim = 3;
+        optional bool is_button_bright = 4;
+        optional bool is_proximity_screen_off = 5;
         // only set if already awake
-        bool is_stay_awake = 6;
-        bool is_doze = 7;
-        bool is_draw = 8;
+        optional bool is_stay_awake = 6;
+        optional bool is_doze = 7;
+        optional bool is_draw = 8;
     }
     message UserActivityProto {
-        bool is_screen_bright = 1;
-        bool is_screen_dim = 2;
-        bool is_screen_dream = 3;
+        optional bool is_screen_bright = 1;
+        optional bool is_screen_dim = 2;
+        optional bool is_screen_dream = 3;
     }
     message UidProto {
         // Enum values gotten from ActivityManager.java
@@ -88,12 +87,12 @@
             // Process does not exist.
             PROCESS_STATE_NONEXISTENT = 17;
         }
-        int32 uid = 1;
-        string uid_string = 2;
-        bool is_active = 3;
-        int32 num_wake_locks = 4;
-        bool is_process_state_unknown = 5;
-        ProcessState process_state = 6;
+        optional int32 uid = 1;
+        optional string uid_string = 2;
+        optional bool is_active = 3;
+        optional int32 num_wake_locks = 4;
+        optional bool is_process_state_unknown = 5;
+        optional ProcessState process_state = 6;
     }
 
     // Enum values gotten from PowerManagerInternal.java
@@ -120,123 +119,123 @@
         DOCK_STATE_HE_DESK = 4;
     }
 
-    ConstantsProto constants = 1;
+    optional ConstantsProto constants = 1;
     // A bitfield that indicates what parts of the power state have
     // changed and need to be recalculated.
-    int32 dirty = 2;
+    optional int32 dirty = 2;
     // Indicates whether the device is awake or asleep or somewhere in between.
-    Wakefulness wakefulness = 3;
-    bool is_wakefulness_changing = 4;
+    optional Wakefulness wakefulness = 3;
+    optional bool is_wakefulness_changing = 4;
     // True if the device is plugged into a power source.
-    bool is_powered = 5;
+    optional bool is_powered = 5;
     // The current plug type
-    PlugType plug_type = 6;
+    optional PlugType plug_type = 6;
     // The current battery level percentage.
-    int32 battery_level = 7;
+    optional int32 battery_level = 7;
     // The battery level percentage at the time the dream started.
-    int32 battery_level_when_dream_started = 8;
+    optional int32 battery_level_when_dream_started = 8;
     // The current dock state.
-    DockState dock_state = 9;
+    optional DockState dock_state = 9;
     // True if the device should stay on.
-    bool is_stay_on = 10;
+    optional bool is_stay_on = 10;
     // True if the proximity sensor reads a positive result.
-    bool is_proximity_positive = 11;
+    optional bool is_proximity_positive = 11;
     // True if boot completed occurred.  We keep the screen on until this happens.
-    bool is_boot_completed = 12;
+    optional bool is_boot_completed = 12;
     // True if systemReady() has been called.
-    bool is_system_ready = 13;
+    optional bool is_system_ready = 13;
     // True if auto-suspend mode is enabled.
-    bool is_hal_auto_suspend_mode_enabled = 14;
+    optional bool is_hal_auto_suspend_mode_enabled = 14;
     // True if interactive mode is enabled.
-    bool is_hal_auto_interactive_mode_enabled = 15;
+    optional bool is_hal_auto_interactive_mode_enabled = 15;
     // Summarizes the state of all active wakelocks.
-    ActiveWakeLocksProto active_wake_locks = 16;
+    optional ActiveWakeLocksProto active_wake_locks = 16;
     // Have we scheduled a message to check for long wake locks?  This is when
     // we will check. (In milliseconds timestamp)
-    int64 notify_long_scheduled_ms = 17;
+    optional int64 notify_long_scheduled_ms = 17;
     // Last time we checked for long wake locks. (In milliseconds timestamp)
-    int64 notify_long_dispatched_ms = 18;
+    optional int64 notify_long_dispatched_ms = 18;
     // The time we decided to do next long check. (In milliseconds timestamp)
-    int64 notify_long_next_check_ms = 19;
+    optional int64 notify_long_next_check_ms = 19;
     // Summarizes the effect of the user activity timer.
-    UserActivityProto user_activity = 20;
+    optional UserActivityProto user_activity = 20;
     // If true, instructs the display controller to wait for the proximity
     // sensor to go negative before turning the screen on.
-    bool is_request_wait_for_negative_proximity = 21;
+    optional bool is_request_wait_for_negative_proximity = 21;
     // True if MSG_SANDMAN has been scheduled.
-    bool is_sandman_scheduled = 22;
+    optional bool is_sandman_scheduled = 22;
     // True if the sandman has just been summoned for the first time since entering
     // the dreaming or dozing state.  Indicates whether a new dream should begin.
-    bool is_sandman_summoned = 23;
+    optional bool is_sandman_summoned = 23;
     // If true, the device is in low power mode.
-    bool is_low_power_mode_enabled = 24;
+    optional bool is_low_power_mode_enabled = 24;
     // True if the battery level is currently considered low.
-    bool is_battery_level_low = 25;
+    optional bool is_battery_level_low = 25;
     // True if we are currently in light device idle mode.
-    bool is_light_device_idle_mode = 26;
+    optional bool is_light_device_idle_mode = 26;
     // True if we are currently in device idle mode.
-    bool is_device_idle_mode = 27;
+    optional bool is_device_idle_mode = 27;
     // Set of app ids that we will always respect the wake locks for.
     repeated int32 device_idle_whitelist = 28;
     // Set of app ids that are temporarily allowed to acquire wakelocks due to
     // high-pri message
     repeated int32 device_idle_temp_whitelist = 29;
     // Timestamp of the last time the device was awoken.
-    int64 last_wake_time_ms = 30;
+    optional int64 last_wake_time_ms = 30;
     // Timestamp of the last time the device was put to sleep.
-    int64 last_sleep_time_ms = 31;
+    optional int64 last_sleep_time_ms = 31;
     // Timestamp of the last call to user activity.
-    int64 last_user_activity_time_ms = 32;
-    int64 last_user_activity_time_no_change_lights_ms = 33;
+    optional int64 last_user_activity_time_ms = 32;
+    optional int64 last_user_activity_time_no_change_lights_ms = 33;
     // Timestamp of last interactive power hint.
-    int64 last_interactive_power_hint_time_ms = 34;
+    optional int64 last_interactive_power_hint_time_ms = 34;
     // Timestamp of the last screen brightness boost.
-    int64 last_screen_brightness_boost_time_ms = 35;
+    optional int64 last_screen_brightness_boost_time_ms = 35;
     // True if screen brightness boost is in progress.
-    bool is_screen_brightness_boost_in_progress = 36;
+    optional bool is_screen_brightness_boost_in_progress = 36;
     // True if the display power state has been fully applied, which means the
     // display is actually on or actually off or whatever was requested.
-    bool is_display_ready = 37;
+    optional bool is_display_ready = 37;
     // True if the wake lock suspend blocker has been acquired.
-    bool is_holding_wake_lock_suspend_blocker = 38;
+    optional bool is_holding_wake_lock_suspend_blocker = 38;
     // The suspend blocker used to keep the CPU alive when the display is on, the
     // display is getting ready or there is user activity (in which case the
     // display must be on).
-    bool is_holding_display_suspend_blocker = 39;
+    optional bool is_holding_display_suspend_blocker = 39;
     // Settings and configuration
-    PowerServiceSettingsAndConfigurationDumpProto settings_and_configuration = 40;
+    optional PowerServiceSettingsAndConfigurationDumpProto settings_and_configuration = 40;
     // Sleep timeout in ms
-    sint32 sleep_timeout_ms = 41;
+    optional sint32 sleep_timeout_ms = 41;
     // Screen off timeout in ms
-    int32 screen_off_timeout_ms = 42;
+    optional int32 screen_off_timeout_ms = 42;
     // Screen dim duration in ms
-    int32 screen_dim_duration_ms = 43;
+    optional int32 screen_dim_duration_ms = 43;
     // We are currently in the middle of a batch change of uids.
-    bool are_uids_changing = 44;
+    optional bool are_uids_changing = 44;
     // Some uids have actually changed while mUidsChanging was true.
-    bool are_uids_changed = 45;
+    optional bool are_uids_changed = 45;
     // List of UIDs and their states
     repeated UidProto uids = 46;
-    android.os.LooperProto looper = 47;
+    optional android.os.LooperProto looper = 47;
     // List of all wake locks acquired by applications.
     repeated WakeLockProto wake_locks = 48;
     // List of all suspend blockers.
     repeated SuspendBlockerProto suspend_blockers = 49;
-    WirelessChargerDetectorProto wireless_charger_detector = 50;
+    optional WirelessChargerDetectorProto wireless_charger_detector = 50;
 }
 
 message SuspendBlockerProto {
-    string name = 1;
-    int32 reference_count = 2;
+    optional string name = 1;
+    optional int32 reference_count = 2;
 }
 
 message WakeLockProto {
     message WakeLockFlagsProto {
         // Turn the screen on when the wake lock is acquired.
-        bool is_acquire_causes_wakeup = 1;
+        optional bool is_acquire_causes_wakeup = 1;
         // When this wake lock is released, poke the user activity timer
         // so the screen stays on for a little longer.
-        bool is_on_after_release = 2;
+        optional bool is_on_after_release = 2;
     }
 
     // Enum values gotten from PowerManager.java
@@ -259,31 +258,31 @@
         DRAW_WAKE_LOCK = 128;
     }
 
-    LockLevel lock_level = 1;
-    string tag = 2;
-    WakeLockFlagsProto flags = 3;
-    bool is_disabled = 4;
+    optional LockLevel lock_level = 1;
+    optional string tag = 2;
+    optional WakeLockFlagsProto flags = 3;
+    optional bool is_disabled = 4;
     // Acquire time in ms
-    int64 acq_ms = 5;
-    bool is_notified_long = 6;
+    optional int64 acq_ms = 5;
+    optional bool is_notified_long = 6;
     // Owner UID
-    int32 uid = 7;
+    optional int32 uid = 7;
     // Owner PID
-    int32 pid = 8;
-    android.os.WorkSourceProto work_source = 9;
+    optional int32 pid = 8;
+    optional android.os.WorkSourceProto work_source = 9;
 }
 
 message PowerServiceSettingsAndConfigurationDumpProto {
     message StayOnWhilePluggedInProto {
-        bool is_stay_on_while_plugged_in_ac = 1;
-        bool is_stay_on_while_plugged_in_usb = 2;
-        bool is_stay_on_while_plugged_in_wireless = 3;
+        optional bool is_stay_on_while_plugged_in_ac = 1;
+        optional bool is_stay_on_while_plugged_in_usb = 2;
+        optional bool is_stay_on_while_plugged_in_wireless = 3;
     }
     message ScreenBrightnessSettingLimitsProto {
-        int32 setting_minimum = 1;
-        int32 setting_maximum = 2;
-        int32 setting_default = 3;
-        int32 setting_for_vr_default = 4;
+        optional int32 setting_minimum = 1;
+        optional int32 setting_maximum = 2;
+        optional int32 setting_default = 3;
+        optional int32 setting_for_vr_default = 4;
     }
 
     // Enum values gotten from Settings.java
@@ -303,106 +302,106 @@
 
 
     // True to decouple auto-suspend mode from the display state.
-    bool is_decouple_hal_auto_suspend_mode_from_display_config = 1;
+    optional bool is_decouple_hal_auto_suspend_mode_from_display_config = 1;
     // True to decouple interactive mode from the display state.
-    bool is_decouple_hal_interactive_mode_from_display_config = 2;
+    optional bool is_decouple_hal_interactive_mode_from_display_config = 2;
     // True if the device should wake up when plugged or unplugged.
-    bool is_wake_up_when_plugged_or_unplugged_config = 3;
+    optional bool is_wake_up_when_plugged_or_unplugged_config = 3;
     // True if the device should wake up when plugged or unplugged in theater mode.
-    bool is_wake_up_when_plugged_or_unplugged_in_theater_mode_config = 4;
+    optional bool is_wake_up_when_plugged_or_unplugged_in_theater_mode_config = 4;
     // True if theater mode is enabled
-    bool is_theater_mode_enabled = 5;
+    optional bool is_theater_mode_enabled = 5;
     // True if the device should suspend when the screen is off due to proximity.
-    bool is_suspend_when_screen_off_due_to_proximity_config = 6;
+    optional bool is_suspend_when_screen_off_due_to_proximity_config = 6;
     // True if dreams are supported on this device.
-    bool are_dreams_supported_config = 7;
+    optional bool are_dreams_supported_config = 7;
     // Default value for dreams enabled
-    bool are_dreams_enabled_by_default_config = 8;
+    optional bool are_dreams_enabled_by_default_config = 8;
     // Default value for dreams activate-on-sleep
-    bool are_dreams_activated_on_sleep_by_default_config = 9;
+    optional bool are_dreams_activated_on_sleep_by_default_config = 9;
     // Default value for dreams activate-on-dock
-    bool are_dreams_activated_on_dock_by_default_config = 10;
+    optional bool are_dreams_activated_on_dock_by_default_config = 10;
     // True if dreams can run while not plugged in.
-    bool are_dreams_enabled_on_battery_config = 11;
+    optional bool are_dreams_enabled_on_battery_config = 11;
     // Minimum battery level to allow dreaming when powered.
     // Use -1 to disable this safety feature.
-    sint32 dreams_battery_level_minimum_when_powered_config = 12;
+    optional sint32 dreams_battery_level_minimum_when_powered_config = 12;
     // Minimum battery level to allow dreaming when not powered.
     // Use -1 to disable this safety feature.
-    sint32 dreams_battery_level_minimum_when_not_powered_config = 13;
+    optional sint32 dreams_battery_level_minimum_when_not_powered_config = 13;
     // If the battery level drops by this percentage and the user activity
     // timeout has expired, then assume the device is receiving insufficient
     // current to charge effectively and terminate the dream.  Use -1 to disable
     // this safety feature.
-    sint32 dreams_battery_level_drain_cutoff_config = 14;
+    optional sint32 dreams_battery_level_drain_cutoff_config = 14;
     // True if dreams are enabled by the user.
-    bool are_dreams_enabled_setting = 15;
+    optional bool are_dreams_enabled_setting = 15;
     // True if dreams should be activated on sleep.
-    bool are_dreams_activate_on_sleep_setting = 16;
+    optional bool are_dreams_activate_on_sleep_setting = 16;
     // True if dreams should be activated on dock.
-    bool are_dreams_activate_on_dock_setting = 17;
+    optional bool are_dreams_activate_on_dock_setting = 17;
     // True if doze should not be started until after the screen off transition.
-    bool is_doze_after_screen_off_config = 18;
+    optional bool is_doze_after_screen_off_config = 18;
     // If true, the device is in low power mode.
-    bool is_low_power_mode_setting = 19;
+    optional bool is_low_power_mode_setting = 19;
     // Current state of whether the settings are allowing auto low power mode.
-    bool is_auto_low_power_mode_configured = 20;
+    optional bool is_auto_low_power_mode_configured = 20;
     // The user turned off low power mode below the trigger level
-    bool is_auto_low_power_mode_snoozing = 21;
+    optional bool is_auto_low_power_mode_snoozing = 21;
     // The minimum screen off timeout, in milliseconds.
-    int32 minimum_screen_off_timeout_config_ms = 22;
+    optional int32 minimum_screen_off_timeout_config_ms = 22;
     // The screen dim duration, in milliseconds.
-    int32 maximum_screen_dim_duration_config_ms = 23;
+    optional int32 maximum_screen_dim_duration_config_ms = 23;
     // The maximum screen dim time expressed as a ratio relative to the screen off timeout.
-    float maximum_screen_dim_ratio_config = 24;
+    optional float maximum_screen_dim_ratio_config = 24;
     // The screen off timeout setting value in milliseconds.
-    int32 screen_off_timeout_setting_ms = 25;
+    optional int32 screen_off_timeout_setting_ms = 25;
     // The sleep timeout setting value in milliseconds.
-    sint32 sleep_timeout_setting_ms = 26;
+    optional sint32 sleep_timeout_setting_ms = 26;
     // The maximum allowable screen off timeout according to the device administration policy.
-    int32 maximum_screen_off_timeout_from_device_admin_ms = 27;
-    bool is_maximum_screen_off_timeout_from_device_admin_enforced_locked = 28;
+    optional int32 maximum_screen_off_timeout_from_device_admin_ms = 27;
+    optional bool is_maximum_screen_off_timeout_from_device_admin_enforced_locked = 28;
     // The stay on while plugged in setting.
     // A set of battery conditions under which to make the screen stay on.
-    StayOnWhilePluggedInProto stay_on_while_plugged_in = 29;
+    optional StayOnWhilePluggedInProto stay_on_while_plugged_in = 29;
     // The screen brightness setting, from 0 to 255.
     // Use -1 if no value has been set.
-    sint32 screen_brightness_setting = 30;
+    optional sint32 screen_brightness_setting = 30;
     // The screen auto-brightness adjustment setting, from -1 to 1.
     // Use 0 if there is no adjustment.
-    float screen_auto_brightness_adjustment_setting = 31;
+    optional float screen_auto_brightness_adjustment_setting = 31;
     // The screen brightness mode.
-    ScreenBrightnessMode screen_brightness_mode_setting = 32;
+    optional ScreenBrightnessMode screen_brightness_mode_setting = 32;
     // The screen brightness setting override from the window manager
     // to allow the current foreground activity to override the brightness.
     // Use -1 to disable.
-    sint32 screen_brightness_override_from_window_manager = 33;
+    optional sint32 screen_brightness_override_from_window_manager = 33;
     // The user activity timeout override from the window manager
     // to allow the current foreground activity to override the user activity
     // timeout. Use -1 to disable.
-    sint64 user_activity_timeout_override_from_window_manager_ms = 34;
+    optional sint64 user_activity_timeout_override_from_window_manager_ms = 34;
     // The window manager has determined the user to be inactive via other means.
     // Set this to false to disable.
-    bool is_user_inactive_override_from_window_manager = 35;
+    optional bool is_user_inactive_override_from_window_manager = 35;
     // The screen brightness setting override from the settings application
     // to temporarily adjust the brightness until next updated,
     // Use -1 to disable.
-    sint32 temporary_screen_brightness_setting_override = 36;
+    optional sint32 temporary_screen_brightness_setting_override = 36;
     // The screen brightness adjustment setting override from the settings
     // application to temporarily adjust the auto-brightness adjustment factor
     // until next updated, in the range -1..1.
     // Use NaN to disable.
-    float temporary_screen_auto_brightness_adjustment_setting_override = 37;
+    optional float temporary_screen_auto_brightness_adjustment_setting_override = 37;
     // The screen state to use while dozing.
-    DisplayState doze_screen_state_override_from_dream_manager = 38;
+    optional DisplayState doze_screen_state_override_from_dream_manager = 38;
     // The screen brightness to use while dozing.
-    float dozed_screen_brightness_override_from_dream_manager = 39;
+    optional float dozed_screen_brightness_override_from_dream_manager = 39;
     // Screen brightness settings limits.
-    ScreenBrightnessSettingLimitsProto screen_brightness_setting_limits = 40;
+    optional ScreenBrightnessSettingLimitsProto screen_brightness_setting_limits = 40;
     // The screen brightness setting, from 0 to 255, to be used while in VR Mode.
-    int32 screen_brightness_for_vr_setting = 41;
+    optional int32 screen_brightness_for_vr_setting = 41;
     // True if double tap to wake is enabled
-    bool is_double_tap_wake_enabled = 42;
+    optional bool is_double_tap_wake_enabled = 42;
     // True if we are currently in VR Mode.
-    bool is_vr_mode_enabled = 43;
+    optional bool is_vr_mode_enabled = 43;
 }
diff --git a/core/proto/android/service/print.proto b/core/proto/android/service/print.proto
index f099872..c2be7f1 100644
--- a/core/proto/android/service/print.proto
+++ b/core/proto/android/service/print.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 package android.service.print;
 
 option java_multiple_files = true;
@@ -30,7 +29,7 @@
 
 message PrintUserStateProto {
     // Should be 0, 10, 11, 12, etc. where 0 is the owner.
-    int32 user_id = 1;
+    optional int32 user_id = 1;
 
     // The installed print services
     repeated InstalledPrintServiceProto installed_services = 2;
@@ -48,18 +47,18 @@
     repeated PrinterDiscoverySessionProto discovery_sessions = 6;
 
     // The print spooler state
-    PrintSpoolerStateProto print_spooler_state = 7;
+    optional PrintSpoolerStateProto print_spooler_state = 7;
 }
 
 message PrintSpoolerStateProto {
     // Is the print spooler destroyed?
-    bool is_destroyed = 1;
+    optional bool is_destroyed = 1;
 
     // Is the print spooler bound?
-    bool is_bound = 2;
+    optional bool is_bound = 2;
 
     // State internal to the print spooler
-    PrintSpoolerInternalStateProto internal_state = 3;
+    optional PrintSpoolerInternalStateProto internal_state = 3;
 }
 
 message PrintSpoolerInternalStateProto {
@@ -75,7 +74,7 @@
 
 message PrinterCapabilitiesProto {
     // Minimum margins of the printer
-    MarginsProto min_margins = 1;
+    optional MarginsProto min_margins = 1;
 
     // List of supported media sizes
     repeated MediaSizeProto media_sizes = 2;
@@ -92,10 +91,10 @@
 
 message PrinterInfoProto {
     // The id of the printer
-    PrinterIdProto id = 1;
+    optional PrinterIdProto id = 1;
 
     // The name of the printer
-    string name = 2;
+    optional string name = 2;
 
     enum Status {
         // unused
@@ -111,21 +110,21 @@
         STATUS_UNAVAILABLE = 3;
     }
     // The status of the printer
-    Status status = 3;
+    optional Status status = 3;
 
     // The description of the printer
-    string description = 4;
+    optional string description = 4;
 
     // The capabilities of the printer
-    PrinterCapabilitiesProto capabilities = 5;
+    optional PrinterCapabilitiesProto capabilities = 5;
 }
 
 message PrinterDiscoverySessionProto {
     // Is this session destroyed?
-    bool is_destroyed = 1;
+    optional bool is_destroyed = 1;
 
     // Is printer discovery in progress?
-    bool is_printer_discovery_in_progress = 2;
+    optional bool is_printer_discovery_in_progress = 2;
 
     // List of printer discovery observers
     repeated string printer_discovery_observers = 3;
@@ -142,44 +141,44 @@
 
 message InstalledPrintServiceProto {
     // Component name of the service
-    android.content.ComponentNameProto component_name = 1;
+    optional android.content.ComponentNameProto component_name = 1;
 
     // Settings activity for this service
-    string settings_activity = 2;
+    optional string settings_activity = 2;
 
     // Add printers activity for this service
-    string add_printers_activity = 3;
+    optional string add_printers_activity = 3;
 
     // Advances options activity for this service
-    string advanced_options_activity = 4;
+    optional string advanced_options_activity = 4;
 }
 
 message PrinterIdProto {
     // Component name of the service that reported the printer
-    android.content.ComponentNameProto service_name = 1;
+    optional android.content.ComponentNameProto service_name = 1;
 
     // Local id of the printer
-    string local_id = 2;
+    optional string local_id = 2;
 }
 
 message ActivePrintServiceProto {
     // Component name of the service
-    android.content.ComponentNameProto component_name = 1;
+    optional android.content.ComponentNameProto component_name = 1;
 
     // Is the active service destroyed
-    bool is_destroyed = 2;
+    optional bool is_destroyed = 2;
 
     // Is the active service bound
-    bool is_bound = 3;
+    optional bool is_bound = 3;
 
     // Has the active service a discovery session
-    bool has_discovery_session = 4;
+    optional bool has_discovery_session = 4;
 
     // Has the active service a active print jobs
-    bool has_active_print_jobs = 5;
+    optional bool has_active_print_jobs = 5;
 
     // Is the active service discovering printers
-    bool is_discovering_printers = 6;
+    optional bool is_discovering_printers = 6;
 
     // The tracked printers of this active service
     repeated PrinterIdProto tracked_printers = 7;
@@ -187,58 +186,58 @@
 
 message MediaSizeProto {
     // Id of this media size
-    string id = 1;
+    optional string id = 1;
 
     // Label of this media size
-    string label = 2;
+    optional string label = 2;
 
     // Height of the media
-    int32 height_mils = 3;
+    optional int32 height_mils = 3;
 
     // Width of the media
-    int32 width_mils = 4;
+    optional int32 width_mils = 4;
 }
 
 message ResolutionProto {
     // Id of this resolution
-    string id = 1;
+    optional string id = 1;
 
     // Label for this resoltion
-    string label = 2;
+    optional string label = 2;
 
     // Resolution in horizontal orientation
-    int32 horizontal_dpi = 3;
+    optional int32 horizontal_dpi = 3;
 
     // Resolution in vertical orientation
-    int32 vertical_dpi = 4;
+    optional int32 vertical_dpi = 4;
 }
 
 message MarginsProto {
     // Space at the top
-    int32 top_mils = 1;
+    optional int32 top_mils = 1;
 
     // Space at the left
-    int32 left_mils = 2;
+    optional int32 left_mils = 2;
 
     // Space at the right
-    int32 right_mils = 3;
+    optional int32 right_mils = 3;
 
     // Space at the bottom
-    int32 bottom_mils = 4;
+    optional int32 bottom_mils = 4;
 }
 
 message PrintAttributesProto {
     // Media to use
-    ResolutionProto media_size = 1;
+    optional ResolutionProto media_size = 1;
 
     // Is the media in portrait mode?
-    bool is_portrait = 2;
+    optional bool is_portrait = 2;
 
     // Resolution to use
-    ResolutionProto resolution = 3;
+    optional ResolutionProto resolution = 3;
 
     // Margins around the document
-    MarginsProto min_margins = 4;
+    optional MarginsProto min_margins = 4;
 
     enum ColorMode {
         // unused
@@ -251,7 +250,7 @@
         COLOR_MODE_COLOR = 2;
     }
     // Color mode to use
-    ColorMode color_mode = 5;
+    optional ColorMode color_mode = 5;
 
     enum DuplexMode {
         // unused
@@ -267,37 +266,37 @@
         DUPLEX_MODE_SHORT_EDGE = 4;
     }
     // Duplex mode to use
-    DuplexMode duplex_mode = 6;
+    optional DuplexMode duplex_mode = 6;
 }
 
 message PrintDocumentInfoProto {
     // Name of the document to print
-    string name = 1;
+    optional string name = 1;
 
     // Number of pages in the doc
-    int32 page_count = 2;
+    optional int32 page_count = 2;
 
     // Type of content (see PrintDocumentInfo.ContentType)
-    int32 content_type = 3;
+    optional int32 content_type = 3;
 
     // The size of the the document
-    int64 data_size = 4;
+    optional int64 data_size = 4;
 }
 
 message PageRangeProto {
     // Start of the range
-    int32 start = 1;
+    optional int32 start = 1;
 
     // End of the range (included)
-    int32 end = 2;
+    optional int32 end = 2;
 }
 
 message PrintJobInfoProto {
     // Label of the job
-    string label = 1;
+    optional string label = 1;
 
     // Id of the job
-    string print_job_id = 2;
+    optional string print_job_id = 2;
 
     enum State {
         // Unknown state
@@ -326,43 +325,43 @@
     }
 
     // State of the job
-    State state = 3;
+    optional State state = 3;
 
     // Printer handling the job
-    PrinterIdProto printer = 4;
+    optional PrinterIdProto printer = 4;
 
     // Tag assigned to the job
-    string tag = 5;
+    optional string tag = 5;
 
     // Time the job was created
-    int64 creation_time = 6;
+    optional int64 creation_time = 6;
 
     // Attributes of the job
-    PrintAttributesProto attributes = 7;
+    optional PrintAttributesProto attributes = 7;
 
     // Document info of the job
-    PrintDocumentInfoProto document_info = 8;
+    optional PrintDocumentInfoProto document_info = 8;
 
     // If the job current getting canceled
-    bool is_canceling = 9;
+    optional bool is_canceling = 9;
 
     // The selected ranges of the job
     repeated PageRangeProto pages = 10;
 
     // Does the job have any advanced options
-    bool has_advanced_options = 11;
+    optional bool has_advanced_options = 11;
 
     // Progress of the job
-    float progress = 12;
+    optional float progress = 12;
 
     // The current service set state
-    string status = 13;
+    optional string status = 13;
 }
 
 message CachedPrintJobProto {
     // The id of the app the job belongs to
-    int32 app_id = 1;
+    optional int32 app_id = 1;
 
     // The print job
-    PrintJobInfoProto print_job = 2;
+    optional PrintJobInfoProto print_job = 2;
 }
\ No newline at end of file
diff --git a/core/proto/android/service/procstats.proto b/core/proto/android/service/procstats.proto
index 322b212..b2e0373 100644
--- a/core/proto/android/service/procstats.proto
+++ b/core/proto/android/service/procstats.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 option java_multiple_files = true;
 option java_outer_classname = "ProcessStatsServiceProto";
 
@@ -30,11 +29,11 @@
  */
 message ProcessStatsServiceDumpProto {
 
-    ProcessStatsSectionProto procstats_now = 1;
+    optional ProcessStatsSectionProto procstats_now = 1;
 
-    ProcessStatsSectionProto procstats_over_3hrs = 2;
+    optional ProcessStatsSectionProto procstats_over_3hrs = 2;
 
-    ProcessStatsSectionProto procstats_over_24hrs = 3;
+    optional ProcessStatsSectionProto procstats_over_24hrs = 3;
 }
 
 /**
@@ -46,22 +45,22 @@
 message ProcessStatsSectionProto {
 
     // Elapsed realtime at start of report.
-    int64 start_realtime_ms = 1;
+    optional int64 start_realtime_ms = 1;
 
     // Elapsed realtime at end of report.
-    int64 end_realtime_ms = 2;
+    optional int64 end_realtime_ms = 2;
 
     // CPU uptime at start of report.
-    int64 start_uptime_ms = 3;
+    optional int64 start_uptime_ms = 3;
 
     // CPU uptime at end of report.
-    int64 end_uptime_ms = 4;
+    optional int64 end_uptime_ms = 4;
 
     // System runtime library. e.g. "libdvm.so", "libart.so".
-    string runtime = 5;
+    optional string runtime = 5;
 
     // whether kernel reports swapped pss.
-    bool has_swapped_pss = 6;
+    optional bool has_swapped_pss = 6;
 
     // Data completeness. e.g. "complete", "partial", shutdown", or "sysprops".
     enum Status {
@@ -81,23 +80,23 @@
 message ProcessStatsProto {
 
     // Name of process.
-    string process = 1;
+    optional string process = 1;
 
     // Uid of the process.
-    int32 uid = 2;
+    optional int32 uid = 2;
 
     // Information about how often kills occurred
     message Kill {
       // Count of excessive CPU kills
-      int32 cpu = 1;
+      optional int32 cpu = 1;
 
       // Count of kills when cached
-      int32 cached = 2;
+      optional int32 cached = 2;
 
       // PSS stats during cached kill
-      android.util.AggStats cached_pss = 3;
+      optional android.util.AggStats cached_pss = 3;
     }
-    Kill kill = 3;
+    optional Kill kill = 3;
 
     message State {
         enum ScreenState {
@@ -105,7 +104,7 @@
             OFF = 1;
             ON = 2;
         }
-        ScreenState screen_state = 1;
+        optional ScreenState screen_state = 1;
 
         enum MemoryState {
             MEMORY_UNKNOWN = 0;
@@ -114,7 +113,7 @@
             LOW = 3;        // low memory.
             CRITICAL = 4;   // critical memory.
         }
-        MemoryState memory_state = 2;
+        optional MemoryState memory_state = 2;
 
         enum ProcessState {
             PROCESS_UNKNOWN = 0;
@@ -147,19 +146,19 @@
             // Cached process that is empty.
             CACHED_EMPTY = 14;
         }
-        ProcessState process_state = 3;
+        optional ProcessState process_state = 3;
 
         // Millisecond duration spent in this state
-        int64 duration_ms = 4;
+        optional int64 duration_ms = 4;
 
         // # of samples taken
-        int32 sample_size = 5;
+        optional int32 sample_size = 5;
 
         // PSS is memory reserved for this process
-        android.util.AggStats pss = 6;
+        optional android.util.AggStats pss = 6;
 
         // USS is memory shared between processes, divided evenly for accounting
-        android.util.AggStats uss = 7;
+        optional android.util.AggStats uss = 7;
     }
     repeated State states = 5;
 }
diff --git a/core/proto/android/service/wirelesschargerdetector.proto b/core/proto/android/service/wirelesschargerdetector.proto
index 7ba7c17..bd697c8 100644
--- a/core/proto/android/service/wirelesschargerdetector.proto
+++ b/core/proto/android/service/wirelesschargerdetector.proto
@@ -14,37 +14,36 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 package android.service.power;
 
 option java_multiple_files = true;
 
 message WirelessChargerDetectorProto {
     message VectorProto {
-        float x = 1;
-        float y = 2;
-        float z = 3;
+        optional float x = 1;
+        optional float y = 2;
+        optional float z = 3;
     }
 
     // Previously observed wireless power state.
-    bool is_powered_wirelessly = 1;
+    optional bool is_powered_wirelessly = 1;
     // True if the device is thought to be at rest on a wireless charger.
-    bool is_at_rest = 2;
+    optional bool is_at_rest = 2;
     // The gravity vector most recently observed while at rest.
-    VectorProto rest = 3;
+    optional VectorProto rest = 3;
     // True if detection is in progress.
-    bool is_detection_in_progress = 4;
+    optional bool is_detection_in_progress = 4;
     // The time when detection was last performed.
-    int64 detection_start_time_ms = 5;
+    optional int64 detection_start_time_ms = 5;
     // True if the rest position should be updated if at rest.
-    bool is_must_update_rest_position = 6;
+    optional bool is_must_update_rest_position = 6;
     // The total number of samples collected.
-    int32 total_samples = 7;
+    optional int32 total_samples = 7;
     // The number of samples collected that showed evidence of not being at rest.
-    int32 moving_samples = 8;
+    optional int32 moving_samples = 8;
     // The value of the first sample that was collected.
-    VectorProto first_sample = 9;
+    optional VectorProto first_sample = 9;
     // The value of the last sample that was collected.
-    VectorProto last_sample = 10;
+    optional VectorProto last_sample = 10;
 }
\ No newline at end of file
diff --git a/core/proto/android/telephony/signalstrength.proto b/core/proto/android/telephony/signalstrength.proto
index ff230cb..366f1d1 100644
--- a/core/proto/android/telephony/signalstrength.proto
+++ b/core/proto/android/telephony/signalstrength.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 option java_package = "android.telephony";
 option java_multiple_files = true;
 
diff --git a/core/proto/android/util/common.proto b/core/proto/android/util/common.proto
index 6dd4c02..429c3cad 100644
--- a/core/proto/android/util/common.proto
+++ b/core/proto/android/util/common.proto
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 package android.util;
 
 option java_multiple_files = true;
@@ -25,9 +24,9 @@
  */
 message AggStats {
 
-    int64 min = 1;
+    optional int64 min = 1;
 
-    int64 average = 2;
+    optional int64 average = 2;
 
-    int64 max = 3;
+    optional int64 max = 3;
 }
diff --git a/core/proto/android/view/displayinfo.proto b/core/proto/android/view/displayinfo.proto
index 8583868..9ca4046 100644
--- a/core/proto/android/view/displayinfo.proto
+++ b/core/proto/android/view/displayinfo.proto
@@ -14,16 +14,15 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 package android.view;
 
 option java_multiple_files = true;
 
 /* represents DisplayInfo */
 message DisplayInfoProto {
-  int32 logical_width = 1;
-  int32 logical_height = 2;
-  int32 app_width = 3;
-  int32 app_height = 4;
+  optional int32 logical_width = 1;
+  optional int32 logical_height = 2;
+  optional int32 app_width = 3;
+  optional int32 app_height = 4;
 }
diff --git a/core/proto/android/view/windowlayoutparams.proto b/core/proto/android/view/windowlayoutparams.proto
index 5bb84dc..7821212 100644
--- a/core/proto/android/view/windowlayoutparams.proto
+++ b/core/proto/android/view/windowlayoutparams.proto
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
-syntax = "proto3";
-
+syntax = "proto2";
 package android.view;
 
 option java_multiple_files = true;
 
 /* represents WindowManager.LayoutParams */
 message WindowLayoutParamsProto {
-  int32 type = 1;
+  optional int32 type = 1;
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3d5ae3d..105bb7e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3112,7 +3112,7 @@
     <!-- Allows an application to bind app's slices and get their
          content. This content will be surfaced to the
          user and not to leave the device.
-         <p>Not for use by third-party applications. @hide -->
+         <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.BIND_SLICE"
         android:protectionLevel="signature|privileged|development" />
 
@@ -3587,6 +3587,10 @@
     <permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE"
         android:protectionLevel="signature|development|instant|appop" />
 
+    <!-- @hide Allows system components to access all app shortcuts. -->
+    <permission android:name="android.permission.ACCESS_SHORTCUTS"
+        android:protectionLevel="signature" />
+
     <application android:process="system"
                  android:persistent="true"
                  android:hasCode="false"
diff --git a/core/res/res/layout/floating_popup_menu_button.xml b/core/res/res/layout/floating_popup_menu_button.xml
index 6cbe8c8..c419e46 100644
--- a/core/res/res/layout/floating_popup_menu_button.xml
+++ b/core/res/res/layout/floating_popup_menu_button.xml
@@ -53,7 +53,6 @@
         android:ellipsize="end"
         android:fontFamily="sans-serif-medium"
         android:textSize="@dimen/floating_toolbar_text_size"
-        android:textAllCaps="true"
         android:textColor="?attr/floatingToolbarForegroundColor"
         android:background="@null"
         android:focusable="false"
diff --git a/core/res/res/layout/slice_grid.xml b/core/res/res/layout/slice_grid.xml
index 70df76b..15ded7b 100644
--- a/core/res/res/layout/slice_grid.xml
+++ b/core/res/res/layout/slice_grid.xml
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<android.slice.views.GridView
+<android.app.slice.views.GridView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
@@ -21,4 +21,4 @@
     android:gravity="center_vertical"
     android:background="?android:attr/activatedBackgroundIndicator"
     android:clipToPadding="false">
-</android.slice.views.GridView>
+</android.app.slice.views.GridView>
diff --git a/core/res/res/layout/slice_message.xml b/core/res/res/layout/slice_message.xml
index a3279b6..96f8078 100644
--- a/core/res/res/layout/slice_message.xml
+++ b/core/res/res/layout/slice_message.xml
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<android.slice.views.MessageView
+<android.app.slice.views.MessageView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
@@ -48,4 +48,4 @@
         android:layout_alignStart="@android:id/title"
         android:textAppearance="?android:attr/textAppearanceListItem"
         android:maxLines="10" />
-</android.slice.views.MessageView>
+</android.app.slice.views.MessageView>
diff --git a/core/res/res/layout/slice_message_local.xml b/core/res/res/layout/slice_message_local.xml
index d4180f3..5c767ba 100644
--- a/core/res/res/layout/slice_message_local.xml
+++ b/core/res/res/layout/slice_message_local.xml
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<android.slice.views.MessageView
+<android.app.slice.views.MessageView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
@@ -35,4 +35,4 @@
         android:background="#ffeeeeee"
         android:maxLines="10" />
 
-</android.slice.views.MessageView>
+</android.app.slice.views.MessageView>
diff --git a/core/res/res/layout/slice_remote_input.xml b/core/res/res/layout/slice_remote_input.xml
index dc570c4..90d0c82 100644
--- a/core/res/res/layout/slice_remote_input.xml
+++ b/core/res/res/layout/slice_remote_input.xml
@@ -15,7 +15,7 @@
      limitations under the License.
 -->
 <!-- LinearLayout -->
-<android.slice.views.RemoteInputView
+<android.app.slice.views.RemoteInputView
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/remote_input"
         android:background="@drawable/slice_remote_input_bg"
@@ -73,4 +73,4 @@
 
     </FrameLayout>
 
-</android.slice.views.RemoteInputView>
\ No newline at end of file
+</android.app.slice.views.RemoteInputView>
\ No newline at end of file
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 8bc50b5..5f65553 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Opletberigte"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Kleinhandeldemonstrasie"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-verbinding"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Program loop tans"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Programme wat batterykrag gebruik"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> gebruik tans batterykrag"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> programme gebruik tans batterykrag"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Invoermetode"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Teksaksies"</string>
     <string name="email" msgid="4560673117055050403">"E-pos"</string>
-    <string name="dial" msgid="4204975095406423102">"Foon"</string>
-    <string name="map" msgid="6068210738233985748">"Kaarte"</string>
-    <string name="browse" msgid="6993590095938149861">"Blaaier"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Kontak"</string>
+    <string name="dial" msgid="1253998302767701559">"Bel"</string>
+    <string name="map" msgid="6521159124535543457">"Spoor op"</string>
+    <string name="browse" msgid="1245903488306147205">"Maak oop"</string>
+    <string name="sms" msgid="4560537514610063430">"SMS"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Voeg by"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Bergingspasie word min"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Sommige stelselfunksies werk moontlik nie"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nie genoeg berging vir die stelsel nie. Maak seker jy het 250 MB spasie beskikbaar en herbegin."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Kanselleer"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Kanselleer"</string>
-    <string name="close" msgid="2318214661230355730">"MAAK TOE"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Aandag"</string>
     <string name="loading" msgid="7933681260296021180">"Laai tans..."</string>
     <string name="capital_on" msgid="1544682755514494298">"AAN"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skaal"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Wys altyd"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Heraktiveer hierdie in Stelselinstellings &gt; Programme &gt; Afgelaai."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Program reageer nie"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> gebruik dalk te veel berging."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> steun nie die huidige skermgrootte-instelling nie en sal dalk onverwags reageer."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Wys altyd"</string>
     <string name="smv_application" msgid="3307209192155442829">"Die program <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) het sy selfopgelegde StrictMode-beleid oortree."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Noodboodskappetoets"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Antwoord"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM word nie toegelaat nie"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM is nie opgestel nie"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM word nie toegelaat nie"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Foon word nie toegelaat nie"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Opspringvenster"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Opspringvenster"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Hierdie kortpad vereis die jongste program"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Kon nie die kortpad teruglaai nie omdat die program nie rugsteun en teruglaai steun nie"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Kon nie teruglaai nie omdat programondertekening nie ooreenstem nie"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Kon nie kortpad teruglaai nie"</string>
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 77a0ed7..c4be6f4 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"ማንቂያዎች"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"የችርቻሮ ማሳያ"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"የዩኤስቢ ግንኙነት"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"APP እየሠራ ነው"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"ባትሪ በመፍጀት ላይ ያሉ መተግበሪያዎች"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> ባትሪ እየተጠቀመ ነው"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> መተግበሪያዎች ባትሪ እየተጠቀሙ ነው"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"ግቤት ስልት"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"የፅሁፍ እርምጃዎች"</string>
     <string name="email" msgid="4560673117055050403">"ኢሜይል"</string>
-    <string name="dial" msgid="4204975095406423102">"ስልክ"</string>
-    <string name="map" msgid="6068210738233985748">"ካርታዎች"</string>
-    <string name="browse" msgid="6993590095938149861">"አሳሽ"</string>
-    <string name="sms" msgid="8250353543787396737">"ኤስኤምኤስ"</string>
-    <string name="add_contact" msgid="7990645816259405444">"ዕውቂያ"</string>
+    <string name="dial" msgid="1253998302767701559">"ጥሪ"</string>
+    <string name="map" msgid="6521159124535543457">"ቦታውን አግኝ"</string>
+    <string name="browse" msgid="1245903488306147205">"ክፈት"</string>
+    <string name="sms" msgid="4560537514610063430">"መልዕክት"</string>
+    <string name="add_contact" msgid="7867066569670597203">"አክል"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"የማከማቻ ቦታ እያለቀ ነው"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"አንዳንድ የስርዓት ተግባራት ላይሰሩ ይችላሉ"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ለስርዓቱ የሚሆን በቂ ቦታ የለም። 250 ሜባ ነጻ ቦታ እንዳለዎት ያረጋግጡና ዳግም ያስጀምሩ።"</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"ይቅር"</string>
     <string name="yes" msgid="5362982303337969312">"እሺ"</string>
     <string name="no" msgid="5141531044935541497">"ይቅር"</string>
-    <string name="close" msgid="2318214661230355730">"ዝጋ"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"ትኩረት"</string>
     <string name="loading" msgid="7933681260296021180">"በመጫን ላይ…"</string>
     <string name="capital_on" msgid="1544682755514494298">"በ"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"የልኬት ለውጥ"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"ሁልጊዜ አሳይ"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"በስርዓት ቅንብሮች  ውስጥ ይሄንን ዳግም አንቃ&gt; Apps &amp;gt፤ወርዷል፡፡"</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"መተግበሪያው ምላሽ እየሰጠ አይደለም"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> በጣም ብዙ ማህደረ ትውስታ እየተጠቀመ ሊሆን ይችላል።"</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> አሁን ያለውን የማሳያ መጠን ቅንብር አይደግፍም እና ያልተጠብቀ ባሕሪ ሊያሳይ ይችላል።"</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"ሁልጊዜ አሳይ"</string>
     <string name="smv_application" msgid="3307209192155442829">"መተግበሪያው <xliff:g id="APPLICATION">%1$s</xliff:g>( ሂደት<xliff:g id="PROCESS">%2$s</xliff:g>) በራስ ተነሳሺ StrictMode ደንብን ይተላለፋል።"</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"የአስቸኳይ አደጋ መልእክቶች ሙከራ"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"ምላሽ ስጥ"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"ሲም አይፈቀድም"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"ሲም አልቀረበም"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"ሲም አይፈቀድም"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"ስልክ አይፈቀድም"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"ብቅ-ባይ መስኮት"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"ብቅ-ባይ መስኮት"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"ይህ አቋራጭ በጣም የቅርብ ጊዜውን መተግበሪያ ይፈልጋል"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"መተግበሪያ ምትኬን እና ወደ ነበረበት መመለስን ሳለማይደግፍ አቋራጭ ወደ ነበረበት ሊመለስ አልቻለም"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"በመተግበሪያ ፊርማ አለመዛመድ አቋራጭን ወደነበረበት መመለስ አልተቻለም"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"አቋራጭን ወደ ነበረበት መመለስ አልተቻለም"</string>
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 7b516c5..a365c15 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -261,6 +261,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"التنبيهات"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"عرض توضيحي لبائع التجزئة"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"‏اتصال USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"التطبيق قيد التشغيل"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"التطبيقات التي تستهلك البطارية"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"يستخدم تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> البطارية"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"تستخدم <xliff:g id="NUMBER">%1$d</xliff:g> من التطبيقات البطارية"</string>
@@ -1058,11 +1059,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"طريقة الإرسال"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"إجراءات النص"</string>
     <string name="email" msgid="4560673117055050403">"بريد إلكتروني"</string>
-    <string name="dial" msgid="4204975095406423102">"الهاتف"</string>
-    <string name="map" msgid="6068210738233985748">"الخرائط"</string>
-    <string name="browse" msgid="6993590095938149861">"المتصفح"</string>
-    <string name="sms" msgid="8250353543787396737">"‏رسالة SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"جهة اتصال"</string>
+    <string name="dial" msgid="1253998302767701559">"اتصال"</string>
+    <string name="map" msgid="6521159124535543457">"تحديد الموقع"</string>
+    <string name="browse" msgid="1245903488306147205">"فتح"</string>
+    <string name="sms" msgid="4560537514610063430">"رسالة"</string>
+    <string name="add_contact" msgid="7867066569670597203">"إضافة"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"مساحة التخزين منخفضة"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"قد لا تعمل بعض وظائف النظام"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ليست هناك سعة تخزينية كافية للنظام. تأكد من أنه لديك مساحة خالية تبلغ ٢٥٠ ميغابايت وأعد التشغيل."</string>
@@ -1072,7 +1073,6 @@
     <string name="cancel" msgid="6442560571259935130">"إلغاء"</string>
     <string name="yes" msgid="5362982303337969312">"حسنًا"</string>
     <string name="no" msgid="5141531044935541497">"إلغاء"</string>
-    <string name="close" msgid="2318214661230355730">"إغلاق"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"تنبيه"</string>
     <string name="loading" msgid="7933681260296021180">"جارٍ التحميل…"</string>
     <string name="capital_on" msgid="1544682755514494298">"تشغيل"</string>
@@ -1129,8 +1129,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"تدرج"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"الإظهار دائمًا"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"‏يمكنك إعادة تمكين هذا في إعدادات النظام &gt; التطبيقات &gt; ما تم تنزيله."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"التطبيق لا يستجيب"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"ربما يشغل <xliff:g id="APP_NAME">%1$s</xliff:g> مساحة كبيرة جدًا من الذاكرة."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> غير متوافق مع الإعداد الحالي لحجم شاشة العرض وربما يعمل بطريقة غير متوقعة."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"العرض دائمًا"</string>
     <string name="smv_application" msgid="3307209192155442829">"‏انتهك التطبيق <xliff:g id="APPLICATION">%1$s</xliff:g> (العملية <xliff:g id="PROCESS">%2$s</xliff:g>) سياسة StrictMode المفروضة ذاتيًا."</string>
@@ -1924,11 +1922,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"اختبار رسائل الطوارئ"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"الرد"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"‏غير مسموح باستخدام SIM"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"‏لم يتم تقديم SIM"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"‏غير مسموح باستخدام SIM"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"غير مسموح باستخدام الهاتف"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"نافذة منبثقة"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"نافذة منبثقة"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"يتطلب هذا الاختصار أحدث تطبيق"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"تعذّرت استعادة الاختصار لأن التطبيق لا يوفِّر إمكانية النسخ الاحتياطي والاستعادة"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"تعذّرت استعادة الاختصار بسبب عدم تطابق توقيع التطبيق"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"تعذّرت استعادة الاختصار"</string>
 </resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 8ff588b..40b5473 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Siqnallar"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Pərakəndə demo"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB əlaqə"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Tətbiq işləyir"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Batareyadan istifadə edən tətbiqlər"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> batareyadan istifadə edir"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> tətbiq batareyadan istifadə edir"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Daxiletmə metodu"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Mətn əməliyyatları"</string>
     <string name="email" msgid="4560673117055050403">"E-poçt"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefon"</string>
-    <string name="map" msgid="6068210738233985748">"Xəritə"</string>
-    <string name="browse" msgid="6993590095938149861">"Brauzer"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Kontakt"</string>
+    <string name="dial" msgid="1253998302767701559">"Zəng"</string>
+    <string name="map" msgid="6521159124535543457">"Tapmaq"</string>
+    <string name="browse" msgid="1245903488306147205">"Açın"</string>
+    <string name="sms" msgid="4560537514610063430">"Mesaj"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Əlavə edin"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Yaddaş yeri bitir"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Bəzi sistem funksiyaları işləməyə bilər"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sistem üçün yetərincə yaddaş ehtiyatı yoxdur. 250 MB yaddaş ehtiyatının olmasına əmin olun və yenidən başladın."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Ləğv et"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Ləğv et"</string>
-    <string name="close" msgid="2318214661230355730">"BAĞLAYIN"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Diqqət"</string>
     <string name="loading" msgid="7933681260296021180">"Yüklənir…"</string>
     <string name="capital_on" msgid="1544682755514494298">"AÇIQ"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Miqyas"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Həmişə göstər"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Bunları Sistem ayarlarında yenidən aktivləşdir Yüklənmiş &gt; Tətbiqlər &gt;."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Tətbiq cavab vermir"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> daha çox yaddaş istifadə edə bilər."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> cari Ekran ölçüsü ayarını dəstəkləmir və gözlənilməz şəkildə davrana bilər."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Həmişə göstərin"</string>
     <string name="smv_application" msgid="3307209192155442829">"Tətbiq <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) StrictMode siyasətini pozdu."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Təcili mesaj testi"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Cavablayın"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM-ə icazə verilmir"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM təmin edilməyib"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM-ə icazə verilmir"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Telefona icazə verilmir"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Popap Pəncərəsi"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Popap Pəncərəsi"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Bu qısayol ən son tətbiqi tələb edir"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Qısayolu bərpa etmək mümkün olmadı, çünki tətbiq yedəkləməni və bərpa etməyi dəstəkləmir"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Tətbiqin imza uyğunsuzluğu səbəbilə qısayolu bərpa etmək mümkün olmadı"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Qısayolu bərpa etmək mümkün olmadı"</string>
 </resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index b1e1117..0b82ffb 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -252,6 +252,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Obaveštenja"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Režim demonstracije za maloprodajne objekte"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB veza"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Aplikacija je pokrenuta"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Aplikacije koje troše bateriju"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> koristi bateriju"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"Aplikacije (<xliff:g id="NUMBER">%1$d</xliff:g>) koriste bateriju"</string>
@@ -998,11 +999,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Metod unosa"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Radnje u vezi sa tekstom"</string>
     <string name="email" msgid="4560673117055050403">"Pošalji imejl"</string>
-    <string name="dial" msgid="4204975095406423102">"Pozovi"</string>
-    <string name="map" msgid="6068210738233985748">"Mape"</string>
-    <string name="browse" msgid="6993590095938149861">"Pregledač"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Kontakt"</string>
+    <string name="dial" msgid="1253998302767701559">"Pozovi"</string>
+    <string name="map" msgid="6521159124535543457">"Pronađi"</string>
+    <string name="browse" msgid="1245903488306147205">"Otvori"</string>
+    <string name="sms" msgid="4560537514610063430">"Pošalji SMS"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Dodaj"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Memorijski prostor je na izmaku"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Neke sistemske funkcije možda ne funkcionišu"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nema dovoljno memorijskog prostora za sistem. Uverite se da imate 250 MB slobodnog prostora i ponovo pokrenite."</string>
@@ -1012,7 +1013,6 @@
     <string name="cancel" msgid="6442560571259935130">"Otkaži"</string>
     <string name="yes" msgid="5362982303337969312">"Potvrdi"</string>
     <string name="no" msgid="5141531044935541497">"Otkaži"</string>
-    <string name="close" msgid="2318214661230355730">"ZATVORI"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Pažnja"</string>
     <string name="loading" msgid="7933681260296021180">"Učitava se…"</string>
     <string name="capital_on" msgid="1544682755514494298">"DA"</string>
@@ -1069,8 +1069,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Razmera"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Uvek prikazuj"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Ponovo omogućite u meniju Sistemska podešavanja &gt; Aplikacije &gt; Preuzeto."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikacija ne reaguje"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> možda koristi previše memorije."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava trenutno podešavanje veličine prikaza i može da se ponaša neočekivano."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Uvek prikazuj"</string>
     <string name="smv_application" msgid="3307209192155442829">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) je prekršila samonametnute StrictMode smernice."</string>
@@ -1819,11 +1817,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Testiranje poruka u hitnim slučajevima"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Odgovori"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM kartica nije dozvoljena"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM kartica nije podešena"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM kartica nije dozvoljena"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Telefon nije dozvoljen"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Iskačući prozor"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Iskačući prozor"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"i još <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Ova prečica zahteva najnoviju aplikaciju"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Vraćanje prečice nije uspelo jer aplikacija ne podržava pravljenje rezervne kopije i vraćanje"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Vraćanje prečice nije uspelo jer se potpisi aplikacija ne podudaraju"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Vraćanje prečice nije uspelo"</string>
 </resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 42937df..039b6eb 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -255,6 +255,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Абвесткi"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Дэманстрацыйны рэжым для пунктаў продажу"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Падключэнне USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Праграма працуе"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Праграмы, якія выкарыстоўваюць акумулятар"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> выкарыстоўвае акумулятар"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"Наступная колькасць праграм выкарыстоўваюць акумулятар: <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
@@ -1018,11 +1019,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Метад уводу"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Дзеянні з тэкстам"</string>
     <string name="email" msgid="4560673117055050403">"Электронная пошта"</string>
-    <string name="dial" msgid="4204975095406423102">"Тэлефон"</string>
-    <string name="map" msgid="6068210738233985748">"Карты"</string>
-    <string name="browse" msgid="6993590095938149861">"Браўзер"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Кантакт"</string>
+    <string name="dial" msgid="1253998302767701559">"Выклікаць"</string>
+    <string name="map" msgid="6521159124535543457">"Знайсці"</string>
+    <string name="browse" msgid="1245903488306147205">"Адкрыць"</string>
+    <string name="sms" msgid="4560537514610063430">"Паведамленне"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Дадаць"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Месца для захавання на зыходзе"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Некаторыя сістэмныя функцыі могуць не працаваць"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Не хапае сховішча для сістэмы. Пераканайцеся, што ў вас ёсць 250 МБ свабоднага месца, і перазапусціце."</string>
@@ -1032,7 +1033,6 @@
     <string name="cancel" msgid="6442560571259935130">"Скасаваць"</string>
     <string name="yes" msgid="5362982303337969312">"ОК"</string>
     <string name="no" msgid="5141531044935541497">"Скасаваць"</string>
-    <string name="close" msgid="2318214661230355730">"ЗАКРЫЦЬ"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Увага"</string>
     <string name="loading" msgid="7933681260296021180">"Загрузка..."</string>
     <string name="capital_on" msgid="1544682755514494298">"Уключыць"</string>
@@ -1089,8 +1089,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Шкала"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Заўсёды паказваць"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Зноў уключыце гэта ў раздзеле \"Сістэмныя налады &gt; Прыкладанні &gt; Спампаваныя\"."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Праграма не адказвае"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> можа выкарыстоўваць занадта шмат памяці."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> не падтрымлівае бягучую наладу Памеру дысплэя і можа паводзіць сябе непрадказальным чынам."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Заўсёды паказваць"</string>
     <string name="smv_application" msgid="3307209192155442829">"Прыкладанне <xliff:g id="APPLICATION">%1$s</xliff:g> (працэс <xliff:g id="PROCESS">%2$s</xliff:g>) парушыла ўласную палітыку StrictMode."</string>
@@ -1854,11 +1852,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Праверка экстранных паведамленняў"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Адказаць"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM-карта не дапускаецца"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM-карты няма"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM-карта не дапускаецца"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Тэлефон не дапускаецца"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Выплыўное акно"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Выплыўное акно"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Для гэтага ярлыка патрабуецца найноўшая версія праграмы"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Не атрымалася аднавіць ярлык, бо праграма не падтрымлівае рэзервовае капіраванне і аднаўленне"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Не атрымалася аднавіць ярлык з-за несупадзення подпісаў праграм"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Не атрымалася аднавіць ярлык"</string>
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 5643b7d..ccdeb24 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Сигнали"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Демонстрационен режим за магазини"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB връзка"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Приложението работи"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Приложения, използващи батерията"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> използва батерията"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> приложения използват батерията"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Метод на въвеждане"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Действия с текста"</string>
     <string name="email" msgid="4560673117055050403">"Имейл"</string>
-    <string name="dial" msgid="4204975095406423102">"Телефон"</string>
-    <string name="map" msgid="6068210738233985748">"Карти"</string>
-    <string name="browse" msgid="6993590095938149861">"Браузър"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Контакт"</string>
+    <string name="dial" msgid="1253998302767701559">"Обаждане"</string>
+    <string name="map" msgid="6521159124535543457">"Намиране"</string>
+    <string name="browse" msgid="1245903488306147205">"Отваряне"</string>
+    <string name="sms" msgid="4560537514610063430">"Съобщение"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Добавяне"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Мястото в хранилището е на изчерпване"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Възможно е някои функции на системата да не работят"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"За системата няма достатъчно място в хранилището. Уверете се, че имате свободни 250 МБ, и рестартирайте."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Отказ"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Отказ"</string>
-    <string name="close" msgid="2318214661230355730">"ЗАТВАРЯНЕ"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Внимание"</string>
     <string name="loading" msgid="7933681260296021180">"Зарежда се..."</string>
     <string name="capital_on" msgid="1544682755514494298">"ВКЛ"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Мащаб"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Винаги да се показва"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Активирайте отново това в „Системни настройки“ &gt; „Приложения“ &gt; „Изтеглени“."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Приложението не реагира"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"Възможно е <xliff:g id="APP_NAME">%1$s</xliff:g> да използва твърде много памет."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддържа текущата настройка за размер на дисплея и може да се държи по неочакван начин."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Винаги да се показва"</string>
     <string name="smv_application" msgid="3307209192155442829">"Приложението „<xliff:g id="APPLICATION">%1$s</xliff:g>“ (процес „<xliff:g id="PROCESS">%2$s</xliff:g>“) наруши правилото за стриктен режим, наложено от самото него."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Тест за спешни съобщения"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Отговор"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM картата не е разрешена"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM картата не е обезпечена"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM картата не е разрешена"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Телефонът не е разрешен"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Изскачащ прозорец"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Изскачащ прозорец"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"За този пряк път се изисква най-новата версия на приложението"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Прекият път не можа да бъде възстановен, защото приложението не поддържа създаването на резервно копие и възстановяването"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Прекият път не можа да бъде възстановен поради несъответствие в подписа на приложението"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Прекият път не можа да бъде възстановен"</string>
 </resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 48b8e64..f5744ed 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"সতর্কতা"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"খুচরা বিক্রয়ের ডেমো"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB সংযোগ"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"অ্যাপ চলছে"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"কিছু অ্যাপ ব্যাটারি ব্যবহার করছে"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপটি ব্যাটারি ব্যবহার করছে"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g>টি অ্যাপ ব্যাটারি ব্যবহার করছে"</string>
@@ -402,7 +403,7 @@
     <string name="permlab_vibrate" msgid="7696427026057705834">"ভাইব্রেশন নিয়ন্ত্রণ করুন"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"অ্যাপ্লিকেশানকে কম্পক নিয়ন্ত্রণ করতে দেয়৷"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"সরাসরি ফোন নম্বরগুলিতে কল করে"</string>
-    <string name="permdesc_callPhone" msgid="3740797576113760827">"অ্যাপ্লিকেশানটিকে আপনার হস্তক্ষেপ ছাড়াই ফোন নম্বরগুলিতে কল করতে মঞ্জুর করে৷ এটি অপ্রত্যাশিত পরিমাণ খরচা বা কলের কারণ হতে পারে৷ মনে রাখবেন, এটি অ্যাপ্লিকেশানটির দ্বারা জরুরি নম্বরগুলিতে কল করাকে অনুমতি দেয় না৷ ক্ষতিকারক অ্যাপ্লিকেশানগুলি আপনার সম্মতি ছাড়াই কল করার ফলে আপনাকে অহেতুক অর্থ প্রদান করতে হতে পারে৷"</string>
+    <string name="permdesc_callPhone" msgid="3740797576113760827">"অ্যাপ্লিকেশানটিকে আপনার হস্তক্ষেপ ছাড়াই ফোন নম্বরগুলিতে কল করতে মঞ্জুর করে৷ এটি অপ্রত্যাশিত পরিমাণ খরচা বা কলের কারণ হতে পারে৷ মনে রাখবেন, এটি অ্যাপ্লিকেশানটির দ্বারা জরুরি নম্বরগুলিতে কল করাকে অনুমতি দেয় না৷ ক্ষতিকারক অ্যাপ্লিকেশানগুলি আপনার সম্মতি ছাড়াই কল করার ফলে আপনাকে অহেতুক পেমেন্ট করতে হতে পারে৷"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS পরিষেবাতে অ্যাক্সেস"</string>
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"আপনার হস্তক্ষেপ ছাড়াই কল করতে অ্যাপ্লিকেশানটিকে IMS পরিষেবা ব্যবহারের অনুমতি দিন৷"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"ফোনের স্থিতি এবং পরিচয় পড়ুন"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"ইনপুট পদ্ধতি"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"পাঠ্য ক্রিয়াগুলি"</string>
     <string name="email" msgid="4560673117055050403">"ইমেল"</string>
-    <string name="dial" msgid="4204975095406423102">"ফোন করুন"</string>
-    <string name="map" msgid="6068210738233985748">"মানচিত্র"</string>
-    <string name="browse" msgid="6993590095938149861">"ব্রাউজার"</string>
-    <string name="sms" msgid="8250353543787396737">"এসএমএস পাঠান"</string>
-    <string name="add_contact" msgid="7990645816259405444">"পরিচিতি যোগ করুন"</string>
+    <string name="dial" msgid="1253998302767701559">"কল"</string>
+    <string name="map" msgid="6521159124535543457">"অবস্থান নির্ণয় করুন"</string>
+    <string name="browse" msgid="1245903488306147205">"খুলুন"</string>
+    <string name="sms" msgid="4560537514610063430">"মেসেজ"</string>
+    <string name="add_contact" msgid="7867066569670597203">"যোগ করুন"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"স্টোরেজ পূর্ণ হতে চলেছে"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"কিছু কিছু সিস্টেম ক্রিয়াকলাপ কাজ নাও করতে পারে"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"সিস্টেমের জন্য যথেষ্ট স্টোরেজ নেই৷ আপনার কাছে ২৫০এমবি ফাঁকা স্থান রয়েছে কিনা সে বিষয়ে নিশ্চিত হন এবং সিস্টেম চালু করুন৷"</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"বাতিল করুন"</string>
     <string name="yes" msgid="5362982303337969312">"ঠিক আছে"</string>
     <string name="no" msgid="5141531044935541497">"বাতিল করুন"</string>
-    <string name="close" msgid="2318214661230355730">"বন্ধ করুন"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"খেয়াল করুন"</string>
     <string name="loading" msgid="7933681260296021180">"লোড হচ্ছে..."</string>
     <string name="capital_on" msgid="1544682755514494298">"চালু করুন"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"স্কেল"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"সবসময় দেখান"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"সিস্টেম সেটিংস&gt; অ্যাপ্স&gt; ডাউনলোড করাগুলি এ এটি পুনঃসক্ষম করুন৷"</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"অ্যাপটি সাড়া দিচ্ছে না"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"মনে হচ্ছে <xliff:g id="APP_NAME">%1$s</xliff:g> খুব বেশি মেমরি ব্যবহার করছে।"</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g>, বর্তমান প্রদর্শনের আকারের সেটিংস সমর্থন করে না এবং অপ্রত্যাশিত আচরণ করতে পারে৷"</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"সর্বদা দেখান"</string>
     <string name="smv_application" msgid="3307209192155442829">"অ্যাপ্লিকেশানটি <xliff:g id="APPLICATION">%1$s</xliff:g> (প্রক্রিয়া <xliff:g id="PROCESS">%2$s</xliff:g>) তার স্ব-প্রয়োগ করা কঠোর মোড নীতি লঙ্ঘন করেছে৷"</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"বিপদকালীন বার্তাগুলির পরীক্ষা"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"উত্তর দিন"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"সিম অনুমোদিত নয়"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"সিম প্রস্তুত নয়"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"সিম অনুমোদিত নয়"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"ফোন অনুমোদিত নয়"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"পপ-আপ উইন্ডো"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"পপ-আপ উইন্ডো"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>টি"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"এই শর্টকাটটির জন্য লেটেস্ট অ্যাপ প্রয়োজন"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"শর্টকাট ফিরিয়ে আনা যায়নি কারণ অ্যাপটিতে \'ব্যাক-আপ এবং রিস্টোর\' করার সুবিধা নেই"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"শর্টকাট ফিরিয়ে আনা যায়নি কারণ অ্যাপের সিগ্নেচারটি মিল হচ্ছে না"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"শর্টকাট ফিরিয়ে আনা যায়নি"</string>
 </resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index c4a6d69..57dd73f 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -252,6 +252,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Upozorenja"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Promotivna demonstracija u maloprodaji"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB veza"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Pokrenuta je aplikacija"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Aplikacije koje troše bateriju"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> troši bateriju"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"Broj aplikacija koje troše bateriju: <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
@@ -998,11 +999,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Način unosa"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Akcije za tekst"</string>
     <string name="email" msgid="4560673117055050403">"E-pošta"</string>
-    <string name="dial" msgid="4204975095406423102">"Pozovi"</string>
-    <string name="map" msgid="6068210738233985748">"Mape"</string>
-    <string name="browse" msgid="6993590095938149861">"Preglednik"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Kontakt"</string>
+    <string name="dial" msgid="1253998302767701559">"Pozovite"</string>
+    <string name="map" msgid="6521159124535543457">"Odredite lokaciju"</string>
+    <string name="browse" msgid="1245903488306147205">"Otvorite"</string>
+    <string name="sms" msgid="4560537514610063430">"Poruka"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Dodajte"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ponestaje prostora za pohranu"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Neke funkcije sistema možda neće raditi"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nema dovoljno prostora za sistem. Obezbijedite 250MB slobodnog prostora i ponovo pokrenite uređaj."</string>
@@ -1012,7 +1013,6 @@
     <string name="cancel" msgid="6442560571259935130">"Otkaži"</string>
     <string name="yes" msgid="5362982303337969312">"Uredu"</string>
     <string name="no" msgid="5141531044935541497">"Otkaži"</string>
-    <string name="close" msgid="2318214661230355730">"ZATVORI"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Pažnja"</string>
     <string name="loading" msgid="7933681260296021180">"Učitavanje..."</string>
     <string name="capital_on" msgid="1544682755514494298">"Uključeno"</string>
@@ -1071,8 +1071,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Razmjer"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Uvijek prikaži"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Ponovo omogućite ovu opciju u meniju Postavke sistema &gt; Aplikacije &gt; Preuzete aplikacije."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikacija ne reagira"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"Moguće je da aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> koristi previše memorije."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava trenutnu postavku veličine ekrana i može se ponašati neočekivano."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Uvijek prikaži"</string>
     <string name="smv_application" msgid="3307209192155442829">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) prekršila je vlastita StrictMode pravila."</string>
@@ -1821,11 +1819,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test poruka za hitne slučajeve"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Odgovori"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM kartica nije dozvoljena"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM kartica nije dodijeljena"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM kartica nije dozvoljena"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Telefon nije dozvoljen"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Iskočni prozor"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Iskočni prozor"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Za ovu prečicu potrebna je najnovija aplikacija"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Prečica nije uspješno vraćena jer aplikacija ne podržava izradu sigurnosne kopije i vraćanje"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Prečica nije uspješno vraćena zbog nepodudaranja potpisa aplikacije"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Prečica nije uspješno vraćena"</string>
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index af48cf7..2e0724d 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertes"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demostració comercial"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Connexió USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"S\'està executant una aplicació"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Aplicacions que consumeixen bateria"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> està consumint bateria"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> aplicacions estan consumint bateria"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Mètode d\'introducció de text"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Accions de text"</string>
     <string name="email" msgid="4560673117055050403">"Correu electrònic"</string>
-    <string name="dial" msgid="4204975095406423102">"Truca"</string>
-    <string name="map" msgid="6068210738233985748">"Mapes"</string>
-    <string name="browse" msgid="6993590095938149861">"Navegador"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Contacte"</string>
+    <string name="dial" msgid="1253998302767701559">"Truca"</string>
+    <string name="map" msgid="6521159124535543457">"Localitza"</string>
+    <string name="browse" msgid="1245903488306147205">"Obre"</string>
+    <string name="sms" msgid="4560537514610063430">"Missatge"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Afegeix"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"L\'espai d\'emmagatzematge s\'està esgotant"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"És possible que algunes funcions del sistema no funcionin"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"No hi ha prou espai d\'emmagatzematge per al sistema. Comprova que tinguis 250 MB d\'espai lliure i reinicia."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Cancel·la"</string>
     <string name="yes" msgid="5362982303337969312">"D\'acord"</string>
     <string name="no" msgid="5141531044935541497">"Cancel·la"</string>
-    <string name="close" msgid="2318214661230355730">"TANCA"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Atenció"</string>
     <string name="loading" msgid="7933681260296021180">"S\'està carregant…"</string>
     <string name="capital_on" msgid="1544682755514494298">"SÍ"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostra sempre"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Torna a activar-ho a Configuració del sistema &gt; Aplicacions &gt; Baixades."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"L\'aplicació no respon"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"És possible que <xliff:g id="APP_NAME">%1$s</xliff:g> faci servir massa memòria."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet la mida de pantalla actual i és possible que funcioni de manera inesperada."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostra sempre"</string>
     <string name="smv_application" msgid="3307209192155442829">"L\'aplicació <xliff:g id="APPLICATION">%1$s</xliff:g>(procés <xliff:g id="PROCESS">%2$s</xliff:g>) ha incomplert la seva política autoimposada de mode estricte."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Prova de missatges d\'emergència"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Respon"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM no compatible"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM no proporcionada"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM no compatible"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Telèfon no no compatible"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Finestra emergent"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Finestra emergent"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"<xliff:g id="NUMBER">%1$d</xliff:g> més"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Per fer servir aquesta drecera has de tenir l\'última versió de l\'aplicació"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"No s\'ha pogut restaurar la drecera perquè l\'aplicació no permet la còpia de seguretat ni la restauració"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"No s\'ha pogut restaurar la drecera perquè la signatura de l\'aplicació no coincideix"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"No s\'ha pogut restaurar la drecera"</string>
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index d1029e6..a7021e9 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -255,6 +255,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Upozornění"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Prodejní ukázka"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Připojení USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Aplikace je spuštěna"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Aplikace spotřebovávají baterii"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> využívá baterii"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"Aplikace (<xliff:g id="NUMBER">%1$d</xliff:g>) využívají baterii"</string>
@@ -1018,11 +1019,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Metoda zadávání dat"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Operace s textem"</string>
     <string name="email" msgid="4560673117055050403">"Poslat e-mail"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefon"</string>
-    <string name="map" msgid="6068210738233985748">"Mapy"</string>
-    <string name="browse" msgid="6993590095938149861">"Prohlížeč"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Kontakt"</string>
+    <string name="dial" msgid="1253998302767701559">"Zavolat"</string>
+    <string name="map" msgid="6521159124535543457">"Najít"</string>
+    <string name="browse" msgid="1245903488306147205">"Otevřít"</string>
+    <string name="sms" msgid="4560537514610063430">"Zpráva"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Přidat"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"V úložišti je málo místa"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Některé systémové funkce nemusí fungovat"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Pro systém není dostatek místa v úložišti. Uvolněte alespoň 250 MB místa a restartujte zařízení."</string>
@@ -1032,7 +1033,6 @@
     <string name="cancel" msgid="6442560571259935130">"Zrušit"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Zrušit"</string>
-    <string name="close" msgid="2318214661230355730">"ZAVŘÍT"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Upozornění"</string>
     <string name="loading" msgid="7933681260296021180">"Načítání..."</string>
     <string name="capital_on" msgid="1544682755514494298">"I"</string>
@@ -1089,8 +1089,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Měřítko"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Vždy zobrazovat"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Tento režim znovu povolíte v sekci Nastavení systému &gt; Aplikace &gt; Stažené."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikace nereaguje"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> pravděpodobně využívá příliš mnoho paměti."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> aktuální nastavení velikosti zobrazení nepodporuje a může se chovat neočekávaně."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Vždy zobrazovat"</string>
     <string name="smv_application" msgid="3307209192155442829">"Aplikace <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) porušila své vlastní vynucené zásady StrictMode."</string>
@@ -1854,11 +1852,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test nouzových zpráv"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Odpovědět"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM karta není povolena"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM karta není poskytována"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM karta není povolena"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Telefon není povolen"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Vyskakovací okno"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Vyskakovací okno"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"a ještě <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Tato zkratka vyžaduje nejnovější verzi aplikace"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Zkratku nelze obnovit, protože aplikace nepodporuje zálohování a obnovu"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Zkratku nelze obnovit, protože se neshoduje podpis aplikace"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Zkratku nelze obnovit"</string>
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 66af879d..5b0edbe 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Underretninger"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demo til udstilling i butik"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-forbindelse"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Appen kører"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Apps, der bruger batteri"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> bruger batteri"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> apps bruger batteri"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Inputmetode"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Teksthandlinger"</string>
     <string name="email" msgid="4560673117055050403">"E-mail"</string>
-    <string name="dial" msgid="4204975095406423102">"Opkald"</string>
-    <string name="map" msgid="6068210738233985748">"Kort"</string>
-    <string name="browse" msgid="6993590095938149861">"Browser"</string>
-    <string name="sms" msgid="8250353543787396737">"Sms"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Kontaktperson"</string>
+    <string name="dial" msgid="1253998302767701559">"Ring op"</string>
+    <string name="map" msgid="6521159124535543457">"Find"</string>
+    <string name="browse" msgid="1245903488306147205">"Åbn"</string>
+    <string name="sms" msgid="4560537514610063430">"Besked"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Tilføj"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Der er snart ikke mere lagerplads"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Nogle systemfunktioner virker måske ikke"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Der er ikke nok ledig lagerplads til systemet. Sørg for, at du har 250 MB ledig plads, og genstart."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Annuller"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Annuller"</string>
-    <string name="close" msgid="2318214661230355730">"LUK"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Bemærk"</string>
     <string name="loading" msgid="7933681260296021180">"Indlæser…"</string>
     <string name="capital_on" msgid="1544682755514494298">"TIL"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skaler"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Vis altid"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktivér dette igen i Systemindstillinger &gt; Apps &gt; Downloadet."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Appen svarer ikke"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> bruger muligvis for meget hukommelse."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> understøtter ikke den aktuelle indstilling for visningsstørrelse og vil muligvis ikke fungere som forventet."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Vis altid"</string>
     <string name="smv_application" msgid="3307209192155442829">"Appen <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) har overtrådt sin egen StrictMode-politik."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test af nødbeskeder"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Svar"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM-kortet har ikke adgangstilladelse"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM-kortet er ikke aktiveret"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM-kortet har ikke adgangstilladelse"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Telefonen har ikke adgangstilladelse"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Pop op-vindue"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Pop op-vindue"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"<xliff:g id="NUMBER">%1$d</xliff:g> mere"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Denne genvej kræver den nyeste app"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Genvejen kunne ikke gendannes, da appen ikke understøtter sikkerhedskopiering og gendannelse"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Genvejen kunne ikke gendannes på grund af uoverensstemmelse i appsignatur"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Genvejen kunne ikke gendannes"</string>
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index f76408a..0cff7dd 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Warnmeldungen"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demo für Einzelhandel"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-Verbindung"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"App wird ausgeführt"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Strom verbrauchende Apps"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> verbraucht Strom"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> Apps verbrauchen Strom"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Eingabemethode"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Textaktionen"</string>
     <string name="email" msgid="4560673117055050403">"E-Mail"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefon"</string>
-    <string name="map" msgid="6068210738233985748">"Karten"</string>
-    <string name="browse" msgid="6993590095938149861">"Browser"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Kontakt"</string>
+    <string name="dial" msgid="1253998302767701559">"Anrufen"</string>
+    <string name="map" msgid="6521159124535543457">"Suchen"</string>
+    <string name="browse" msgid="1245903488306147205">"Öffnen"</string>
+    <string name="sms" msgid="4560537514610063430">"SMS"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Hinzufügen"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Der Speicherplatz wird knapp"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Einige Systemfunktionen funktionieren möglicherweise nicht."</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Der Speicherplatz reicht nicht für das System aus. Stelle sicher, dass 250 MB freier Speicherplatz vorhanden sind, und starte das Gerät dann neu."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Abbrechen"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Abbrechen"</string>
-    <string name="close" msgid="2318214661230355730">"SCHLIEẞEN"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Achtung"</string>
     <string name="loading" msgid="7933681260296021180">"Wird geladen…"</string>
     <string name="capital_on" msgid="1544682755514494298">"AN"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skalieren"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Immer anzeigen"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Eine erneute Aktivierung ist in den Systemeinstellungen unter \"Apps &gt; Heruntergeladen\" möglich."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"App reagiert nicht"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> belegt möglicherweise zu viel Speicherplatz."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> unterstützt nicht die aktuelle Einstellung für die Anzeigegröße, sodass ein unerwartetes Verhalten auftreten kann."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Immer anzeigen"</string>
     <string name="smv_application" msgid="3307209192155442829">"Die App <xliff:g id="APPLICATION">%1$s</xliff:g> (Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) hat gegen deine selbsterzwungene StrictMode-Richtlinie verstoßen."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test der Notfallwarnungen"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Antworten"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM-Karte nicht zulässig"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM nicht eingerichtet"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM-Karte nicht zulässig"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Smartphone nicht zulässig"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Pop-up-Fenster"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Pop-up-Fenster"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Für diese Verknüpfung ist die aktuelle App-Version erforderlich"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Verknüpfung konnte nicht wiederhergestellt werden, weil die App keine Sicherung und keine Wiederherstellung unterstützt"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Verknüpfung konnte nicht wiederhergestellt werden, weil die App-Signatur nicht übereinstimmt"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Verknüpfung konnte nicht wiederhergestellt werden"</string>
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index d2cc930..9619737 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Ειδοποιήσεις"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Επίδειξη λιανικής"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Σύνδεση USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Η εφαρμογή εκτελείται"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Εφαρμογές που καταναλώνουν μπαταρία"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> χρησιμοποιεί μπαταρία"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> εφαρμογές χρησιμοποιούν μπαταρία"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Μέθοδος εισόδου"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Ενέργειες κειμένου"</string>
     <string name="email" msgid="4560673117055050403">"Ηλεκτρονικό ταχυδρομείο"</string>
-    <string name="dial" msgid="4204975095406423102">"Τηλέφωνο"</string>
-    <string name="map" msgid="6068210738233985748">"Χάρτες"</string>
-    <string name="browse" msgid="6993590095938149861">"Πρόγραμμα περιήγησης"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Επαφή"</string>
+    <string name="dial" msgid="1253998302767701559">"Κλήση"</string>
+    <string name="map" msgid="6521159124535543457">"Εντοπισμός"</string>
+    <string name="browse" msgid="1245903488306147205">"Άνοιγμα"</string>
+    <string name="sms" msgid="4560537514610063430">"Μήνυμα"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Προσθήκη"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ο αποθηκευτικός χώρος εξαντλείται"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Ορισμένες λειτουργίες συστήματος ενδέχεται να μην λειτουργούν"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Δεν υπάρχει αρκετός αποθηκευτικός χώρος για το σύστημα. Βεβαιωθείτε ότι διαθέτετε 250 MB ελεύθερου χώρου και κάντε επανεκκίνηση."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Ακύρωση"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Ακύρωση"</string>
-    <string name="close" msgid="2318214661230355730">"ΚΛΕΙΣΙΜΟ"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Προσοχή"</string>
     <string name="loading" msgid="7933681260296021180">"Φόρτωση…"</string>
     <string name="capital_on" msgid="1544682755514494298">"Ενεργό"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Κλίμακα"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Να εμφανίζονται πάντα"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Ενεργοποιήστε το ξανά στις Ρυθμίσεις συστημάτων &gt; Εφαρμογές &gt; Ληφθείσες."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Η εφαρμογή δεν αποκρίνεται"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> μπορεί να χρησιμοποιεί υπερβολική μνήμη."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν υποστηρίζει την τρέχουσα ρύθμιση Μεγέθους οθόνης και ενδέχεται να παρουσιάζει μη αναμενόμενη συμπεριφορά."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Να εμφανίζεται πάντα"</string>
     <string name="smv_application" msgid="3307209192155442829">"Η εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> (διεργασία <xliff:g id="PROCESS">%2$s</xliff:g>) παραβίασε την αυτοεπιβαλλόμενη πολιτική StrictMode."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Δοκιμαστικό μήνυμα έκτακτης ανάγκης"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Απάντηση"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"Η κάρτα SIM δεν επιτρέπεται"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Δεν παρέχεται κάρτα SIM"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"Η κάρτα SIM δεν επιτρέπεται"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Το τηλέφωνο δεν επιτρέπεται"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Αναδυόμενο παράθυρο"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Αναδυόμενο παράθυρο"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Αυτή η συντόμευση απαιτεί την πιο πρόσφατη έκδοση της εφαρμογής"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Δεν ήταν δυνατή η επαναφορά της συντόμευσης, επειδή η εφαρμογή δεν υποστηρίζει τη δημιουργία αντιγράφων ασφαλείας και την επαναφορά"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Δεν ήταν δυνατή η επαναφορά της συντόμευσης, λόγω αναντιστοιχίας της υπογραφής εφαρμογής"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Δεν ήταν δυνατή η επαναφορά της συντόμευσης"</string>
 </resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index ad03374..07450b2 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alerts"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Retail demo"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB connection"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"App running"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Apps consuming battery"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> is using battery"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> apps are using battery"</string>
@@ -978,11 +979,16 @@
     <string name="inputMethod" msgid="1653630062304567879">"Input method"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Text actions"</string>
     <string name="email" msgid="4560673117055050403">"Email"</string>
-    <string name="dial" msgid="4204975095406423102">"Phone"</string>
-    <string name="map" msgid="6068210738233985748">"Maps"</string>
-    <string name="browse" msgid="6993590095938149861">"Browser"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Contact"</string>
+    <!-- no translation found for dial (1253998302767701559) -->
+    <skip />
+    <!-- no translation found for map (6521159124535543457) -->
+    <skip />
+    <!-- no translation found for browse (1245903488306147205) -->
+    <skip />
+    <!-- no translation found for sms (4560537514610063430) -->
+    <skip />
+    <!-- no translation found for add_contact (7867066569670597203) -->
+    <skip />
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Not enough storage for the system. Make sure that you have 250 MB of free space and restart."</string>
@@ -1789,6 +1795,13 @@
     <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM not allowed"</string>
     <string name="mmcc_illegal_me" msgid="4438696681169345015">"Phone not allowed"</string>
     <string name="popup_window_default_title" msgid="4874318849712115433">"Pop-Up Window"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <!-- no translation found for shortcut_restored_on_lower_version (5270675146351613828) -->
+    <skip />
+    <!-- no translation found for shortcut_restore_not_supported (5028808567940014190) -->
+    <skip />
+    <!-- no translation found for shortcut_restore_signature_mismatch (2406209324521327518) -->
+    <skip />
+    <!-- no translation found for shortcut_restore_unknown_issue (8703738064603262597) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index ad03374..07450b2 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alerts"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Retail demo"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB connection"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"App running"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Apps consuming battery"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> is using battery"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> apps are using battery"</string>
@@ -978,11 +979,16 @@
     <string name="inputMethod" msgid="1653630062304567879">"Input method"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Text actions"</string>
     <string name="email" msgid="4560673117055050403">"Email"</string>
-    <string name="dial" msgid="4204975095406423102">"Phone"</string>
-    <string name="map" msgid="6068210738233985748">"Maps"</string>
-    <string name="browse" msgid="6993590095938149861">"Browser"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Contact"</string>
+    <!-- no translation found for dial (1253998302767701559) -->
+    <skip />
+    <!-- no translation found for map (6521159124535543457) -->
+    <skip />
+    <!-- no translation found for browse (1245903488306147205) -->
+    <skip />
+    <!-- no translation found for sms (4560537514610063430) -->
+    <skip />
+    <!-- no translation found for add_contact (7867066569670597203) -->
+    <skip />
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Not enough storage for the system. Make sure that you have 250 MB of free space and restart."</string>
@@ -1789,6 +1795,13 @@
     <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM not allowed"</string>
     <string name="mmcc_illegal_me" msgid="4438696681169345015">"Phone not allowed"</string>
     <string name="popup_window_default_title" msgid="4874318849712115433">"Pop-Up Window"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <!-- no translation found for shortcut_restored_on_lower_version (5270675146351613828) -->
+    <skip />
+    <!-- no translation found for shortcut_restore_not_supported (5028808567940014190) -->
+    <skip />
+    <!-- no translation found for shortcut_restore_signature_mismatch (2406209324521327518) -->
+    <skip />
+    <!-- no translation found for shortcut_restore_unknown_issue (8703738064603262597) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index ad03374..07450b2 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alerts"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Retail demo"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB connection"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"App running"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Apps consuming battery"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> is using battery"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> apps are using battery"</string>
@@ -978,11 +979,16 @@
     <string name="inputMethod" msgid="1653630062304567879">"Input method"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Text actions"</string>
     <string name="email" msgid="4560673117055050403">"Email"</string>
-    <string name="dial" msgid="4204975095406423102">"Phone"</string>
-    <string name="map" msgid="6068210738233985748">"Maps"</string>
-    <string name="browse" msgid="6993590095938149861">"Browser"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Contact"</string>
+    <!-- no translation found for dial (1253998302767701559) -->
+    <skip />
+    <!-- no translation found for map (6521159124535543457) -->
+    <skip />
+    <!-- no translation found for browse (1245903488306147205) -->
+    <skip />
+    <!-- no translation found for sms (4560537514610063430) -->
+    <skip />
+    <!-- no translation found for add_contact (7867066569670597203) -->
+    <skip />
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Not enough storage for the system. Make sure that you have 250 MB of free space and restart."</string>
@@ -1789,6 +1795,13 @@
     <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM not allowed"</string>
     <string name="mmcc_illegal_me" msgid="4438696681169345015">"Phone not allowed"</string>
     <string name="popup_window_default_title" msgid="4874318849712115433">"Pop-Up Window"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <!-- no translation found for shortcut_restored_on_lower_version (5270675146351613828) -->
+    <skip />
+    <!-- no translation found for shortcut_restore_not_supported (5028808567940014190) -->
+    <skip />
+    <!-- no translation found for shortcut_restore_signature_mismatch (2406209324521327518) -->
+    <skip />
+    <!-- no translation found for shortcut_restore_unknown_issue (8703738064603262597) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index ad03374..07450b2 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alerts"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Retail demo"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB connection"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"App running"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Apps consuming battery"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> is using battery"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> apps are using battery"</string>
@@ -978,11 +979,16 @@
     <string name="inputMethod" msgid="1653630062304567879">"Input method"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Text actions"</string>
     <string name="email" msgid="4560673117055050403">"Email"</string>
-    <string name="dial" msgid="4204975095406423102">"Phone"</string>
-    <string name="map" msgid="6068210738233985748">"Maps"</string>
-    <string name="browse" msgid="6993590095938149861">"Browser"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Contact"</string>
+    <!-- no translation found for dial (1253998302767701559) -->
+    <skip />
+    <!-- no translation found for map (6521159124535543457) -->
+    <skip />
+    <!-- no translation found for browse (1245903488306147205) -->
+    <skip />
+    <!-- no translation found for sms (4560537514610063430) -->
+    <skip />
+    <!-- no translation found for add_contact (7867066569670597203) -->
+    <skip />
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Not enough storage for the system. Make sure that you have 250 MB of free space and restart."</string>
@@ -1789,6 +1795,13 @@
     <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM not allowed"</string>
     <string name="mmcc_illegal_me" msgid="4438696681169345015">"Phone not allowed"</string>
     <string name="popup_window_default_title" msgid="4874318849712115433">"Pop-Up Window"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <!-- no translation found for shortcut_restored_on_lower_version (5270675146351613828) -->
+    <skip />
+    <!-- no translation found for shortcut_restore_not_supported (5028808567940014190) -->
+    <skip />
+    <!-- no translation found for shortcut_restore_signature_mismatch (2406209324521327518) -->
+    <skip />
+    <!-- no translation found for shortcut_restore_unknown_issue (8703738064603262597) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index d6da98d..336b35d 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‎‏‏‎‎‏‎‏‏‏‏‏‏‎‎‎‏‎‏‏‏‏‎‎‎‏‏‏‏‏‏‎‏‎Alerts‎‏‎‎‏‎"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‎‎‎‎‎‎‏‏‎‎‎‏‎‎‎‏‎‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‏‎‎‎‎‏‏‏‎‎‏‏‏‏‏‏‏‎‏‏‎Retail demo‎‏‎‎‏‎"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‏‏‎‎‏‎‎‏‎‏‏‏‎‏‏‏‎‎‎‎‏‎‎‏‏‏‏‎‏‏‎‎‎‎‎‎‏‎‎‏‎USB connection‎‏‎‎‏‎"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‏‏‎‏‎‏‏‎‏‎‎‏‏‎‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‎‎‏‎‎‎‎‏‏‎‎‏‏‏‎‎‏‏‏‏‏‏‏‎App running‎‏‎‎‏‎"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‏‎‎‎‏‎‎‏‏‏‎‎‏‏‎‏‏‏‏‏‎‏‎‏‎‎‎‏‎‎‏‏‎‏‎‏‏‎‏‏‎‎‎‎‎‎‏‏‎‎‏‏‎‎Apps consuming battery‎‏‎‎‏‎"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎‏‏‎‏‎‎‏‎‏‎‏‎‎‏‎‏‎‏‏‏‏‏‎‏‏‏‏‎‎‎‏‎‏‏‏‎‎‎‏‏‎‎‏‎‏‎‏‏‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ is using battery‎‏‎‎‏‎"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‏‎‏‏‎‎‎‏‏‎‏‎‎‏‎‎‏‎‎‏‎‏‏‎‎‎‎‎‎‎‎‏‎‏‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="NUMBER">%1$d</xliff:g>‎‏‎‎‏‏‏‎ apps are using battery‎‏‎‎‏‎"</string>
@@ -978,11 +979,16 @@
     <string name="inputMethod" msgid="1653630062304567879">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‎‎‏‎‏‏‎‎‏‎‎‏‎‎‎‏‎‎‎‏‎‎‏‎‎‎‏‏‏‎Input method‎‏‎‎‏‎"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‎‏‎‎‎‎‎‏‏‎‎‎‎‎‎‏‏‎‎‏‎‎‏‎‏‎‏‏‏‏‎‏‎‎‏‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‏‏‎‎Text actions‎‏‎‎‏‎"</string>
     <string name="email" msgid="4560673117055050403">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‏‎‎‎‏‎‎‎‎‎‎‏‎‎‏‎‏‎‏‎‏‏‎‏‎‏‏‏‏‎‏‎‏‏‎‎‎‏‎‏‎‏‎‎‎‏‏‎Email‎‏‎‎‏‎"</string>
-    <string name="dial" msgid="4204975095406423102">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‎‏‏‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‎‎‏‎‎‎‎‎‎‎‏‏‎‎‎‏‎‎‎‎‎‏‏‎‏‏‎‎‎‎‏‏‏‏‏‎‎Phone‎‏‎‎‏‎"</string>
-    <string name="map" msgid="6068210738233985748">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‎‏‏‎‏‎‎‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‎‎‎‎‏‎‏‎‏‎‎‏‎‏‏‏‎‎‏‎‏‎‏‏‎‏‎‏‎‎‎Maps‎‏‎‎‏‎"</string>
-    <string name="browse" msgid="6993590095938149861">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‎‎‏‏‏‎‎‎‏‏‏‎‎‏‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‎‏‎‏‏‏‎‏‏‏‏‎‎‏‎‏‎Browser‎‏‎‎‏‎"</string>
-    <string name="sms" msgid="8250353543787396737">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‏‏‎‏‎‏‎‏‏‏‏‏‏‎‎‎‏‏‎‏‎‏‎‏‎‎‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎SMS‎‏‎‎‏‎"</string>
-    <string name="add_contact" msgid="7990645816259405444">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‏‎‎‎‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‏‎‎‏‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‎‎‏‏‎‏‎‎‎‎‏‎‎‎Contact‎‏‎‎‏‎"</string>
+    <!-- no translation found for dial (1253998302767701559) -->
+    <skip />
+    <!-- no translation found for map (6521159124535543457) -->
+    <skip />
+    <!-- no translation found for browse (1245903488306147205) -->
+    <skip />
+    <!-- no translation found for sms (4560537514610063430) -->
+    <skip />
+    <!-- no translation found for add_contact (7867066569670597203) -->
+    <skip />
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‏‎‎‎‏‎‏‏‏‎‎‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‎‏‎‎‏‎‏‎‏‎‎‎‎‏‎‎‏‎‎‎‎‏‏‎‎‎‏‎‎Storage space running out‎‏‎‎‏‎"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‏‏‏‏‏‎‏‎‎‎‎‏‏‎‏‏‎‏‏‏‎‏‏‎‏‎‎‎‎‎‎‎‎‎‎‎‎‏‏‏‎‎‎‏‏‏‎‎‎‏‏‎Some system functions may not work‎‏‎‎‏‎"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‏‎‏‎‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‎‏‎‏‎‎‎‏‏‏‎‎‏‏‎‏‏‎‏‏‏‎‏‏‎‏‏‎‎‎‎‎Not enough storage for the system. Make sure you have 250MB of free space and restart.‎‏‎‎‏‎"</string>
@@ -1789,6 +1795,13 @@
     <string name="mmcc_illegal_ms" msgid="2769452751852211112">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‎‏‏‏‏‎‎‎‏‎‎‏‎‏‎‎‏‏‎‏‎‏‏‎‎‏‎‎‎‎‏‏‎‎‎‎‏‎‎‎‎‏‎‏‏‏‎‏‎‏‎‎‎‎SIM not allowed‎‏‎‎‏‎"</string>
     <string name="mmcc_illegal_me" msgid="4438696681169345015">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‏‎‎‏‎‏‏‎‏‎‏‏‎‎‎‏‏‏‎‏‎‏‎‎‎‎‏‎‏‏‎‎‏‏‎‏‏‏‎‏‏‎‎‏‏‏‏‏‎‏‏‏‎Phone not allowed‎‏‎‎‏‎"</string>
     <string name="popup_window_default_title" msgid="4874318849712115433">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‏‎‎‏‎‏‎‎‎‎‏‏‏‏‎‎‏‎‏‎‏‏‎‎‏‎‎‏‏‏‎‎‎‏‎‏‎‎‏‏‎‎‏‏‏‎‏‏‏‎‏‎‎‏‎Popup Window‎‏‎‎‏‎"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <string name="slice_more_content" msgid="8504342889413274608">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‎‏‎‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‎‎‏‎‏‏‏‎‎‏‏‎‎‎‏‏‏‎‏‎‏‏‏‏‏‏‎‎‎‎‎+ ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%1$d</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <!-- no translation found for shortcut_restored_on_lower_version (5270675146351613828) -->
+    <skip />
+    <!-- no translation found for shortcut_restore_not_supported (5028808567940014190) -->
+    <skip />
+    <!-- no translation found for shortcut_restore_signature_mismatch (2406209324521327518) -->
+    <skip />
+    <!-- no translation found for shortcut_restore_unknown_issue (8703738064603262597) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index ea8b54e..67dac60 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demo para punto de venta"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Conexión USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"App en ejecución"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Apps que consumen batería"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> está consumiendo batería"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> apps están consumiendo batería"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Método de entrada"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Acciones de texto"</string>
     <string name="email" msgid="4560673117055050403">"Correo electrónico"</string>
-    <string name="dial" msgid="4204975095406423102">"Teléfono"</string>
-    <string name="map" msgid="6068210738233985748">"Mapas"</string>
-    <string name="browse" msgid="6993590095938149861">"Navegador"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Contacto"</string>
+    <string name="dial" msgid="1253998302767701559">"Llamar"</string>
+    <string name="map" msgid="6521159124535543457">"Buscar"</string>
+    <string name="browse" msgid="1245903488306147205">"Abrir"</string>
+    <string name="sms" msgid="4560537514610063430">"Mensaje"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Agregar"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Queda poco espacio de almacenamiento"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Es posible que algunas funciones del sistema no estén disponibles."</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"No hay espacio suficiente para el sistema. Asegúrate de que haya 250 MB libres y reinicia el dispositivo."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
     <string name="yes" msgid="5362982303337969312">"Aceptar"</string>
     <string name="no" msgid="5141531044935541497">"Cancelar"</string>
-    <string name="close" msgid="2318214661230355730">"CERRAR"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Atención"</string>
     <string name="loading" msgid="7933681260296021180">"Cargando…"</string>
     <string name="capital_on" msgid="1544682755514494298">"Sí"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar siempre"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Volver a activar Configuración del sistema &gt; Aplicaciones &gt; Descargas"</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"La app no responde"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"Es posible que <xliff:g id="APP_NAME">%1$s</xliff:g> esté consumiendo demasiada memoria."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> no es compatible con la configuración del tamaño de pantalla actual. Es posible que no se comporte de manera correcta."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar siempre"</string>
     <string name="smv_application" msgid="3307209192155442829">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) ha infringido su política StrictMode de aplicación automática."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Prueba de mensajes de emergencia"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Responder"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM no permitida"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM no provista"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM no permitida"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Teléfono no permitido"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Ventana emergente"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Ventana emergente"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"<xliff:g id="NUMBER">%1$d</xliff:g> más"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Este acceso directo requiere la app más reciente"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Error al restablecer el acceso directo porque la app no admite la opción de copia de seguridad y restauración"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Error al restablecer el acceso directo por falta de coincidencia con la firma de apps"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Error al restablecer el acceso directo"</string>
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 6164bac..a9e8488 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demo para tiendas"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Conexión USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Aplicación en ejecución"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Aplicaciones que consumen batería"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> está usando la batería"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> aplicaciones están usando la batería"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Método de introducción de texto"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Acciones de texto"</string>
     <string name="email" msgid="4560673117055050403">"Correo electrónico"</string>
-    <string name="dial" msgid="4204975095406423102">"Teléfono"</string>
-    <string name="map" msgid="6068210738233985748">"Mapas"</string>
-    <string name="browse" msgid="6993590095938149861">"Navegador"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Contacto"</string>
+    <string name="dial" msgid="1253998302767701559">"Llamar"</string>
+    <string name="map" msgid="6521159124535543457">"Localizar"</string>
+    <string name="browse" msgid="1245903488306147205">"Abrir"</string>
+    <string name="sms" msgid="4560537514610063430">"Mensaje"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Añadir"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Queda poco espacio"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Es posible que algunas funciones del sistema no funcionen."</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"No hay espacio suficiente para el sistema. Comprueba que haya 250 MB libres y reinicia el dispositivo."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
     <string name="yes" msgid="5362982303337969312">"Aceptar"</string>
     <string name="no" msgid="5141531044935541497">"Cancelar"</string>
-    <string name="close" msgid="2318214661230355730">"CERRAR"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Atención"</string>
     <string name="loading" msgid="7933681260296021180">"Cargando..."</string>
     <string name="capital_on" msgid="1544682755514494298">"ACTIVADO"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar siempre"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Para volver a habilitar esta opción, accede a Ajustes &gt; Aplicaciones &gt; Descargadas."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"La aplicación no responde"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"Es posible que <xliff:g id="APP_NAME">%1$s</xliff:g> esté usando demasiada memoria."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite el tamaño de pantalla actual y es posible que funcione de forma inesperada."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar siempre"</string>
     <string name="smv_application" msgid="3307209192155442829">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) ha infringido su política StrictMode autoaplicable."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Prueba de mensajes de emergencia"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Responder"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM no compatible"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM no proporcionada"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM no compatible"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Teléfono no compatible"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Ventana emergente"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Ventana emergente"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"<xliff:g id="NUMBER">%1$d</xliff:g> más"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Para usar este acceso directo, necesitas la última versión de la aplicación"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"No se ha podido restaurar el acceso directo porque la aplicación no es compatible con la función de copia de seguridad y restauración"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"No se ha podido restaurar el acceso directo porque la firma de la aplicación no coincide"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"No se ha podido restaurar el acceso directo"</string>
 </resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index b48afe0..27ceef2 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Teatised"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Poedemo"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-ühendus"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Rakendus töötab"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Rakendused kasutavad akutoidet"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> kasutab akutoidet"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> rakendust kasutab akutoidet"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Sisestusmeetod"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Tekstitoimingud"</string>
     <string name="email" msgid="4560673117055050403">"E-post"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefon"</string>
-    <string name="map" msgid="6068210738233985748">"Maps"</string>
-    <string name="browse" msgid="6993590095938149861">"Brauser"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Kontakt"</string>
+    <string name="dial" msgid="1253998302767701559">"Helista"</string>
+    <string name="map" msgid="6521159124535543457">"Leia"</string>
+    <string name="browse" msgid="1245903488306147205">"Ava"</string>
+    <string name="sms" msgid="4560537514610063430">"Saada sõnum"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Lisa"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Talletusruum saab täis"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Mõned süsteemifunktsioonid ei pruugi töötada"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Süsteemis pole piisavalt talletusruumi. Veenduge, et seadmes oleks 250 MB vaba ruumi, ja käivitage seade uuesti."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Tühista"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Tühista"</string>
-    <string name="close" msgid="2318214661230355730">"SULGE"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Tähelepanu"</string>
     <string name="loading" msgid="7933681260296021180">"Laadimine ..."</string>
     <string name="capital_on" msgid="1544682755514494298">"SEES"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Mõõtkava"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Kuva alati"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Lubage see uuesti valikutes Süsteemiseaded &gt; Rakendused &gt; Allalaaditud."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Rakendus ei reageeri"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"Võimalik, et rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> kasutab liiga palju mälu."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> ei toeta praegust ekraani suuruse seadet ja võib ootamatult käituda."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Kuva alati"</string>
     <string name="smv_application" msgid="3307209192155442829">"Rakendus <xliff:g id="APPLICATION">%1$s</xliff:g> (protsess <xliff:g id="PROCESS">%2$s</xliff:g>) on rikkunud isekehtestatud StrictMode\'i eeskirju."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Hädaabisõnumite test"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Vasta"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM-kaart pole lubatud"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM-kaart on ettevalmistamata"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM-kaart pole lubatud"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Telefon pole lubatud"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Hüpikaken"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Hüpikaken"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"See otsetee nõuab rakenduse uusimat versiooni"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Otseteed ei õnnestunud taastada, kuna rakendus ei toeta varundamist ega taastamist"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Otseteed ei õnnestunud taastada, kuna rakenduse allkiri ei ühti"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Otseteed ei õnnestunud taastada"</string>
 </resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 98b5f5a..ae29264 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Abisuak"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Saltzaileentzako demoa"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB konexioa"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Aplikazio bat abian da"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Bateria kontsumitzen ari diren aplikazioak"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> ari da bateria erabiltzen"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> aplikazio ari dira bateria erabiltzen"</string>
@@ -583,7 +584,7 @@
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Etxekoa"</item>
     <item msgid="869923650527136615">"Mugikorra"</item>
-    <item msgid="7897544654242874543">"Lanekoa"</item>
+    <item msgid="7897544654242874543">"Lantokia"</item>
     <item msgid="1103601433382158155">"Laneko faxa"</item>
     <item msgid="1735177144948329370">"Etxeko faxa"</item>
     <item msgid="603878674477207394">"Bilagailua"</item>
@@ -592,24 +593,24 @@
   </string-array>
   <string-array name="emailAddressTypes">
     <item msgid="8073994352956129127">"Etxekoa"</item>
-    <item msgid="7084237356602625604">"Lanekoa"</item>
+    <item msgid="7084237356602625604">"Lantokia"</item>
     <item msgid="1112044410659011023">"Beste bat"</item>
     <item msgid="2374913952870110618">"Pertsonalizatua"</item>
   </string-array>
   <string-array name="postalAddressTypes">
     <item msgid="6880257626740047286">"Etxekoa"</item>
-    <item msgid="5629153956045109251">"Lanekoa"</item>
+    <item msgid="5629153956045109251">"Lantokia"</item>
     <item msgid="4966604264500343469">"Beste bat"</item>
     <item msgid="4932682847595299369">"Pertsonalizatua"</item>
   </string-array>
   <string-array name="imAddressTypes">
     <item msgid="1738585194601476694">"Etxekoa"</item>
-    <item msgid="1359644565647383708">"Lanekoa"</item>
+    <item msgid="1359644565647383708">"Lantokia"</item>
     <item msgid="7868549401053615677">"Beste bat"</item>
     <item msgid="3145118944639869809">"Pertsonalizatua"</item>
   </string-array>
   <string-array name="organizationTypes">
-    <item msgid="7546335612189115615">"Lanekoa"</item>
+    <item msgid="7546335612189115615">"Lantokia"</item>
     <item msgid="4378074129049520373">"Beste bat"</item>
     <item msgid="3455047468583965104">"Pertsonalizatua"</item>
   </string-array>
@@ -626,7 +627,7 @@
     <string name="phoneTypeCustom" msgid="1644738059053355820">"Pertsonalizatua"</string>
     <string name="phoneTypeHome" msgid="2570923463033985887">"Etxekoa"</string>
     <string name="phoneTypeMobile" msgid="6501463557754751037">"Mugikorra"</string>
-    <string name="phoneTypeWork" msgid="8863939667059911633">"Lanekoa"</string>
+    <string name="phoneTypeWork" msgid="8863939667059911633">"Lantokia"</string>
     <string name="phoneTypeFaxWork" msgid="3517792160008890912">"Laneko faxa"</string>
     <string name="phoneTypeFaxHome" msgid="2067265972322971467">"Etxeko faxa"</string>
     <string name="phoneTypePager" msgid="7582359955394921732">"Bilagailua"</string>
@@ -650,16 +651,16 @@
     <string name="eventTypeOther" msgid="7388178939010143077">"Beste bat"</string>
     <string name="emailTypeCustom" msgid="8525960257804213846">"Pertsonalizatua"</string>
     <string name="emailTypeHome" msgid="449227236140433919">"Etxekoa"</string>
-    <string name="emailTypeWork" msgid="3548058059601149973">"Lanekoa"</string>
+    <string name="emailTypeWork" msgid="3548058059601149973">"Lantokia"</string>
     <string name="emailTypeOther" msgid="2923008695272639549">"Beste bat"</string>
     <string name="emailTypeMobile" msgid="119919005321166205">"Mugikorra"</string>
     <string name="postalTypeCustom" msgid="8903206903060479902">"Pertsonalizatua"</string>
     <string name="postalTypeHome" msgid="8165756977184483097">"Etxekoa"</string>
-    <string name="postalTypeWork" msgid="5268172772387694495">"Lanekoa"</string>
+    <string name="postalTypeWork" msgid="5268172772387694495">"Lantokia"</string>
     <string name="postalTypeOther" msgid="2726111966623584341">"Beste bat"</string>
     <string name="imTypeCustom" msgid="2074028755527826046">"Pertsonalizatua"</string>
     <string name="imTypeHome" msgid="6241181032954263892">"Orri nagusia"</string>
-    <string name="imTypeWork" msgid="1371489290242433090">"Lanekoa"</string>
+    <string name="imTypeWork" msgid="1371489290242433090">"Lantokia"</string>
     <string name="imTypeOther" msgid="5377007495735915478">"Beste bat"</string>
     <string name="imProtocolCustom" msgid="6919453836618749992">"Pertsonalizatua"</string>
     <string name="imProtocolAim" msgid="7050360612368383417">"AIM"</string>
@@ -671,7 +672,7 @@
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
-    <string name="orgTypeWork" msgid="29268870505363872">"Lanekoa"</string>
+    <string name="orgTypeWork" msgid="29268870505363872">"Lantokia"</string>
     <string name="orgTypeOther" msgid="3951781131570124082">"Bestelakoa"</string>
     <string name="orgTypeCustom" msgid="225523415372088322">"Pertsonalizatua"</string>
     <string name="relationTypeCustom" msgid="3542403679827297300">"Pertsonalizatua"</string>
@@ -691,7 +692,7 @@
     <string name="relationTypeSpouse" msgid="394136939428698117">"Ezkonlaguna"</string>
     <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Pertsonalizatua"</string>
     <string name="sipAddressTypeHome" msgid="6093598181069359295">"Etxekoa"</string>
-    <string name="sipAddressTypeWork" msgid="6920725730797099047">"Lanekoa"</string>
+    <string name="sipAddressTypeWork" msgid="6920725730797099047">"Lantokia"</string>
     <string name="sipAddressTypeOther" msgid="4408436162950119849">"Beste bat"</string>
     <string name="quick_contacts_not_available" msgid="746098007828579688">"Ez da kontaktua ikusteko aplikaziorik aurkitu."</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Idatzi PIN kodea"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Idazketa-metodoa"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Testu-ekintzak"</string>
     <string name="email" msgid="4560673117055050403">"Posta"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefonoa"</string>
-    <string name="map" msgid="6068210738233985748">"Mapak"</string>
-    <string name="browse" msgid="6993590095938149861">"Arakatzailea"</string>
-    <string name="sms" msgid="8250353543787396737">"SMSa"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Kontaktua"</string>
+    <string name="dial" msgid="1253998302767701559">"Deitu"</string>
+    <string name="map" msgid="6521159124535543457">"Aurkitu"</string>
+    <string name="browse" msgid="1245903488306147205">"Ireki"</string>
+    <string name="sms" msgid="4560537514610063430">"Bidali mezua"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Gehitu"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Memoria betetzen ari da"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Sistemaren funtzio batzuek ez dute agian funtzionatuko"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sisteman ez dago behar adina memoria. Ziurtatu gutxienez 250 MB erabilgarri dituzula eta, ondoren, berrabiarazi gailua."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Utzi"</string>
     <string name="yes" msgid="5362982303337969312">"Ados"</string>
     <string name="no" msgid="5141531044935541497">"Utzi"</string>
-    <string name="close" msgid="2318214661230355730">"ITXI"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Abisua"</string>
     <string name="loading" msgid="7933681260296021180">"Kargatzen…"</string>
     <string name="capital_on" msgid="1544682755514494298">"AKTIBATUTA"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Eskala"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Erakutsi beti"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Gaitu hori berriro Sistemaren ezarpenak &gt; Aplikazioak &gt; Deskargatutakoak."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikazioak ez du erantzuten"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> memoria gehiegi erabiltzen ari liteke."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak ez du onartzen uneko pantailaren tamaina eta espero ez bezala joka lezake."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Erakutsi beti"</string>
     <string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioak (<xliff:g id="PROCESS">%2$s</xliff:g> prozesua) berak aplikatutako StrictMode gidalerroa urratu du."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Larrialdi-mezuen proba"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Erantzun"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"Ez da onartzen SIM txartela"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Ez dago SIM txartelik"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"Ez da onartzen SIM txartela"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Ez da onartzen telefonoa"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Leiho gainerakorra"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Leiho gainerakorra"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"Beste <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Aplikazioaren bertsio berriena behar da lasterbideak funtziona dezan"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Ezin izan da leheneratu lasterbidea aplikazioak ez duelako onartzen babeskopiak egiteko eta leheneratzeko aukera"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Ezin izan da leheneratu lasterbidea aplikazioaren sinadurak ez datozelako bat"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Ezin izan da leheneratu lasterbidea"</string>
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 9385f58..54b4011 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"هشدارها"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"نمونه برای خرده‌فروشان"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"‏اتصال USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"برنامه درحال اجرا"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"برنامه‌های مصرف‌کننده باتری"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> درحال استفاده کردن از باتری است"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> برنامه درحال استفاده کردن از باتری هستند"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"روش ورودی"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"عملکردهای متنی"</string>
     <string name="email" msgid="4560673117055050403">"رایانامه"</string>
-    <string name="dial" msgid="4204975095406423102">"تلفن"</string>
-    <string name="map" msgid="6068210738233985748">"نقشه‌ها"</string>
-    <string name="browse" msgid="6993590095938149861">"مرورگر"</string>
-    <string name="sms" msgid="8250353543787396737">"پیامک"</string>
-    <string name="add_contact" msgid="7990645816259405444">"مخاطب"</string>
+    <string name="dial" msgid="1253998302767701559">"تماس"</string>
+    <string name="map" msgid="6521159124535543457">"مکان‌یابی"</string>
+    <string name="browse" msgid="1245903488306147205">"باز کردن"</string>
+    <string name="sms" msgid="4560537514610063430">"پیام"</string>
+    <string name="add_contact" msgid="7867066569670597203">"افزودن"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"حافظه درحال پر شدن است"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"برخی از عملکردهای سیستم ممکن است کار نکنند"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"فضای ذخیره‌سازی سیستم کافی نیست. اطمینان حاصل کنید که دارای ۲۵۰ مگابایت فضای خالی هستید و سیستم را راه‌اندازی مجدد کنید."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"لغو"</string>
     <string name="yes" msgid="5362982303337969312">"تأیید"</string>
     <string name="no" msgid="5141531044935541497">"لغو"</string>
-    <string name="close" msgid="2318214661230355730">"بستن"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"توجه"</string>
     <string name="loading" msgid="7933681260296021180">"در حال بارکردن…"</string>
     <string name="capital_on" msgid="1544682755514494298">"روشن"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"مقیاس"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"همیشه نشان داده شود"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"‏در تنظیمات سیستم &gt;برنامه‎ها &gt; مورد بارگیری شده آن را دوباره فعال کنید."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"برنامه پاسخ نمی‌دهد"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> ممکن است حافظه خیلی زیادی مصرف کند."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> از تنظیم فعلی اندازه نمایشگر پشتیبانی نمی‌کند و ممکن است رفتار غیرمنتظره‌ای داشته باشد."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"همیشه نشان داده شود"</string>
     <string name="smv_application" msgid="3307209192155442829">"‏برنامه <xliff:g id="APPLICATION">%1$s</xliff:g> (پردازش <xliff:g id="PROCESS">%2$s</xliff:g>) خط‌مشی StrictMode اجرایی خود را نقض کرده است."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"آزمایش پیام‌های اضطراری"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"پاسخ"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"سیم‌کارت مجاز نیست"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"سیم‌کارت مجوز لازم را ندارد"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"سیم‌کارت مجاز نیست"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"تلفن مجاز نیست"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"پنجره بازشو"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"پنجره بازشو"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"‎+ <xliff:g id="NUMBER">%1$d</xliff:g>‎"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"این میان‌بر به جدیدترین نسخه برنامه نیاز دارد"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"نمی‌توان میان‌بر را بازیابی کرد زیرا برنامه از پشتیبان‌گیری و بازیابی پشتیبانی نمی‌کند"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"به‌علت عدم تطابق امضای برنامه نمی‌توان میان‌بر را بازیابی کرد"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"نمی‌توان میان‌بر را بازیابی کرد"</string>
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index c523452..9ec963b 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Ilmoitukset"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Esittelytila"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-yhteys"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Sovellus käynnissä"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Akkua kuluttavat sovellukset"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> käyttää akkua."</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> sovellusta käyttää akkua."</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Syöttötapa"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Tekstitoiminnot"</string>
     <string name="email" msgid="4560673117055050403">"Sähköposti"</string>
-    <string name="dial" msgid="4204975095406423102">"Puhelin"</string>
-    <string name="map" msgid="6068210738233985748">"Kartat"</string>
-    <string name="browse" msgid="6993590095938149861">"Selain"</string>
-    <string name="sms" msgid="8250353543787396737">"Tekstiviesti"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Yhteystieto"</string>
+    <string name="dial" msgid="1253998302767701559">"Soita"</string>
+    <string name="map" msgid="6521159124535543457">"Paikanna"</string>
+    <string name="browse" msgid="1245903488306147205">"Avaa"</string>
+    <string name="sms" msgid="4560537514610063430">"Viesti"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Lisää"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Tallennustila loppumassa"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Kaikki järjestelmätoiminnot eivät välttämättä toimi"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Tallennustila ei riitä. Varmista, että vapaata tilaa on 250 Mt, ja käynnistä uudelleen."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Peruuta"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Peruuta"</string>
-    <string name="close" msgid="2318214661230355730">"SULJE"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Huomio"</string>
     <string name="loading" msgid="7933681260296021180">"Ladataan…"</string>
     <string name="capital_on" msgid="1544682755514494298">"PÄÄLLÄ"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Asteikko"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Näytä aina"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Ota tämä uudelleen käyttöön kohdassa Järjestelmäasetukset &gt; Sovellukset &gt; Ladattu."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Sovellus ei vastaa"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> saattaa käyttää liikaa muistia."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei tue nykyistä näytön kokoasetusta ja saattaa toimia odottamattomalla tavalla."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Näytä aina"</string>
     <string name="smv_application" msgid="3307209192155442829">"Sovellus <xliff:g id="APPLICATION">%1$s</xliff:g> (prosessi <xliff:g id="PROCESS">%2$s</xliff:g>) on rikkonut itse käyttöön ottamaansa StrictMode-käytäntöä."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Hätäilmoitustesti"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Vastaa"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM-kortti estetty"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM-kortti ei käyttäjien hallinnassa"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM-kortti estetty"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Puhelin estetty"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Ponnahdusikkuna"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Ponnahdusikkuna"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Tämä pikakuvake edellyttää uusinta sovellusta."</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Pikakuvakkeen palautus epäonnistui, koska sovellus ei tue varmuuskopiointia eikä palauttamista."</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Pikakuvakkeen palautus epäonnistui sovelluksen allekirjoituksen yhteensopimattomuuden vuoksi."</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Pikakuvakkeen palautus epäonnistui."</string>
 </resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 4f6b3aa..16283e7 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertes"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Démo en magasin"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Connexion USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Application en cours d\'exécution"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Applications qui sollicitent la pile"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> sollicite la pile"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> applications sollicitent la pile"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Mode de saisie"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Actions sur le texte"</string>
     <string name="email" msgid="4560673117055050403">"Courriel"</string>
-    <string name="dial" msgid="4204975095406423102">"Téléphone"</string>
-    <string name="map" msgid="6068210738233985748">"Cartes"</string>
-    <string name="browse" msgid="6993590095938149861">"Navigateur"</string>
-    <string name="sms" msgid="8250353543787396737">"Messagerie texte"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Contact"</string>
+    <string name="dial" msgid="1253998302767701559">"Appel"</string>
+    <string name="map" msgid="6521159124535543457">"Localiser"</string>
+    <string name="browse" msgid="1245903488306147205">"Ouvert"</string>
+    <string name="sms" msgid="4560537514610063430">"Message"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Ajouter"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Espace de stockage bientôt saturé"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Il est possible que certaines fonctionnalités du système ne soient pas opérationnelles."</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Espace de stockage insuffisant pour le système. Assurez-vous de disposer de 250 Mo d\'espace libre, puis redémarrez."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Annuler"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Annuler"</string>
-    <string name="close" msgid="2318214661230355730">"FERMER"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Attention"</string>
     <string name="loading" msgid="7933681260296021180">"Chargement en cours..."</string>
     <string name="capital_on" msgid="1544682755514494298">"OUI"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Redimensionner"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Toujours afficher"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Réactivez ce mode en accédant à Paramètres système &gt; Applications &gt; Téléchargements"</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"L\'application ne répond pas"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> utilise peut-être trop de mémoire."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec le paramètre de taille d\'affichage actuel et peut se comporter de manière inattendue."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Toujours afficher"</string>
     <string name="smv_application" msgid="3307209192155442829">"L\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>) a enfreint ses propres règles du mode strict."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test de messages d\'urgence"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Répondre"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"Carte SIM non autorisée"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Carte SIM non configurée"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"Carte SIM non autorisée"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Téléphone non autorisé"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Fenêtre contextuelle"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Fenêtre contextuelle"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Ce raccourci nécessite la dernière version de l\'application"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Impossible de restaurer le raccourci, car l\'application ne prend pas en charge la sauvegarde et la restauration"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Impossible de restaurer le raccourci en raison d\'une erreur de correspondance des signature d\'applications"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Impossible de restaurer le raccourci"</string>
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 92838e4..34e761b 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertes"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Démonstration en magasin"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Connexion USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Application en cours d\'exécution"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Applications utilisant la batterie"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> utilise la batterie"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> applications utilisent la batterie"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Mode de saisie"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Actions sur le texte"</string>
     <string name="email" msgid="4560673117055050403">"E-mail"</string>
-    <string name="dial" msgid="4204975095406423102">"Téléphone"</string>
-    <string name="map" msgid="6068210738233985748">"Cartes"</string>
-    <string name="browse" msgid="6993590095938149861">"Navigateur"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Contact"</string>
+    <string name="dial" msgid="1253998302767701559">"Appeler"</string>
+    <string name="map" msgid="6521159124535543457">"Localiser"</string>
+    <string name="browse" msgid="1245903488306147205">"Ouvrir"</string>
+    <string name="sms" msgid="4560537514610063430">"Envoyer un message"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Ajouter"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Espace de stockage bientôt saturé"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Il est possible que certaines fonctionnalités du système ne soient pas opérationnelles."</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Espace de stockage insuffisant pour le système. Assurez-vous de disposer de 250 Mo d\'espace libre, puis redémarrez."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Annuler"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Annuler"</string>
-    <string name="close" msgid="2318214661230355730">"FERMER"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Attention"</string>
     <string name="loading" msgid="7933681260296021180">"Chargement…"</string>
     <string name="capital_on" msgid="1544682755514494298">"OUI"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Mise à l\'échelle"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Toujours afficher"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Réactivez ce mode en accédant à Paramètres système &gt; Applications &gt; Téléchargements"</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"L\'application ne répond pas"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> utilise peut-être trop de mémoire."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec le paramètre de taille d\'affichage actuel et peut présenter un comportement inattendu."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Toujours afficher"</string>
     <string name="smv_application" msgid="3307209192155442829">"L\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>) a enfreint ses propres règles du mode strict."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test de messages d\'urgence"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Répondre"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"Carte SIM non autorisée"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Carte SIM non configurée"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"Carte SIM non autorisée"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Téléphone non autorisé"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Fenêtre pop-up"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Fenêtre pop-up"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"<xliff:g id="NUMBER">%1$d</xliff:g> autres"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Ce raccourci nécessite la dernière version de l\'application"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Impossible de restaurer le raccourci, car l\'application n\'accepte pas la sauvegarde et la restauration"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Impossible de restaurer le raccourci en raison de la non-correspondance de la signature de l\'application"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Impossible de restaurer le raccourci"</string>
 </resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 6d56700..e3b93cb 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demostración comercial"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"conexión USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Estase executando a aplicación"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Aplicacións que consumen batería"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"A aplicación <xliff:g id="APP_NAME">%1$s</xliff:g> está consumindo batería"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> aplicacións están consumindo batería"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Método de entrada"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Accións de texto"</string>
     <string name="email" msgid="4560673117055050403">"Correo electrónico"</string>
-    <string name="dial" msgid="4204975095406423102">"Teléfono"</string>
-    <string name="map" msgid="6068210738233985748">"Mapas"</string>
-    <string name="browse" msgid="6993590095938149861">"Navegador"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Contacto"</string>
+    <string name="dial" msgid="1253998302767701559">"Chamar"</string>
+    <string name="map" msgid="6521159124535543457">"Localizar"</string>
+    <string name="browse" msgid="1245903488306147205">"Abrir"</string>
+    <string name="sms" msgid="4560537514610063430">"Mensaxe"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Engadir"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Estase esgotando o espazo de almacenamento"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"É posible que algunhas funcións do sistema non funcionen"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Non hai almacenamento suficiente para o sistema. Asegúrate de ter un espazo libre de 250 MB e reinicia o dispositivo."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
     <string name="yes" msgid="5362982303337969312">"Aceptar"</string>
     <string name="no" msgid="5141531044935541497">"Cancelar"</string>
-    <string name="close" msgid="2318214661230355730">"PECHAR"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Atención"</string>
     <string name="loading" msgid="7933681260296021180">"Cargando..."</string>
     <string name="capital_on" msgid="1544682755514494298">"SI"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar sempre"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Volve activar esta función en Configuración do sistema &gt; Aplicacións &gt; Descargadas."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"A aplicación non responde"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"É posible que <xliff:g id="APP_NAME">%1$s</xliff:g> estea utilizando demasiada memoria."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> non admite a configuración do tamaño de pantalla actual e quizais presente un comportamento inesperado."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar sempre"</string>
     <string name="smv_application" msgid="3307209192155442829">"A aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) infrinxiu a súa política StrictMode autoaplicada."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Proba de mensaxes de urxencia"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Responder"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"Non se admite a tarxeta SIM"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Non se introduciu ningunha tarxeta SIM"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"Non se admite a tarxeta SIM"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Non se admite o teléfono"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Ventá emerxente"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Ventá emerxente"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"<xliff:g id="NUMBER">%1$d</xliff:g> máis"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Para utilizar este atallo, necesítase a versión máis recente da aplicación"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Non se puido restaurar o atallo porque a aplicación non é compatible coa restauración e a copia de seguranza"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Non se puido restaurar o atallo porque a sinatura da aplicación non coincide"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Non se puido restaurar o atallo"</string>
 </resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index afc082b..d1c3700 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"ચેતવણીઓ"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"રિટેલ ડેમો"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB કનેક્શન"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"ઍપ ચાલી રહ્યું છે"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"ઍપ બૅટરીનો વપરાશ કરી રહ્યાં છે"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> બૅટરીનો ઉપયોગ કરી રહ્યું છે"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> ઍપ બૅટરીનો ઉપયોગ કરી રહ્યાં છે"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"ઇનપુટ પદ્ધતિ"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"ટેક્સ્ટ ક્રિયાઓ"</string>
     <string name="email" msgid="4560673117055050403">"ઇમેઇલ"</string>
-    <string name="dial" msgid="4204975095406423102">"ફોન"</string>
-    <string name="map" msgid="6068210738233985748">"નકશા"</string>
-    <string name="browse" msgid="6993590095938149861">"બ્રાઉઝર"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"સંપર્ક"</string>
+    <string name="dial" msgid="1253998302767701559">"કૉલ કરો"</string>
+    <string name="map" msgid="6521159124535543457">"શોધો"</string>
+    <string name="browse" msgid="1245903488306147205">"ખોલો"</string>
+    <string name="sms" msgid="4560537514610063430">"સંદેશ મોકલો"</string>
+    <string name="add_contact" msgid="7867066569670597203">"ઉમેરો"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"સ્ટોરેજ સ્થાન સમાપ્ત થયું"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"કેટલાક સિસ્ટમ કાર્યો કામ કરી શકશે નહીં"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"સિસ્ટમ માટે પર્યાપ્ત સ્ટોરેજ નથી. ખાતરી કરો કે તમારી પાસે 250MB ખાલી સ્થાન છે અને ફરીથી પ્રારંભ કરો."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"રદ કરો"</string>
     <string name="yes" msgid="5362982303337969312">"ઓકે"</string>
     <string name="no" msgid="5141531044935541497">"રદ કરો"</string>
-    <string name="close" msgid="2318214661230355730">"બંધ કરો"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"ધ્યાન આપો"</string>
     <string name="loading" msgid="7933681260296021180">"લોડ કરી રહ્યું છે…"</string>
     <string name="capital_on" msgid="1544682755514494298">"ચાલુ"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"સ્કેલ"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"હંમેશા બતાવો"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"આને સિસ્ટમ સેટિંગ્સ &gt; ઍપ્લિકેશનો &gt; ડાઉનલોડ કરેલમાં ફરીથી સક્ષમ કરો."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"ઍપ પ્રતિસાદ આપી રહી નથી"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> ખૂબ વધારે મેમરીનો ઉપયોગ કરતી હોઈ શકે."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> વર્તમાન પ્રદર્શન કદની સેટિંગનું સમર્થન કરતું નથી અને અનપેક્ષિત રીતે વર્તી શકે છે."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"હંમેશાં બતાવો"</string>
     <string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> ઍપ્લિકેશન (<xliff:g id="PROCESS">%2$s</xliff:g> પ્રક્રિયા)એ તેની સ્વ-લાગુ કરેલ StrictMode નીતિનું ઉલ્લંઘન કર્યું છે."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"કટોકટી સંદેશાઓનું પરીક્ષણ"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"જવાબ આપો"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"સિમ મંજૂર નથી"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIMની જોગવાઈ કરી નથી"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"સિમ મંજૂર નથી"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"ફોન મંજૂર નથી"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"પૉપઅપ વિંડો"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"પૉપઅપ વિંડો"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"આ શૉર્ટકટ માટે નવી ઍપ જરૂરી છે"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"શૉર્ટકટ ફરી મેળવી શકાયો નથી કારણ કે ઍપ બૅકઅપ અને ફરી મેળવવાનું સમર્થન કરતી નથી"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"શૉર્ટકટ ફરી મેળવી શકાયો નથી કારણ કે ઍપમાં છે તે સહી મેળ ખાતી નથી"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"શૉર્ટકટ પાછો મેળવી શકાયો નથી"</string>
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 925565a..0ba0733d 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"सूचनाएं"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"खुदरा डेमो"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB कनेक्शन"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"ऐप अभी इस्तेमाल हो रहा है"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"बैटरी की खपत करने वाले ऐप"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> बैटरी का इस्तेमाल कर रहा है"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> ऐप बैटरी का इस्तेमाल कर रहे हैं"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"इनपुट विधि"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"लेख क्रियाएं"</string>
     <string name="email" msgid="4560673117055050403">"ईमेल करें"</string>
-    <string name="dial" msgid="4204975095406423102">"फ़ोन"</string>
-    <string name="map" msgid="6068210738233985748">"मानचित्र"</string>
-    <string name="browse" msgid="6993590095938149861">"ब्राउज़र"</string>
-    <string name="sms" msgid="8250353543787396737">"मैसेज (एसएमएस)"</string>
-    <string name="add_contact" msgid="7990645816259405444">"संपर्क"</string>
+    <string name="dial" msgid="1253998302767701559">"कॉल करें"</string>
+    <string name="map" msgid="6521159124535543457">"पता लगाएं"</string>
+    <string name="browse" msgid="1245903488306147205">"खोलें"</string>
+    <string name="sms" msgid="4560537514610063430">"मैसेज"</string>
+    <string name="add_contact" msgid="7867066569670597203">"जोड़ें"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"मेमोरी में जगह नहीं बची है"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"हो सकता है कुछ सिस्टम फ़ंक्शन कार्य न करें"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"सिस्टम के लिए ज़रूरी मेमोरी नहीं है. पक्का करें कि आपके पास 250एमबी की खाली जगह है और फिर से शुरू करें."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"रद्द करें"</string>
     <string name="yes" msgid="5362982303337969312">"ठीक है"</string>
     <string name="no" msgid="5141531044935541497">"रद्द करें"</string>
-    <string name="close" msgid="2318214661230355730">"बंद करें"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"ध्यान दें"</string>
     <string name="loading" msgid="7933681260296021180">"लोड हो रहे हैं..."</string>
     <string name="capital_on" msgid="1544682755514494298">"ऑन"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"स्केल"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"हमेशा दिखाएं"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"इसे सिस्‍टम सेटिंग &gt; ऐप &gt; डाउनलोड किए गए में फिर से चालू करें."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"ऐप काम नहीं कर रहा है"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> शायद बहुत ज़्यादा मेमोरी इस्तेमाल कर रहा है."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> वर्तमान स्क्रीन के आकार की सेटिंग का समर्थन नहीं करता है और अनपेक्षित रूप से व्यवहार कर सकता है."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"हमेशा दिखाएं"</string>
     <string name="smv_application" msgid="3307209192155442829">"ऐप्स <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ने उसकी स्‍वयं लागू होने वाली StrictMode नीति का उल्‍लंघन किया है."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"आपातकालीन संदेश परीक्षण"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"जवाब दें"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM की अनुमति नहीं है"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM का प्रावधान नहीं किया गया है"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM की अनुमति नहीं है"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"फ़ोन की अनुमति नहीं है"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"पॉपअप विंडो"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"पॉपअप विंडो"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"इस शॉर्टकट वाला ऐप चलाने के लिए इसका नया वर्शन डाउनलोड करें"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"शॉर्टकट बहाल नहीं किया जा सका क्योंकि इस ऐप में बैकअप लेने और उसे बहाल करने की सुविधा नहीं है"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"ऐप का हस्ताक्षर अलग होने के कारण शॉर्टकट बहाल नहीं किया जा सका"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"शॉर्टकट बहाल नहीं किया जा सका"</string>
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index a7fa3ce..1b92d58 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -252,6 +252,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Upozorenja"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Prodajni demo-način"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB veza"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Izvodi se aplikacija"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Aplikacije troše bateriju"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> koristi bateriju"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"Broj aplikacija koje koriste bateriju: <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
@@ -998,11 +999,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Način unosa"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Radnje s tekstom"</string>
     <string name="email" msgid="4560673117055050403">"E-pošta"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefon"</string>
-    <string name="map" msgid="6068210738233985748">"Karte"</string>
-    <string name="browse" msgid="6993590095938149861">"Preglednik"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Kontakt"</string>
+    <string name="dial" msgid="1253998302767701559">"Poziv"</string>
+    <string name="map" msgid="6521159124535543457">"Lociraj"</string>
+    <string name="browse" msgid="1245903488306147205">"Otvori"</string>
+    <string name="sms" msgid="4560537514610063430">"Poruka"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Dodaj"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ponestaje prostora za pohranu"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Neke sistemske funkcije možda neće raditi"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nema dovoljno pohrane za sustav. Oslobodite 250 MB prostora i pokrenite uređaj ponovo."</string>
@@ -1012,7 +1013,6 @@
     <string name="cancel" msgid="6442560571259935130">"Odustani"</string>
     <string name="yes" msgid="5362982303337969312">"U redu"</string>
     <string name="no" msgid="5141531044935541497">"Odustani"</string>
-    <string name="close" msgid="2318214661230355730">"ZATVORI"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Pažnja"</string>
     <string name="loading" msgid="7933681260296021180">"Učitavanje…"</string>
     <string name="capital_on" msgid="1544682755514494298">"Uklj."</string>
@@ -1069,8 +1069,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Mjerilo"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Uvijek prikaži"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Omogućiti to ponovo u Postavkama sustava &gt; Aplikacije &gt; Preuzimanja."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikacija ne reagira"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> možda upotrebljava previše memorije."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava trenutačnu postavku veličine zaslona i može se ponašati neočekivano."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Uvijek prikaži"</string>
     <string name="smv_application" msgid="3307209192155442829">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) prekršila je vlastito pravilo StrictMode."</string>
@@ -1819,11 +1817,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test hitnih poruka"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Odgovori"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM nije dopušten"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Ne pruža se usluga za SIM"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM nije dopušten"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Telefon nije dopušten"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Skočni prozor"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Skočni prozor"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"još <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Za taj je prečac potrebna najnovija aplikacija"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Vraćanje prečaca nije uspjelo jer aplikacija ne podržava sigurnosno kopiranje i vraćanje"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Vraćanje prečaca nije uspjelo zbog nepodudaranja potpisa aplikacije"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Vraćanje prečaca nije uspjelo"</string>
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index b1ef463..b1e5cb4 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Értesítések"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Kiskereskedelmi bemutató"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-kapcsolat"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Jelenleg futó alkalmazás"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Akkumulátort használó alkalmazások"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás használja az akkumulátort"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> alkalmazás használja az akkumulátort"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Beviteli mód"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Műveletek szöveggel"</string>
     <string name="email" msgid="4560673117055050403">"E-mail"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefon"</string>
-    <string name="map" msgid="6068210738233985748">"Térkép"</string>
-    <string name="browse" msgid="6993590095938149861">"Böngésző"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Névjegy"</string>
+    <string name="dial" msgid="1253998302767701559">"Hívás"</string>
+    <string name="map" msgid="6521159124535543457">"Helymeghatározás"</string>
+    <string name="browse" msgid="1245903488306147205">"Megnyitás"</string>
+    <string name="sms" msgid="4560537514610063430">"Üzenet"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Hozzáadás"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Kevés a szabad terület"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Előfordulhat, hogy néhány rendszerfunkció nem működik."</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nincs elegendő tárhely a rendszerhez. Győződjön meg arról, hogy rendelkezik 250 MB szabad területtel, majd kezdje elölről."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Mégse"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Mégse"</string>
-    <string name="close" msgid="2318214661230355730">"BEZÁRÁS"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Figyelem"</string>
     <string name="loading" msgid="7933681260296021180">"Betöltés..."</string>
     <string name="capital_on" msgid="1544682755514494298">"Be"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skála"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Mindig megjelenik"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Újbóli engedélyezés itt: Rendszerbeállítások &gt; Alkalmazások &gt; Letöltve."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Az alkalmazás nem válaszol"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"Lehetséges, hogy a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> túl sok memóriát használ."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás nem támogatja a képernyőméret jelenlegi beállításait, ezért nem várt módon viselkedhet."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Mindig megjelenik"</string>
     <string name="smv_application" msgid="3307209192155442829">"A(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazás (<xliff:g id="PROCESS">%2$s</xliff:g> folyamat) megsértette az általa kényszerített Szigorú üzemmód irányelvet."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Vészhelyzetben küldött üzenetek tesztelése"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Válasz"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"A SIM-kártya nem engedélyezett"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Nem engedélyezett SIM-kártya"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"A SIM-kártya nem engedélyezett"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"A telefon nem engedélyezett"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Előugró ablak"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Előugró ablak"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"A parancsikon működéséhez az alkalmazás legfrissebb verziójára van szükség"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Nem sikerült visszaállítani a parancsikont, mert az alkalmazás nem támogatja a biztonsági mentést és visszaállítást"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Nem sikerült visszaállítani a parancsikont, mert az alkalmazás-aláírás nem egyezik"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Nem sikerült visszaállítani a parancsikont"</string>
 </resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index b367c67..c950c40 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Ծանուցումներ"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Խանութի ցուցադրական ռեժիմ"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB կապակցում"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Հավելվածն աշխատում է"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Մարտկոցի լիցքը ծախսող հավելվածներ"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"«<xliff:g id="APP_NAME">%1$s</xliff:g>» հավելվածը ծախսում է մարտկոցի լիցքը"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> հավելված ծախսում է մարտկոցի լիցքը"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Մուտքագրման եղանակը"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Տեքստի գործողությունները"</string>
     <string name="email" msgid="4560673117055050403">"Էլփոստ"</string>
-    <string name="dial" msgid="4204975095406423102">"Հեռախոս"</string>
-    <string name="map" msgid="6068210738233985748">"Քարտեզներ"</string>
-    <string name="browse" msgid="6993590095938149861">"Դիտարկիչ"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Կոնտակտ"</string>
+    <string name="dial" msgid="1253998302767701559">"Զանգել"</string>
+    <string name="map" msgid="6521159124535543457">"Գտնել քարտեզում"</string>
+    <string name="browse" msgid="1245903488306147205">"Բացել"</string>
+    <string name="sms" msgid="4560537514610063430">"SMS գրել"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Ավելացնել"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Հիշողությունը սպառվում է"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Որոշ գործառույթներ կարող են չաշխատել"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Համակարգի համար բավարար հիշողություն չկա: Համոզվեք, որ ունեք 250ՄԲ ազատ տարածություն և վերագործարկեք:"</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Չեղարկել"</string>
     <string name="yes" msgid="5362982303337969312">"Լավ"</string>
     <string name="no" msgid="5141531044935541497">"Չեղարկել"</string>
-    <string name="close" msgid="2318214661230355730">"ՓԱԿԵԼ"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Ուշադրություն"</string>
     <string name="loading" msgid="7933681260296021180">"Բեռնում..."</string>
     <string name="capital_on" msgid="1544682755514494298">"I"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Աստիճանակարգել"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Միշտ ցույց տալ"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Կրկին ակտիվացնել սա Համակարգի կարգավորումներում &amp;gt Ծրագրեր &gt; Ներբեռնումներ:"</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Հավելվածը չի արձագանքում"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"Հնարավոր է, որ <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը չափազանց շատ հիշողություն է օգտագործում:"</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը չի աջակցում Էկրանի չափի ընթացիկ կարգավորումները, ինչի պատճառով կարող են խնդիրներ առաջանալ:"</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Միշտ ցուցադրել"</string>
     <string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> ծրագիրը (գործընթաց <xliff:g id="PROCESS">%2$s</xliff:g>) խախտել է իր ինքնահարկադրված Խիստ ռեժիմ  քաղաքականությունը:"</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Արտակարգ իրավիճակների հաղորդագրությունների թեստ"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Պատասխանել"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM քարտի օգտագործումն արգելված է"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM քարտը նախապատրաստված չէ"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM քարտի օգտագործումն արգելված է"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Հեռախոսի օգտագործումն արգելված է"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Հայտնվող պատուհան"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Հայտնվող պատուհան"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Այս դյուրանցման համար անհրաժեշտ է հավելվածի վերջին տարբերակը"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Չհաջողվեց վերականգնել դյուրանցումը, քանի որ հավելվածում չի աջակցվում պահուստավորման և վերականգնման գործառույթը"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Չհաջողվեց վերականգնել դյուրանցումը, քանի որ հավելվածների ստորագրությունները տարբեր են"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Չհաջողվեց վերականգնել դյուրանցումը"</string>
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index a9d4316..fe515d3 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Notifikasi"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demo promo"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Sambungan USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Aplikasi berjalan"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Aplikasi yang menggunakan baterai"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang menggunakan baterai"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> aplikasi sedang meggunakan baterai"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Metode masukan"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Tindakan teks"</string>
     <string name="email" msgid="4560673117055050403">"Email"</string>
-    <string name="dial" msgid="4204975095406423102">"Telepon"</string>
-    <string name="map" msgid="6068210738233985748">"Peta"</string>
-    <string name="browse" msgid="6993590095938149861">"Browser"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Kontak"</string>
+    <string name="dial" msgid="1253998302767701559">"Panggil"</string>
+    <string name="map" msgid="6521159124535543457">"Temukan"</string>
+    <string name="browse" msgid="1245903488306147205">"Buka"</string>
+    <string name="sms" msgid="4560537514610063430">"Pesan"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Tambahkan"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ruang penyimpanan hampir habis"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Beberapa fungsi sistem mungkin tidak dapat bekerja"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Penyimpanan tidak cukup untuk sistem. Pastikan Anda memiliki 250 MB ruang kosong, lalu mulai ulang."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Batal"</string>
     <string name="yes" msgid="5362982303337969312">"Oke"</string>
     <string name="no" msgid="5141531044935541497">"Batal"</string>
-    <string name="close" msgid="2318214661230355730">"TUTUP"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Perhatian"</string>
     <string name="loading" msgid="7933681260296021180">"Memuat..."</string>
     <string name="capital_on" msgid="1544682755514494298">"AKTIF"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skala"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Selalu tampilkan"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktifkan kembali dialog ini di Setelan sistem &gt; Apl &gt; Terdownload."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikasi tidak merespons"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> mungkin menggunakan terlalu banyak memori."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak mendukung setelan Ukuran layar saat ini dan dapat menunjukkan perilaku yang tak diharapkan."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Selalu tampilkan"</string>
     <string name="smv_application" msgid="3307209192155442829">"Apl <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) telah melanggar kebijakan StrictMode yang diberlakukannya sendiri."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Tes pesan darurat"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Balas"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM tidak diizinkan"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM tidak di-provisioning"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM tidak diizinkan"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Ponsel tidak diizinkan"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Jendela Pop-up"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Jendela Pop-up"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Pintasan ini memerlukan aplikasi terbaru"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Tidak dapat memulihkan pintasan karena aplikasi tidak mendukung backup dan pulihkan"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Tidak dapat memulihkan pintasan karena tanda tangan aplikasi tidak cocok"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Tidak dapat memulihkan pintasan."</string>
 </resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 3cdee4c..400228a 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Tilkynningar"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Kynningarútgáfa fyrir verslanir"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-tenging"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Forrit er í gangi"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Forrit sem nota rafhlöðuorku"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> notar rafhlöðuorku"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> forrit nota rafhlöðuorku"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Innsláttaraðferð"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Textaaðgerðir"</string>
     <string name="email" msgid="4560673117055050403">"Tölvupóstur"</string>
-    <string name="dial" msgid="4204975095406423102">"Sími"</string>
-    <string name="map" msgid="6068210738233985748">"Kort"</string>
-    <string name="browse" msgid="6993590095938149861">"Vafri"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS-skilaboð"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Tengiliður"</string>
+    <string name="dial" msgid="1253998302767701559">"Símtal"</string>
+    <string name="map" msgid="6521159124535543457">"Staðsetja"</string>
+    <string name="browse" msgid="1245903488306147205">"Opna"</string>
+    <string name="sms" msgid="4560537514610063430">"Skilaboð"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Bæta við"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Geymslurýmið er senn á þrotum"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Sumir kerfiseiginleikar kunna að vera óvirkir"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Ekki nægt geymslurými fyrir kerfið. Gakktu úr skugga um að 250 MB séu laus og endurræstu."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Hætta við"</string>
     <string name="yes" msgid="5362982303337969312">"Í lagi"</string>
     <string name="no" msgid="5141531044935541497">"Hætta við"</string>
-    <string name="close" msgid="2318214661230355730">"LOKA"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Athugaðu"</string>
     <string name="loading" msgid="7933681260296021180">"Hleður…"</string>
     <string name="capital_on" msgid="1544682755514494298">"KVEIKT"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Breyta stærð"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Sýna alltaf"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Þú getur kveikt aftur á þessu undir Kerfisstillingar &gt; Forrit &gt; Sótt."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Forritið svarar ekki"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> notar hugsanlega of mikið minni."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> styður ekki núverandi skjástærðarstillingu og gæti því ekki virkað sem skyldi."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Sýna alltaf"</string>
     <string name="smv_application" msgid="3307209192155442829">"Forritið <xliff:g id="APPLICATION">%1$s</xliff:g> (ferli <xliff:g id="PROCESS">%2$s</xliff:g>) hefur brotið gegn eigin StrictMode-stefnu."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Prófun neyðarskilaboða"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Svara"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM-kort er ekki leyft"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM-korti ekki úthlutað"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM-kort er ekki leyft"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Sími er ekki leyfður"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Sprettigluggi"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Sprettigluggi"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Nýjasta útgáfa forritsins þarf að vera til staðar til að þessi flýtileið virki"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Ekki var hægt að endurheimta flýtileið vegna þess að forritið styður ekki öryggisafritun og endurheimt"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Ekki var hægt að endurheimta flýtileið vegna þess að undirskriftir forrita passa ekki saman"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Ekki var hægt að endurheimta flýtileið"</string>
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index f08ed1b..283d876 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Avvisi"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demo retail"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Connessione USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"App in esecuzione"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"App che consumano la batteria"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> sta consumando la batteria"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> app stanno consumando la batteria"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Metodo inserimento"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Azioni testo"</string>
     <string name="email" msgid="4560673117055050403">"Invia una email"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefono"</string>
-    <string name="map" msgid="6068210738233985748">"Mappe"</string>
-    <string name="browse" msgid="6993590095938149861">"Browser"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Contatto"</string>
+    <string name="dial" msgid="1253998302767701559">"Chiama"</string>
+    <string name="map" msgid="6521159124535543457">"Localizza"</string>
+    <string name="browse" msgid="1245903488306147205">"Apri"</string>
+    <string name="sms" msgid="4560537514610063430">"Invia messaggio"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Aggiungi"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Spazio di archiviazione in esaurimento"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Alcune funzioni di sistema potrebbero non funzionare"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Memoria insufficiente per il sistema. Assicurati di avere 250 MB di spazio libero e riavvia."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Annulla"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Annulla"</string>
-    <string name="close" msgid="2318214661230355730">"CHIUDI"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Attenzione"</string>
     <string name="loading" msgid="7933681260296021180">"Caricamento..."</string>
     <string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scala"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostra sempre"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Riattivala in Impostazioni di sistema &gt; Applicazioni &gt; Scaricate."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"L\'app non risponde"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"Probabilmente <xliff:g id="APP_NAME">%1$s</xliff:g> utilizza troppa memoria."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> non supporta le dimensioni di visualizzazione attualmente impostate e potrebbe comportarsi in modo imprevisto."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostra sempre"</string>
     <string name="smv_application" msgid="3307209192155442829">"L\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) ha violato la norma StrictMode autoimposta."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Testo messaggi di emergenza"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Rispondi"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"Scheda SIM non consentita"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Scheda SIM non predisposta"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"Scheda SIM non consentita"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Telefono non consentito"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Finestra popup"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Finestra popup"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Per questa scorciatoia è necessaria l\'app più recente"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Impossibile ripristinare la scorciatoia perché l\'app non supporta il backup e il ripristino"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Impossibile ripristinare la scorciatoia perché la firma dell\'app non corrisponde"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Impossibile ripristinare la scorciatoia"</string>
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 98b17dc..5545c43 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -255,6 +255,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"התראות"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"הדגמה לקמעונאים"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"‏חיבור USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"אפליקציה פועלת"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"אפליקציות שמרוקנות את הסוללה"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> משתמשת בסוללה"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> אפליקציות משתמשות בסוללה"</string>
@@ -1018,11 +1019,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"שיטת קלט"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"פעולות טקסט"</string>
     <string name="email" msgid="4560673117055050403">"אימייל"</string>
-    <string name="dial" msgid="4204975095406423102">"טלפון"</string>
-    <string name="map" msgid="6068210738233985748">"מפות"</string>
-    <string name="browse" msgid="6993590095938149861">"דפדפן"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"איש קשר"</string>
+    <string name="dial" msgid="1253998302767701559">"שיחה"</string>
+    <string name="map" msgid="6521159124535543457">"איתור"</string>
+    <string name="browse" msgid="1245903488306147205">"פתיחה"</string>
+    <string name="sms" msgid="4560537514610063430">"הודעה"</string>
+    <string name="add_contact" msgid="7867066569670597203">"הוספה"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"שטח האחסון אוזל"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"ייתכן שפונקציות מערכת מסוימות לא יפעלו"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"‏אין מספיק שטח אחסון עבור המערכת. ודא שיש לך שטח פנוי בגודל 250MB התחל שוב."</string>
@@ -1032,7 +1033,6 @@
     <string name="cancel" msgid="6442560571259935130">"ביטול"</string>
     <string name="yes" msgid="5362982303337969312">"אישור"</string>
     <string name="no" msgid="5141531044935541497">"ביטול"</string>
-    <string name="close" msgid="2318214661230355730">"סגירה"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"זהירות"</string>
     <string name="loading" msgid="7933681260296021180">"טוען..."</string>
     <string name="capital_on" msgid="1544682755514494298">"מופעל"</string>
@@ -1089,8 +1089,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"שינוי קנה-מידה"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"הצג תמיד"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"‏אפשר תכונה זו מחדש ב\'הגדרות מערכת\' &lt;‏ Google Apps‏ &lt; \'הורדות\'."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"האפליקציה לא מגיבה"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"ייתכן שהאפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> משתמשת ביותר מדי שטח זיכרון."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> אינו תומך בהגדרת הגודל הנוכחית של התצוגה, והתנהגותו עשויה להיות בלתי צפויה."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"הצג תמיד"</string>
     <string name="smv_application" msgid="3307209192155442829">"‏האפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g> (תהליך <xliff:g id="PROCESS">%2$s</xliff:g>) הפר את מדיניות StrictMode באכיפה עצמית שלו."</string>
@@ -1854,11 +1852,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"בדיקה של הודעות חירום"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"השב"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"‏כרטיס ה-SIM לא מורשה"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"‏כרטיס ה-SIM לא מזוהה"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"‏כרטיס ה-SIM לא מורשה"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"הטלפון לא מורשה"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"חלון קופץ"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"חלון קופץ"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"קיצור דרך זה דורש את האפליקציה העדכנית ביותר"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"לא ניתן היה לשחזר את קיצור הדרך מפני שהאפליקציה אינה תומכת בגיבוי ובשחזור"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"לא ניתן היה לשחזר את קיצור הדרך עקב חוסר התאמה בחתימה על האפליקציות"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"לא ניתן היה לשחזר את קיצור הדרך"</string>
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 66ce56c..baff85c 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"通知"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"販売店デモ"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB 接続"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"アプリを実行しています"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"アプリが電池を消費しています"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」が電池を使用しています"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> 個のアプリが電池を使用しています"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"入力方法"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"テキスト操作"</string>
     <string name="email" msgid="4560673117055050403">"メール"</string>
-    <string name="dial" msgid="4204975095406423102">"電話"</string>
-    <string name="map" msgid="6068210738233985748">"マップ"</string>
-    <string name="browse" msgid="6993590095938149861">"ブラウザ"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"連絡先"</string>
+    <string name="dial" msgid="1253998302767701559">"電話"</string>
+    <string name="map" msgid="6521159124535543457">"探す"</string>
+    <string name="browse" msgid="1245903488306147205">"開く"</string>
+    <string name="sms" msgid="4560537514610063430">"メッセージ"</string>
+    <string name="add_contact" msgid="7867066569670597203">"追加"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"空き容量わずか"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"一部のシステム機能が動作しない可能性があります"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"システムに十分な容量がありません。250MBの空き容量を確保して再起動してください。"</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"キャンセル"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"キャンセル"</string>
-    <string name="close" msgid="2318214661230355730">"閉じる"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"注意"</string>
     <string name="loading" msgid="7933681260296021180">"読み込んでいます..."</string>
     <string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"スケール"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"常に表示"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"[システム設定]&gt;[アプリ]&gt;[ダウンロード済み]で再度有効にします。"</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"このアプリは応答していません"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」のメモリの使用量は多すぎる可能性があります。"</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」は現在の [表示サイズ] 設定に対応していないため、予期しない動作が発生するおそれがあります。"</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"常に表示"</string>
     <string name="smv_application" msgid="3307209192155442829">"アプリ「<xliff:g id="APPLICATION">%1$s</xliff:g>」(プロセス「<xliff:g id="PROCESS">%2$s</xliff:g>」)でStrictModeポリシー違反がありました。"</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"テスト用緊急速報メール"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"返信"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM 使用不可"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM には対応していません"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM は許可されていません"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"電話は許可されていません"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"ポップアップ ウィンドウ"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"ポップアップ ウィンドウ"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"他 <xliff:g id="NUMBER">%1$d</xliff:g> 件"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"このショートカットを使用するには、最新のアプリが必要です"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"このアプリはバックアップと復元に対応していないため、ショートカットを復元できませんでした"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"アプリの署名が一致しないため、ショートカットを復元できませんでした"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"ショートカットを復元できませんでした"</string>
 </resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 879270b..85234cb 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"გაფრთხილებები"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"დემო-რეჟიმი საცალო მოვაჭრეებისთვის"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB კავშირი"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"აპი გაშვებულია"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"ბატარეის მხარჯავი აპები"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> იყენებს ბატარეას"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"ბატარეას <xliff:g id="NUMBER">%1$d</xliff:g> აპი იყენებს"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"შეყვანის მეთოდი"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"ქმედებები ტექსტზე"</string>
     <string name="email" msgid="4560673117055050403">"ელფოსტა"</string>
-    <string name="dial" msgid="4204975095406423102">"ტელეფონი"</string>
-    <string name="map" msgid="6068210738233985748">"Maps"</string>
-    <string name="browse" msgid="6993590095938149861">"ბრაუზერი"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"კონტაქტი"</string>
+    <string name="dial" msgid="1253998302767701559">"ზარი"</string>
+    <string name="map" msgid="6521159124535543457">"მიკვლევა"</string>
+    <string name="browse" msgid="1245903488306147205">"გახსნა"</string>
+    <string name="sms" msgid="4560537514610063430">"შეტყობინება"</string>
+    <string name="add_contact" msgid="7867066569670597203">"დამატება"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"თავისუფალი ადგილი იწურება"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"სისტემის ზოგიერთმა ფუნქციამ შესაძლოა არ იმუშავოს"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"სისტემისათვის საკმარისი საცავი არ არის. დარწმუნდით, რომ იქონიოთ სულ მცირე 250 მბაიტი თავისუფალი სივრცე და დაიწყეთ ხელახლა."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"გაუქმება"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"გაუქმება"</string>
-    <string name="close" msgid="2318214661230355730">"დახურვა"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"ყურადღება"</string>
     <string name="loading" msgid="7933681260296021180">"ჩატვირთვა…"</string>
     <string name="capital_on" msgid="1544682755514494298">"ჩართ."</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"მასშტაბი"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"ყოველთვის ჩვენება"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"ხელახალი გააქტიურება განყოფილებაში: სისტემის პარამეტრები &gt; აპები &gt; ჩამოტვირთულები."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"აპი არ რეაგირებს"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> შესაძლოა მეხსიერებას გადამეტებით იყენებდეს."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის მიერ ეკრანის ამჟამინდელი პარამეტრები მხარდაუჭერელია და შეიძლება არასათანადოდ იმუშაოს."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"ყოველთვის ჩვენება"</string>
     <string name="smv_application" msgid="3307209192155442829">"აპმა <xliff:g id="APPLICATION">%1$s</xliff:g> (პროცესი <xliff:g id="PROCESS">%2$s</xliff:g>) დაარღვია საკუთარი StrictMode დებულება."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"სატესტო საგანგებო შეტყობინება"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"პასუხი"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM ბარათი დაუშვებელია"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM ბარათი უზრუნველყოფილი არ არის"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM ბარათი დაუშვებელია"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"ტელეფონი დაუშვებელია"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"ამომხტარი ფანჯარა"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"ამომხტარი ფანჯარა"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"ეს მალსახმობი საჭიროებს აპის უახლეს ვერსიას"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"მალსახმობის აღდგენა ვერ მოხერხდა, რადგან ამ აპის მიერ მხარდაუჭერელია სარეზერვო ასლით აღდგენა"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"მალსახმობის აღდგენა ვერ მოხერხდა აპის ხელმოწერის შეუსაბამობის გამო"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"მალსახმობის აღდგენა ვერ მოხერხდა"</string>
 </resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 36dc3a6..5616972 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -172,7 +172,7 @@
     <string name="work_profile_deleted_description" msgid="1100529432509639864">"Әкімші қолданбасы болмағандықтан жұмыс профилі жойылды"</string>
     <string name="work_profile_deleted_details" msgid="6307630639269092360">"Жұмыс профилінің әкімші қолданбасы жоқ немесе бүлінген. Нәтижесінде жұмыс профиліңіз және қатысты деректер жойылды. Көмек алу үшін әкімшіге хабарласыңыз."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="8823792115612348820">"Жұмыс профиліңіз осы құрылғыда енді қолжетімді емес"</string>
-    <string name="work_profile_deleted_reason_maximum_password_failure" msgid="8986903510053359694">"Тым көп құпия сөз енгізу әрекеті жасалды"</string>
+    <string name="work_profile_deleted_reason_maximum_password_failure" msgid="8986903510053359694">"Құпия сөз көп рет қате енгізілді"</string>
     <string name="network_logging_notification_title" msgid="6399790108123704477">"Құрылғы басқарылады"</string>
     <string name="network_logging_notification_text" msgid="7930089249949354026">"Ұйымыңыз осы құрылғыны басқарады және желі трафигін бақылауы мүмкін. Мәліметтер алу үшін түртіңіз."</string>
     <string name="factory_reset_warning" msgid="5423253125642394387">"Құрылғыңыздағы деректер өшіріледі"</string>
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Дабылдар"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Бөлшек саудаға арналған демо нұсқасы"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB байланысы"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Қолданба қосулы"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Батареяны пайдаланып жатқан қолданбалар"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> батареяны пайдалануда"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> қолданба батареяны пайдалануда"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Енгізу әдісі"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Мәтін әрекеттері"</string>
     <string name="email" msgid="4560673117055050403">"Электрондық пошта"</string>
-    <string name="dial" msgid="4204975095406423102">"Телефон"</string>
-    <string name="map" msgid="6068210738233985748">"Maps"</string>
-    <string name="browse" msgid="6993590095938149861">"Браузер"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Контакт"</string>
+    <string name="dial" msgid="1253998302767701559">"Қоңырау шалу"</string>
+    <string name="map" msgid="6521159124535543457">"Орынды анықтау"</string>
+    <string name="browse" msgid="1245903488306147205">"Ашу"</string>
+    <string name="sms" msgid="4560537514610063430">"Хабар"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Енгізу"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Жадта орын азайып барады"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Жүйенің кейбір функциялары жұмыс істемеуі мүмкін"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Жүйе үшін жад жеткіліксіз. 250 МБ бос орын бар екенін тексеріп, қайта іске қосыңыз."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Бас тарту"</string>
     <string name="yes" msgid="5362982303337969312">"Жарайды"</string>
     <string name="no" msgid="5141531044935541497">"Бас тарту"</string>
-    <string name="close" msgid="2318214661230355730">"ЖАБУ"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Назар аударыңыз"</string>
     <string name="loading" msgid="7933681260296021180">"Жүктелуде…"</string>
     <string name="capital_on" msgid="1544682755514494298">"Қосулы"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Меже"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Үнемі көрсету"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Мұны «Жүйелік параметрлер» &gt; «Қолданбалар» &gt; «Жүктелгендер» тармағында қосыңыз."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Қолданба жауап бермеуде"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> жадтан тым көп орын пайдалануда."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасында \"Дисплей өлшемі\" параметрінің таңдалған мәніне қолдау көрсетілмейді, сондықтан дұрыс жұмыс істемеуі мүмкін."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Үнемі көрсету"</string>
     <string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасы (<xliff:g id="PROCESS">%2$s</xliff:g> процесі) өзі қолданған StrictMode саясатын бұзды."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Төтенше хабарлар сынағы"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Жауап"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM картасына рұқсат етілмеген"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM картасы белсендірілмеген"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM картасына рұқсат етілмеген"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Телефонға рұқсат етілмеген"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Қалқымалы терезе"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Қалқымалы терезе"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Бұл таңбаша ең соңғы қолданбаны қажет етеді"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Қолданба сақтық көшірме жасау мен қалпына келтіруді қолдамайтындықтан, таңбаша қалпына келтірілмеді"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Қолтаңба сәйкес келмейтіндіктен, таңбаша қалпына келтірілмеді"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Таңбаша қалпына келтірілмеді"</string>
 </resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index b8f9f8b..cfc79fe 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"ការ​ជូនដំណឹង"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"របៀបដាក់បង្ហាញក្នុងហាង"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"ការ​តភ្ជាប់ USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"កម្មវិធី​ដែល​កំពុង​ដំណើរការ"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"កម្មវិធីដែល​កំពុងប្រើថ្ម"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងប្រើថ្ម"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"កម្មវិធីចំនួន <xliff:g id="NUMBER">%1$d</xliff:g> កំពុងប្រើថ្ម"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"វិធីសាស្ត្រ​បញ្ចូល"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"សកម្មភាព​អត្ថបទ"</string>
     <string name="email" msgid="4560673117055050403">"អ៊ីមែល"</string>
-    <string name="dial" msgid="4204975095406423102">"ទូរសព្ទ"</string>
-    <string name="map" msgid="6068210738233985748">"ផែនទី"</string>
-    <string name="browse" msgid="6993590095938149861">"កម្មវិធីរុករកតាមអ៊ីនធឺណិត"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"ទំនាក់​ទំនង"</string>
+    <string name="dial" msgid="1253998302767701559">"ហៅទូរសព្ទ"</string>
+    <string name="map" msgid="6521159124535543457">"កំណត់ទីតាំង"</string>
+    <string name="browse" msgid="1245903488306147205">"បើក"</string>
+    <string name="sms" msgid="4560537514610063430">"សារ"</string>
+    <string name="add_contact" msgid="7867066569670597203">"បញ្ចូល"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"អស់​ទំហំ​ផ្ទុក"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"មុខងារ​ប្រព័ន្ធ​មួយ​ចំនួន​អាច​មិន​ដំណើរការ​"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"មិន​មាន​ទំហំ​ផ្ទុក​​គ្រប់​គ្រាន់​សម្រាប់​ប្រព័ន្ធ​។ សូម​ប្រាកដ​ថា​អ្នក​មាន​ទំហំ​ទំនេរ​ 250MB ហើយ​ចាប់ផ្ដើម​ឡើង​វិញ។"</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"បោះ​បង់​"</string>
     <string name="yes" msgid="5362982303337969312">"យល់​ព្រម​"</string>
     <string name="no" msgid="5141531044935541497">"បោះ​បង់​"</string>
-    <string name="close" msgid="2318214661230355730">"បិទ"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"ប្រយ័ត្ន"</string>
     <string name="loading" msgid="7933681260296021180">"កំពុង​ផ្ទុក..."</string>
     <string name="capital_on" msgid="1544682755514494298">"បើក"</string>
@@ -1051,8 +1051,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"មាត្រដ្ឋាន"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"បង្ហាញ​ជា​និច្ច"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"បើក​វា​ឡើងវិញ​ក្នុង​ការ​កំណត់​ប្រព័ន្ធ &gt; កម្មវិធី &gt; ទាញ​យក។"</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"កម្មវិធីមិនមានការឆ្លើយតបទេ"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> អាចកំពុងប្រើអង្គចងចាំច្រើនពេក។"</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> មិនគាំទ្រការកំណត់ទំហំនៃការបង្ហាញបច្ចុប្បន្ន និងអាចមានសកម្មភាពខុសពីការរំពឹងទុក។"</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"បង្ហាញ​ជា​និច្ច"</string>
     <string name="smv_application" msgid="3307209192155442829">"កម្មវិធី <xliff:g id="APPLICATION">%1$s</xliff:g> (ដំណើរការ <xliff:g id="PROCESS">%2$s</xliff:g>) បាន​បំពាន​គោលនយោបាយ​របៀប​តឹងរ៉ឹង​អនុវត្ត​ដោយ​ខ្លួន​​ឯង។"</string>
@@ -1786,11 +1784,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"សារសាកល្បងពេលមានអាសន្ន"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"ឆ្លើយតប"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"មិន​អនុញ្ញាត​សីុមកាត​ទេ"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"សីុម​មិន​ត្រូវបាន​ផ្តល់ជូន​ទេ"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"មិន​អនុញ្ញាត​ចំពោះសីុម​ទេ"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"មិន​អនុញ្ញាត​ចំពោះទូរសព្ទ​ទេ"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"វិនដូលេចឡើង"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"វិនដូលេចឡើង"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"ផ្លូវកាត់នេះត្រូវការកម្មវិធីថ្មីបំផុត"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"មិនអាចស្តារផ្លូវកាត់បានទេ ដោយសារកម្មវិធីមិនស្គាល់ការបម្រុងទុក និងការស្តារ"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"មិនអាចស្តារផ្លូវកាត់បានទេ ដោយសារការស៊ីញ៉េកម្មវិធីមិនត្រូវគ្នា"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"មិនអាចស្តារផ្លូវកាត់បានទេ"</string>
 </resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index c362ce1..f02a7ba 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"ಎಚ್ಚರಿಕೆಗಳು"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"ರಿಟೇಲ್ ಡೆಮೋ"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB ಸಂಪರ್ಕ"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"App ರನ್ ಆಗುತ್ತಿದೆ"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಬ್ಯಾಟರಿಯನ್ನು ಉಪಯೋಗಿಸುತ್ತಿವೆ"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಬ್ಯಾಟರಿ ಬಳಸುತ್ತಿದೆ"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಬ್ಯಾಟರಿ ಬಳಸುತ್ತಿವೆ"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"ಇನ್‌ಪುಟ್ ವಿಧಾನ"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"ಪಠ್ಯದ ಕ್ರಮಗಳು"</string>
     <string name="email" msgid="4560673117055050403">"ಇಮೇಲ್"</string>
-    <string name="dial" msgid="4204975095406423102">"ಫೋನ್"</string>
-    <string name="map" msgid="6068210738233985748">"ನಕ್ಷೆಗಳು"</string>
-    <string name="browse" msgid="6993590095938149861">"ಬ್ರೌಸರ್"</string>
-    <string name="sms" msgid="8250353543787396737">"ಎಸ್‌ಎಂಎಸ್‌"</string>
-    <string name="add_contact" msgid="7990645816259405444">"ಸಂಪರ್ಕ"</string>
+    <string name="dial" msgid="1253998302767701559">"ಕರೆ"</string>
+    <string name="map" msgid="6521159124535543457">"ಗುರುತಿಸಿ"</string>
+    <string name="browse" msgid="1245903488306147205">"ತೆರೆ"</string>
+    <string name="sms" msgid="4560537514610063430">"ಸಂದೇಶ"</string>
+    <string name="add_contact" msgid="7867066569670597203">"ಸೇರಿಸಿ"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"ಸಂಗ್ರಹಣೆ ಸ್ಥಳವು ತುಂಬಿದೆ"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"ಕೆಲವು ಸಿಸ್ಟಂ ಕಾರ್ಯವಿಧಾನಗಳು ಕಾರ್ಯನಿರ್ವಹಿಸದೇ ಇರಬಹುದು"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ಸಿಸ್ಟಂನಲ್ಲಿ ಸಾಕಷ್ಟು ಸಂಗ್ರಹಣೆಯಿಲ್ಲ. ನೀವು 250MB ನಷ್ಟು ಖಾಲಿ ಸ್ಥಳವನ್ನು ಹೊಂದಿರುವಿರಾ ಎಂಬುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ ಹಾಗೂ ಮರುಪ್ರಾರಂಭಿಸಿ."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"ರದ್ದುಮಾಡಿ"</string>
     <string name="yes" msgid="5362982303337969312">"ಸರಿ"</string>
     <string name="no" msgid="5141531044935541497">"ರದ್ದುಮಾಡಿ"</string>
-    <string name="close" msgid="2318214661230355730">"ಮುಚ್ಚಿ"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"ಗಮನಿಸಿ"</string>
     <string name="loading" msgid="7933681260296021180">"ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."</string>
     <string name="capital_on" msgid="1544682755514494298">"ಆನ್‌ ಮಾಡಿ"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"ಮಾಪಕ"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"ಯಾವಾಗಲೂ ತೋರಿಸಿ"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"ಸಿಸ್ಟಂ ಸೆಟ್ಟಿಂಗ್‌ಗಳು &gt; ಅಪ್ಲಿಕೇಶನ್‌ಗಳು &gt; ಡೌನ್‌ಲೋಡ್‌ ಆಗಿರುವುದರಲ್ಲಿ ಇದನ್ನು ಮರು ಸಕ್ರಿಯಗೊಳಿಸಿ."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"ಅಪ್ಲಿಕೇಶನ್ ಪ್ರತಿಕ್ರಿಯಿಸುತ್ತಿಲ್ಲ"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಹೆಚ್ಚು ಮೆಮೊರಿಯನ್ನು ಬಳಸಿಕೊಳ್ಳುತ್ತಿರಬಹುದು."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಪ್ರಸ್ತುತ ಪ್ರದರ್ಶನ ಗಾತ್ರದ ಸೆಟ್ಟಿಂಗ್‌ ಅನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ ಮತ್ತು ಅನಿರೀಕ್ಷಿತವಾಗಿ ವರ್ತಿಸಬಹುದು."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"ಯಾವಾಗಲೂ ತೋರಿಸು"</string>
     <string name="smv_application" msgid="3307209192155442829">"ಅಪ್ಲಿಕೇಶನ್‌‌ <xliff:g id="APPLICATION">%1$s</xliff:g> (ಪ್ರಕ್ರಿಯೆಯು <xliff:g id="PROCESS">%2$s</xliff:g>) ತನ್ನ ಸ್ವಯಂ-ಜಾರಿ ಕಠಿಣ ಮೋಡ್ ನೀತಿಯನ್ನು ಉಲ್ಲಂಘನೆ ಮಾಡಿದೆ."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"ತುರ್ತು ಸಂದೇಶಗಳ ಪರೀಕ್ಷೆ"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"ಪ್ರತ್ಯುತ್ತರ"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"ಸಿಮ್‌ಗೆ ಅನುಮತಿಯಿಲ್ಲ"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"ಸಿಮ್ ಸಿದ್ಧವಾಗಿಲ್ಲ"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"ಸಿಮ್‌ಗೆ ಅನುಮತಿಯಿಲ್ಲ"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"ಫೋನ್‌ಗೆ ಅನುಮತಿಯಿಲ್ಲ"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"ಪಾಪ್‌ಅಪ್ ವಿಂಡೋ"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"ಪಾಪ್‌ಅಪ್ ವಿಂಡೋ"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"ಈ ಶಾರ್ಟ್‌ಕಟ್‌ಗೆ ಇತ್ತೀಚಿನ ಅಪ್ಲಿಕೇಶನ್‌ ಅಗತ್ಯವಿದೆ"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"ಅಪ್ಲಿಕೇಶನ್‌ ಬ್ಯಾಕಪ್ ಮತ್ತು ಪುನಃಸ್ಥಾಪನೆಯನ್ನು ಬೆಂಬಲಿಸದಿರುವುದರಿಂದ ಶಾರ್ಟ್‌ಕಟ್‌ ಅನ್ನು ಪುನಃಸ್ಥಾಪನೆ ಮಾಡಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"ಅಪ್ಲಿಕೇಶನ್‌ ಸಹಿ ಹೊಂದಿಕೆಯಾಗದ ಕಾರಣದಿಂದ ಶಾರ್ಟ್‌ಕಟ್‌ ಅನ್ನು ಪುನಃಸ್ಥಾಪಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"ಶಾರ್ಟ್‌ಕಟ್‌ ಅನ್ನು ಪುನಃ ಸ್ಥಾಪನೆ ಮಾಡಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 991a9833..aa2cc3d 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"알림"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"소매 데모"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB 연결"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"실행 중인 앱"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"배터리를 소모하는 앱"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 배터리 사용 중"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"앱 <xliff:g id="NUMBER">%1$d</xliff:g>개에서 배터리 사용 중"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"입력 방법"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"텍스트 작업"</string>
     <string name="email" msgid="4560673117055050403">"이메일"</string>
-    <string name="dial" msgid="4204975095406423102">"전화"</string>
-    <string name="map" msgid="6068210738233985748">"지도"</string>
-    <string name="browse" msgid="6993590095938149861">"브라우저"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"연락처"</string>
+    <string name="dial" msgid="1253998302767701559">"전화"</string>
+    <string name="map" msgid="6521159124535543457">"위치 확인"</string>
+    <string name="browse" msgid="1245903488306147205">"열기"</string>
+    <string name="sms" msgid="4560537514610063430">"메시지"</string>
+    <string name="add_contact" msgid="7867066569670597203">"추가"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"저장 공간이 부족함"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"일부 시스템 기능이 작동하지 않을 수 있습니다."</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"시스템의 저장 공간이 부족합니다. 250MB의 여유 공간이 확보한 후 다시 시작하세요."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"취소"</string>
     <string name="yes" msgid="5362982303337969312">"확인"</string>
     <string name="no" msgid="5141531044935541497">"취소"</string>
-    <string name="close" msgid="2318214661230355730">"닫기"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"주의"</string>
     <string name="loading" msgid="7933681260296021180">"로드 중.."</string>
     <string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"배율"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"항상 표시"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"시스템 설정 &gt; 앱 &gt; 다운로드로 이동하여 이 모드를 다시 사용하도록 설정합니다."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"앱이 응답하지 않음"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 메모리를 과도하게 사용하는 것으로 보입니다."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱은 현재 디스플레이 크기 설정을 지원하지 않으며 예기치 않게 동작할 수 있습니다."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"항상 표시"</string>
     <string name="smv_application" msgid="3307209192155442829">"앱 <xliff:g id="APPLICATION">%1$s</xliff:g>(프로세스 <xliff:g id="PROCESS">%2$s</xliff:g>)이(가) 자체 시행 StrictMode 정책을 위반했습니다."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"긴급 메시지 테스트"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"답장"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM이 허용되지 않음"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM이 프로비저닝되지 않음"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM이 허용되지 않음"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"전화가 허용되지 않음"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"팝업 창"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"팝업 창"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"<xliff:g id="NUMBER">%1$d</xliff:g>개 더보기"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"바로가기를 사용하려면 최신 앱이 필요합니다"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"앱이 백업 및 복원을 지원하지 않으므로 바로가기를 복원할 수 없습니다"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"앱 서명이 일치하지 않아 바로가기를 복원할 수 없습니다"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"바로가기를 복원할 수 없습니다"</string>
 </resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 06bbabe..a1cc479 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Эскертүүлөр"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Чекене соода дүкөнү үчүн демо режим"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB аркылуу туташуу"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Колдонмо иштеп жатат"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Колдонмолор батареяңызды коротууда"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу батареяны пайдаланып жатат"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> колдонмо батареяны пайдаланып жатат"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Киргизүү ыкмасы"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Текст боюнча иштер"</string>
     <string name="email" msgid="4560673117055050403">"Электрондук почта"</string>
-    <string name="dial" msgid="4204975095406423102">"Телефон"</string>
-    <string name="map" msgid="6068210738233985748">"Карталар"</string>
-    <string name="browse" msgid="6993590095938149861">"Серепчи"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Байланыш"</string>
+    <string name="dial" msgid="1253998302767701559">"Чалуу"</string>
+    <string name="map" msgid="6521159124535543457">"Жайгашкан жер"</string>
+    <string name="browse" msgid="1245903488306147205">"Ачуу"</string>
+    <string name="sms" msgid="4560537514610063430">"Билдирүү"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Кошуу"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Сактагычта орун калбай баратат"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Системанын кээ бир функциялары иштебеши мүмкүн"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Тутумда сактагыч жетишсиз. 250МБ бош орун бар экенин текшерип туруп, өчүрүп күйгүзүңүз."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Жокко чыгаруу"</string>
     <string name="yes" msgid="5362982303337969312">"Жарайт"</string>
     <string name="no" msgid="5141531044935541497">"Жокко чыгаруу"</string>
-    <string name="close" msgid="2318214661230355730">"ЖАБУУ"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Көңүл буруңуз"</string>
     <string name="loading" msgid="7933681260296021180">"Жүктөлүүдө…"</string>
     <string name="capital_on" msgid="1544682755514494298">"ЖАНДЫРЫЛГАН"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Шкала"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Ар дайым көрсөтүлсүн"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Муну тутум жөндөөлөрүнөн кайра иштетүү &gt; Колдонмолор &gt; Жүктөлүп алынган."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Колдонмо жооп бербей жатат"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу эстутумду өтө көп колдонуп жатышы мүмкүн."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу көрүнүштүн тандалган өлчөмүн экранда көрсөтө албайт жана туура эмес иштеши мүмкүн."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Ар дайым көрсөтүлсүн"</string>
     <string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосу (<xliff:g id="PROCESS">%2$s</xliff:g> процесси) өз алдынча иштеткен StrictMode саясатын бузду."</string>
@@ -1785,11 +1783,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Өзгөчө кырдаалда жөнөтүлүүчү билдирүүлөрдү сыноо"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Жооп берүү"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM картаны колдонууга тыюу салынган"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM карта таанылган жок"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM картаны колдонууга тыюу салынган"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Телефонду колдонууга тыюу салынган"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Калкып чыкма терезе"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Калкып чыкма терезе"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Бул кыска жолго колдонмонун эң акыркы версиясы талап кылынат"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Колдонмо камдык көчүрмөнү сактоо жана калыбына келтирүү функцияларын колдобогондуктан кыска жол калыбына келтирилбей койду"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Колдонмонун колтамгасы дал келбегендиктен кыска жол калыбына келтирилбей койду"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Кыска жол калыбына келтирилбей койду"</string>
 </resources>
diff --git a/core/res/res/values-large/strings.xml b/core/res/res/values-large/strings.xml
deleted file mode 100644
index e998b9a..0000000
--- a/core/res/res/values-large/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/assets/res/any/strings.xml
-**
-** Copyright 2011, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- Do not translate.  WebView User Agent targeted content -->
-    <string name="web_user_agent_target_content" translatable="false"></string>
-
-</resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 374188f..79a41aa 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"ການເຕືອນ"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"ເດໂມສຳລັບຮ້ານຂາຍ"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"ການເຊື່ອມຕໍ່ USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"ແອັບກຳລັງເຮັດວຽກ"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"ແອັບທີ່ກຳລັງໃຊ້ແບັດເຕີຣີ"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> ກຳລັງໃຊ້ແບັດເຕີຣີຢູ່"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> ແອັບກຳລັງໃຊ້ແບັດເຕີຣີຢູ່"</string>
@@ -978,11 +979,16 @@
     <string name="inputMethod" msgid="1653630062304567879">"ຮູບແບບການປ້ອນຂໍ້ມູນ"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"ການເຮັດວຽກຂອງຂໍ້ຄວາມ"</string>
     <string name="email" msgid="4560673117055050403">"ອີເມວ"</string>
-    <string name="dial" msgid="4204975095406423102">"ໂທລະສັບ"</string>
-    <string name="map" msgid="6068210738233985748">"ແຜນທີ່"</string>
-    <string name="browse" msgid="6993590095938149861">"ໂປຣແກຣມທ່ອງເວັບ"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"ຕິດຕໍ່"</string>
+    <!-- no translation found for dial (1253998302767701559) -->
+    <skip />
+    <!-- no translation found for map (6521159124535543457) -->
+    <skip />
+    <!-- no translation found for browse (1245903488306147205) -->
+    <skip />
+    <!-- no translation found for sms (4560537514610063430) -->
+    <skip />
+    <!-- no translation found for add_contact (7867066569670597203) -->
+    <skip />
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"ພື້ນທີ່ຈັດເກັບຂໍ້ມູນກຳລັງຈະເຕັມ"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"ການເຮັດວຽກບາງຢ່າງຂອງລະບົບບາງອາດຈະໃຊ້ບໍ່ໄດ້"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"​ບໍ່​ມີ​ບ່ອນ​ເກັບ​ຂໍ້​ມູນ​ພຽງ​ພໍ​ສຳ​ລັບ​ລະ​ບົບ. ກວດ​ສອບ​ໃຫ້​ແນ່​ໃຈ​ວ່າ​ທ່ານ​ມີ​ພື້ນ​ທີ່​ຫວ່າງ​ຢ່າງ​ໜ້ອຍ 250MB ​ແລ້ວລອງ​ໃໝ່."</string>
@@ -1789,6 +1795,13 @@
     <string name="mmcc_illegal_ms" msgid="2769452751852211112">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ SIM"</string>
     <string name="mmcc_illegal_me" msgid="4438696681169345015">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ໂທລະສັບ"</string>
     <string name="popup_window_default_title" msgid="4874318849712115433">"ໜ້າຈໍປັອບອັບ"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <!-- no translation found for shortcut_restored_on_lower_version (5270675146351613828) -->
+    <skip />
+    <!-- no translation found for shortcut_restore_not_supported (5028808567940014190) -->
+    <skip />
+    <!-- no translation found for shortcut_restore_signature_mismatch (2406209324521327518) -->
+    <skip />
+    <!-- no translation found for shortcut_restore_unknown_issue (8703738064603262597) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index ab60a62..c836374 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -255,6 +255,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Įspėjimai"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demonstracinė versija mažmenininkams"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB jungtis"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Programa paleista"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Programos, naudojančios akumuliatoriaus energiją"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ naudoja akumuliatoriaus energiją"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"Programų, naudojančių akumuliatoriaus energiją: <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
@@ -1018,11 +1019,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Įvesties būdas"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Teksto veiksmai"</string>
     <string name="email" msgid="4560673117055050403">"Siųsti el. laišką"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefonas"</string>
-    <string name="map" msgid="6068210738233985748">"Žemėlapiai"</string>
-    <string name="browse" msgid="6993590095938149861">"Naršyklė"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Kontaktas"</string>
+    <string name="dial" msgid="1253998302767701559">"Skambinti"</string>
+    <string name="map" msgid="6521159124535543457">"Rasti"</string>
+    <string name="browse" msgid="1245903488306147205">"Atidaryti"</string>
+    <string name="sms" msgid="4560537514610063430">"Pranešimas"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Pridėti"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Mažėja laisvos saugyklos vietos"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Kai kurios sistemos funkcijos gali neveikti"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sistemos saugykloje nepakanka vietos. Įsitikinkite, kad yra 250 MB laisvos vietos, ir paleiskite iš naujo."</string>
@@ -1032,7 +1033,6 @@
     <string name="cancel" msgid="6442560571259935130">"Atšaukti"</string>
     <string name="yes" msgid="5362982303337969312">"Gerai"</string>
     <string name="no" msgid="5141531044935541497">"Atšaukti"</string>
-    <string name="close" msgid="2318214661230355730">"UŽDARYTI"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Dėmesio"</string>
     <string name="loading" msgid="7933681260296021180">"Įkeliama..."</string>
     <string name="capital_on" msgid="1544682755514494298">"ĮJ."</string>
@@ -1089,8 +1089,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Mastelis"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Visada rodyti"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Įgalinkite jį iš naujo nuėję į „Sistemos nustatymai“ &gt; „Programos“ &gt; „Atsisiųsta“."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Programa nereaguoja"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ gali naudoti per daug atminties."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"Programoje „<xliff:g id="APP_NAME">%1$s</xliff:g>“ nepalaikomas dabartinis ekrano dydžio nustatymas ir ji gali netinkamai veikti."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Visada rodyti"</string>
     <string name="smv_application" msgid="3307209192155442829">"Programa „<xliff:g id="APPLICATION">%1$s</xliff:g>“ (procesas „<xliff:g id="PROCESS">%2$s</xliff:g>“) pažeidė savo vykdomą „StrictMode“ politiką."</string>
@@ -1854,11 +1852,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Kritinės padėties pranešimo bandymas"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Atsakyti"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM kortelė neleidžiama"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM kortelė neteikiama"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM kortelė neleidžiama"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Telefonas neleidžiamas"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Iššokantysis langas"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Iššokantysis langas"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"Dar <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Norint naudoti šį spartųjį klavišą būtina naujausios versijos programa"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Nepavyko atkurti sparčiojo klavišo, nes programa nepalaiko atsarginės kopijos kūrimo ir atkūrimo funkcijų"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Nepavyko atkurti sparčiojo klavišo, nes programos parašas neatitinka"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Nepavyko atkurti sparčiojo klavišo"</string>
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index f64fe62..9a067c6 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -252,6 +252,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Brīdinājumi"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demonstrācijas versija veikaliem"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB savienojums"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Lietotne darbojas"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Lietotnes, kas patērē akumulatora jaudu"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> izmanto akumulatoru"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> lietotne(-es) izmanto akumulatoru"</string>
@@ -998,11 +999,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Ievades metode"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Teksta darbības"</string>
     <string name="email" msgid="4560673117055050403">"E-pasts"</string>
-    <string name="dial" msgid="4204975095406423102">"Tālrunis"</string>
-    <string name="map" msgid="6068210738233985748">"Kartes"</string>
-    <string name="browse" msgid="6993590095938149861">"Pārlūkprogramma"</string>
-    <string name="sms" msgid="8250353543787396737">"Īsziņas"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Kontaktpersona"</string>
+    <string name="dial" msgid="1253998302767701559">"Zvanīt"</string>
+    <string name="map" msgid="6521159124535543457">"Atrast"</string>
+    <string name="browse" msgid="1245903488306147205">"Atvērt"</string>
+    <string name="sms" msgid="4560537514610063430">"Īsziņa"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Pievienot"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Paliek maz brīvas vietas"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Dažas sistēmas funkcijas var nedarboties."</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sistēmai pietrūkst vietas. Atbrīvojiet vismaz 250 MB vietas un restartējiet ierīci."</string>
@@ -1012,7 +1013,6 @@
     <string name="cancel" msgid="6442560571259935130">"Atcelt"</string>
     <string name="yes" msgid="5362982303337969312">"Labi"</string>
     <string name="no" msgid="5141531044935541497">"Atcelt"</string>
-    <string name="close" msgid="2318214661230355730">"AIZVĒRT"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Uzmanību!"</string>
     <string name="loading" msgid="7933681260296021180">"Notiek ielāde..."</string>
     <string name="capital_on" msgid="1544682755514494298">"IESLĒGT"</string>
@@ -1069,8 +1069,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Mērogs"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Rādīt vienmēr"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Atkārtoti iespējojiet šeit: Sistēmas iestatījumi &gt; Lietotnes &gt; Lejupielādētās."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Lietotne nereaģē"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"Iespējams, lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> aizņem pārāk daudz vietas atmiņā."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"Lietotnē <xliff:g id="APP_NAME">%1$s</xliff:g> netiek atbalstīts pašreizējais displeja lieluma iestatījums, tādēļ tā var tikt attēlota neparedzētā veidā."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Rādīt vienmēr"</string>
     <string name="smv_application" msgid="3307209192155442829">"Lietotne <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) ir pārkāpusi savu pašieviesto StrictMode politiku."</string>
@@ -1819,11 +1817,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Ārkārtas ziņojuma pārbaude"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Atbildēt"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM karti nav atļauts izmantot"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM karte netiek nodrošināta"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM karti nav atļauts izmantot"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Tālruni nav atļauts izmantot"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Uznirstošais logs"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Uznirstošais logs"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"Vēl <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Šai saīsnei ir nepieciešama jaunākā lietotne."</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Nevarēja atjaunot saīsni, jo lietotnē netiek atbalstīta dublēšana un atjaunošana."</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Saīsni nevarēja atjaunot lietotnes paraksta neatbilstības dēļ."</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Nevarēja atjaunot saīsni."</string>
 </resources>
diff --git a/core/res/res/values-mcc001-mnc01-af/strings.xml b/core/res/res/values-mcc001-mnc01-af/strings.xml
new file mode 100644
index 0000000..e251b61
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-af/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Foon nie toegelaat nie MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-am/strings.xml b/core/res/res/values-mcc001-mnc01-am/strings.xml
new file mode 100644
index 0000000..c5cc421
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-am/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"ስልክ አይፈቀድም MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-ar/strings.xml b/core/res/res/values-mcc001-mnc01-ar/strings.xml
new file mode 100644
index 0000000..ae68ed4
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-ar/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"‏غير مسموح باستخدام الهاتف MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-az/strings.xml b/core/res/res/values-mcc001-mnc01-az/strings.xml
new file mode 100644
index 0000000..7ac0613
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-az/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"MM#6 telefonu dəstəklənmir"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-b+sr+Latn/strings.xml b/core/res/res/values-mcc001-mnc01-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..858fdcb
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-b+sr+Latn/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Telefon nije dozvoljen MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-be/strings.xml b/core/res/res/values-mcc001-mnc01-be/strings.xml
new file mode 100644
index 0000000..a22b9c4
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-be/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Тэлефон не дапускаецца MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-bg/strings.xml b/core/res/res/values-mcc001-mnc01-bg/strings.xml
new file mode 100644
index 0000000..b311679
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-bg/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Телефонът не е разрешен MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-bn/strings.xml b/core/res/res/values-mcc001-mnc01-bn/strings.xml
new file mode 100644
index 0000000..095f8c7
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-bn/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"ফোন অনুমোদিত নয় MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-bs/strings.xml b/core/res/res/values-mcc001-mnc01-bs/strings.xml
new file mode 100644
index 0000000..858fdcb
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-bs/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Telefon nije dozvoljen MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-ca/strings.xml b/core/res/res/values-mcc001-mnc01-ca/strings.xml
new file mode 100644
index 0000000..cfdaf3e
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-ca/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Telèfon no compatible MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-cs/strings.xml b/core/res/res/values-mcc001-mnc01-cs/strings.xml
new file mode 100644
index 0000000..4a7f221
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-cs/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Telefon není povolen (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-da/strings.xml b/core/res/res/values-mcc001-mnc01-da/strings.xml
new file mode 100644
index 0000000..6a7a5c8
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-da/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Telefonen har ikke adgangstilladelse MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-de/strings.xml b/core/res/res/values-mcc001-mnc01-de/strings.xml
new file mode 100644
index 0000000..25b6bd1
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-de/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Smartphone nicht zulässig MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-el/strings.xml b/core/res/res/values-mcc001-mnc01-el/strings.xml
new file mode 100644
index 0000000..ae6b17a
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-el/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Το τηλέφωνο δεν επιτρέπεται MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-en-rAU/strings.xml b/core/res/res/values-mcc001-mnc01-en-rAU/strings.xml
new file mode 100644
index 0000000..231b858
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-en-rAU/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Phone not allowed MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-en-rCA/strings.xml b/core/res/res/values-mcc001-mnc01-en-rCA/strings.xml
new file mode 100644
index 0000000..231b858
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-en-rCA/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Phone not allowed MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-en-rGB/strings.xml b/core/res/res/values-mcc001-mnc01-en-rGB/strings.xml
new file mode 100644
index 0000000..231b858
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-en-rGB/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Phone not allowed MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-en-rIN/strings.xml b/core/res/res/values-mcc001-mnc01-en-rIN/strings.xml
new file mode 100644
index 0000000..231b858
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-en-rIN/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Phone not allowed MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-en-rXC/strings.xml b/core/res/res/values-mcc001-mnc01-en-rXC/strings.xml
new file mode 100644
index 0000000..00e7813
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-en-rXC/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‏‎‎‏‎‏‏‎‎‏‏‎‎‏‏‏‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‏‎‎Phone not allowed MM#6‎‏‎‎‏‎"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-es-rUS/strings.xml b/core/res/res/values-mcc001-mnc01-es-rUS/strings.xml
new file mode 100644
index 0000000..059c64a
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-es-rUS/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Teléfono no admitido MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-es/strings.xml b/core/res/res/values-mcc001-mnc01-es/strings.xml
new file mode 100644
index 0000000..059c64a
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-es/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Teléfono no admitido MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-et/strings.xml b/core/res/res/values-mcc001-mnc01-et/strings.xml
new file mode 100644
index 0000000..62ff8ec
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-et/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Telefon pole lubatud MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-eu/strings.xml b/core/res/res/values-mcc001-mnc01-eu/strings.xml
new file mode 100644
index 0000000..2140993
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-eu/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Telefonoa ez da onartzen MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-fa/strings.xml b/core/res/res/values-mcc001-mnc01-fa/strings.xml
new file mode 100644
index 0000000..3d1acdb
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-fa/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"‏تلفن مجاز نیست MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-fi/strings.xml b/core/res/res/values-mcc001-mnc01-fi/strings.xml
new file mode 100644
index 0000000..1c75bb6
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-fi/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Puhelin estetty MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-fr-rCA/strings.xml b/core/res/res/values-mcc001-mnc01-fr-rCA/strings.xml
new file mode 100644
index 0000000..dbb6052
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-fr-rCA/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Téléphone non autorisé MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-fr/strings.xml b/core/res/res/values-mcc001-mnc01-fr/strings.xml
new file mode 100644
index 0000000..dbb6052
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-fr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Téléphone non autorisé MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-gl/strings.xml b/core/res/res/values-mcc001-mnc01-gl/strings.xml
new file mode 100644
index 0000000..a9cd85e
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-gl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Non se admite o teléfono MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-gu/strings.xml b/core/res/res/values-mcc001-mnc01-gu/strings.xml
new file mode 100644
index 0000000..f7c3285
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-gu/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"MM#6 ફોનની મંજૂરી નથી"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-hi/strings.xml b/core/res/res/values-mcc001-mnc01-hi/strings.xml
new file mode 100644
index 0000000..ff6fed8
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-hi/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"फ़ोन की इजाज़त नहीं है MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-hr/strings.xml b/core/res/res/values-mcc001-mnc01-hr/strings.xml
new file mode 100644
index 0000000..a3b89c9
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-hr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Telefon nije dopušten MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-hu/strings.xml b/core/res/res/values-mcc001-mnc01-hu/strings.xml
new file mode 100644
index 0000000..e591979
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-hu/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"A telefon nem engedélyezett (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-hy/strings.xml b/core/res/res/values-mcc001-mnc01-hy/strings.xml
new file mode 100644
index 0000000..90a840c
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-hy/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Հեռախոսի օգտագործումն արգելված է (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-in/strings.xml b/core/res/res/values-mcc001-mnc01-in/strings.xml
new file mode 100644
index 0000000..1496178
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-in/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Ponsel tidak diizinkan MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-is/strings.xml b/core/res/res/values-mcc001-mnc01-is/strings.xml
new file mode 100644
index 0000000..cb33a8c
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-is/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Sími ekki leyfður MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-it/strings.xml b/core/res/res/values-mcc001-mnc01-it/strings.xml
new file mode 100644
index 0000000..ce902c7
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-it/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Telefono non consentito MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-iw/strings.xml b/core/res/res/values-mcc001-mnc01-iw/strings.xml
new file mode 100644
index 0000000..2f0eec8
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-iw/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"‏הטלפון לא מורשה MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-ja/strings.xml b/core/res/res/values-mcc001-mnc01-ja/strings.xml
new file mode 100644
index 0000000..6661e5f
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-ja/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"電話は許可されていません(MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-ka/strings.xml b/core/res/res/values-mcc001-mnc01-ka/strings.xml
new file mode 100644
index 0000000..3d8e1b2
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-ka/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"ტელეფონი დაუშვებელია MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-kk/strings.xml b/core/res/res/values-mcc001-mnc01-kk/strings.xml
new file mode 100644
index 0000000..ba210c2
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-kk/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Телефон пайдалануға болмайды MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-km/strings.xml b/core/res/res/values-mcc001-mnc01-km/strings.xml
new file mode 100644
index 0000000..2ee5b75
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-km/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"មិន​អនុញ្ញាត​ចំពោះ​ទូរសព្ទ​ទេ MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-kn/strings.xml b/core/res/res/values-mcc001-mnc01-kn/strings.xml
new file mode 100644
index 0000000..de459a2
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-kn/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"ಫೋನ್ MM#6 ಅನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-ko/strings.xml b/core/res/res/values-mcc001-mnc01-ko/strings.xml
new file mode 100644
index 0000000..39b839b
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-ko/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"전화가 허용되지 않음 MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-ky/strings.xml b/core/res/res/values-mcc001-mnc01-ky/strings.xml
new file mode 100644
index 0000000..28a2fd0
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-ky/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Телефонду колдонууга тыюу салынган MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-lo/strings.xml b/core/res/res/values-mcc001-mnc01-lo/strings.xml
new file mode 100644
index 0000000..ca560ce4
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-lo/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ໂທລະສັບ MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-lt/strings.xml b/core/res/res/values-mcc001-mnc01-lt/strings.xml
new file mode 100644
index 0000000..29f1433
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-lt/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Telefonas neleidžiamas (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-lv/strings.xml b/core/res/res/values-mcc001-mnc01-lv/strings.xml
new file mode 100644
index 0000000..0e97385
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-lv/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Tālruni nav atļauts izmantot: MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-mk/strings.xml b/core/res/res/values-mcc001-mnc01-mk/strings.xml
new file mode 100644
index 0000000..f488183
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-mk/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Телефонот не е дозволен MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-ml/strings.xml b/core/res/res/values-mcc001-mnc01-ml/strings.xml
new file mode 100644
index 0000000..20392b6
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-ml/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"ഫോൺ അനുവദനീയമല്ല MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-mn/strings.xml b/core/res/res/values-mcc001-mnc01-mn/strings.xml
new file mode 100644
index 0000000..164462b
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-mn/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Утсыг зөвшөөрөөгүй MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-mr/strings.xml b/core/res/res/values-mcc001-mnc01-mr/strings.xml
new file mode 100644
index 0000000..564573b
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-mr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"फोन MM#6 ला अनुमती देत नाही"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-ms/strings.xml b/core/res/res/values-mcc001-mnc01-ms/strings.xml
new file mode 100644
index 0000000..1399187
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-ms/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Telefon tidak dibenarkan MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-my/strings.xml b/core/res/res/values-mcc001-mnc01-my/strings.xml
new file mode 100644
index 0000000..39fa0e3
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-my/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"ဖုန်းကို ခွင့်မပြုပါ MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-nb/strings.xml b/core/res/res/values-mcc001-mnc01-nb/strings.xml
new file mode 100644
index 0000000..0d46cee
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-nb/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Telefonen er ikke tillatt, MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-ne/strings.xml b/core/res/res/values-mcc001-mnc01-ne/strings.xml
new file mode 100644
index 0000000..469aaa8
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-ne/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"फोनलाई अनुमति छैन MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-nl/strings.xml b/core/res/res/values-mcc001-mnc01-nl/strings.xml
new file mode 100644
index 0000000..adf5d3a
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-nl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Telefoon niet toegestaan MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-pa/strings.xml b/core/res/res/values-mcc001-mnc01-pa/strings.xml
new file mode 100644
index 0000000..3531088
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-pa/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"ਫ਼ੋਨ ਨੂੰ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-pl/strings.xml b/core/res/res/values-mcc001-mnc01-pl/strings.xml
new file mode 100644
index 0000000..1ee5497
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-pl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"MM#6 – telefon niedozwolony"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-pt-rBR/strings.xml b/core/res/res/values-mcc001-mnc01-pt-rBR/strings.xml
new file mode 100644
index 0000000..4eeb835
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-pt-rBR/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Smartphone não permitido MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-pt-rPT/strings.xml b/core/res/res/values-mcc001-mnc01-pt-rPT/strings.xml
new file mode 100644
index 0000000..9de5a17
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-pt-rPT/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Telemóvel não permitido MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-pt/strings.xml b/core/res/res/values-mcc001-mnc01-pt/strings.xml
new file mode 100644
index 0000000..4eeb835
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-pt/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Smartphone não permitido MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-ro/strings.xml b/core/res/res/values-mcc001-mnc01-ro/strings.xml
new file mode 100644
index 0000000..67f05da
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-ro/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Telefonul nu este permis MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-ru/strings.xml b/core/res/res/values-mcc001-mnc01-ru/strings.xml
new file mode 100644
index 0000000..59a0f40
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-ru/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Звонки запрещены (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-si/strings.xml b/core/res/res/values-mcc001-mnc01-si/strings.xml
new file mode 100644
index 0000000..bf48fd0d
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-si/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"දුරකථනය MM#6 ඉඩ නොදේ"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-sk/strings.xml b/core/res/res/values-mcc001-mnc01-sk/strings.xml
new file mode 100644
index 0000000..8c23a50
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-sk/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Telefón nie je povolený (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-sl/strings.xml b/core/res/res/values-mcc001-mnc01-sl/strings.xml
new file mode 100644
index 0000000..ef0e4f7
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-sl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Telefon ni dovoljen MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-sq/strings.xml b/core/res/res/values-mcc001-mnc01-sq/strings.xml
new file mode 100644
index 0000000..57cd6ab
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-sq/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Telefoni nuk lejohet MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-sr/strings.xml b/core/res/res/values-mcc001-mnc01-sr/strings.xml
new file mode 100644
index 0000000..a7ef974ac
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-sr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Телефон није дозвољен MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-sv/strings.xml b/core/res/res/values-mcc001-mnc01-sv/strings.xml
new file mode 100644
index 0000000..dc903f6
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-sv/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Mobil tillåts inte MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-sw/strings.xml b/core/res/res/values-mcc001-mnc01-sw/strings.xml
new file mode 100644
index 0000000..c09faee1
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-sw/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Simu hairuhusiwi MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-ta/strings.xml b/core/res/res/values-mcc001-mnc01-ta/strings.xml
new file mode 100644
index 0000000..0621e7c
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-ta/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"ஃபோன் அனுமதிக்கப்படவில்லை MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-te/strings.xml b/core/res/res/values-mcc001-mnc01-te/strings.xml
new file mode 100644
index 0000000..9e0a1fc
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-te/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"ఫోన్ అనుమతించబడదు MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-th/strings.xml b/core/res/res/values-mcc001-mnc01-th/strings.xml
new file mode 100644
index 0000000..f16f43f
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-th/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"ไม่อนุญาตให้ใช้โทรศัพท์ MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-tl/strings.xml b/core/res/res/values-mcc001-mnc01-tl/strings.xml
new file mode 100644
index 0000000..aa15f0e
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-tl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Hindi pinapahintulutan ang telepono MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-tr/strings.xml b/core/res/res/values-mcc001-mnc01-tr/strings.xml
new file mode 100644
index 0000000..7d0c4c2
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-tr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Telefona izin verilmiyor MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-uk/strings.xml b/core/res/res/values-mcc001-mnc01-uk/strings.xml
new file mode 100644
index 0000000..d791af4
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-uk/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Телефон заборонено (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-ur/strings.xml b/core/res/res/values-mcc001-mnc01-ur/strings.xml
new file mode 100644
index 0000000..3329702
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-ur/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"‏فون کی اجازت نہیں ہے MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-uz/strings.xml b/core/res/res/values-mcc001-mnc01-uz/strings.xml
new file mode 100644
index 0000000..73ac1c0
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-uz/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Chaqiruvlar taqiqlangan (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-vi/strings.xml b/core/res/res/values-mcc001-mnc01-vi/strings.xml
new file mode 100644
index 0000000..e9362de
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-vi/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Không cho phép điện thoại MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-zh-rCN/strings.xml b/core/res/res/values-mcc001-mnc01-zh-rCN/strings.xml
new file mode 100644
index 0000000..c9abc9b
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-zh-rCN/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"不受允许的手机 MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-zh-rHK/strings.xml b/core/res/res/values-mcc001-mnc01-zh-rHK/strings.xml
new file mode 100644
index 0000000..375fe31
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-zh-rHK/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"不允許手機 MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-zh-rTW/strings.xml b/core/res/res/values-mcc001-mnc01-zh-rTW/strings.xml
new file mode 100644
index 0000000..5700f01
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-zh-rTW/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"不支援的手機 MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc001-mnc01-zu/strings.xml b/core/res/res/values-mcc001-mnc01-zu/strings.xml
new file mode 100644
index 0000000..b31303f
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-zu/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="2238090225563073546">"Ifoni ayivunyelwe MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc030-af/strings.xml b/core/res/res/values-mcc310-mnc030-af/strings.xml
index 0b666c2..1b6eec8 100644
--- a/core/res/res/values-mcc310-mnc030-af/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-af/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM is nie opgestel nie MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM word nie toegelaat nie MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Foon nie toegelaat nie MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-am/strings.xml b/core/res/res/values-mcc310-mnc030-am/strings.xml
index 08c5e329..9e10ee2 100644
--- a/core/res/res/values-mcc310-mnc030-am/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-am/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"ሲም አልቀረበም MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"ሲም አይፈቀድም MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"ስልክ አይፈቀድም MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-ar/strings.xml b/core/res/res/values-mcc310-mnc030-ar/strings.xml
index 5d6a53d..51db337 100644
--- a/core/res/res/values-mcc310-mnc030-ar/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-ar/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"‏لم يتم توفير SIM ‏MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"‏غير مسموح باستخدام SIM ‏MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"‏غير مسموح باستخدام الهاتف MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-az/strings.xml b/core/res/res/values-mcc310-mnc030-az/strings.xml
index 194d189..3946a0f 100644
--- a/core/res/res/values-mcc310-mnc030-az/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-az/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM MM#2 təmin etmir"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM MM#3 dəstəkləmir"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"MM#6 telefonu dəstəklənmir"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-b+sr+Latn/strings.xml b/core/res/res/values-mcc310-mnc030-b+sr+Latn/strings.xml
index d306893..6dfa886 100644
--- a/core/res/res/values-mcc310-mnc030-b+sr+Latn/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-b+sr+Latn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM kartica nije podešena MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM kartica nije dozvoljena MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Telefon nije dozvoljen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-be/strings.xml b/core/res/res/values-mcc310-mnc030-be/strings.xml
index 12fef7a..66992cb 100644
--- a/core/res/res/values-mcc310-mnc030-be/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-be/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM-карты няма MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM-карта не дапускаецца MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Тэлефон не дапускаецца MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-bg/strings.xml b/core/res/res/values-mcc310-mnc030-bg/strings.xml
index a7c014a..336a890 100644
--- a/core/res/res/values-mcc310-mnc030-bg/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-bg/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM картата не е обезпечена MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM картата не е разрешена MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Телефонът не е разрешен MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-bn/strings.xml b/core/res/res/values-mcc310-mnc030-bn/strings.xml
index f07a3d6..f4ad84e 100644
--- a/core/res/res/values-mcc310-mnc030-bn/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-bn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"সিমের জন্য প্রস্তুত নয় MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"সিমের অনুমতি নেই MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"ফোন অনুমোদিত নয় MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-bs/strings.xml b/core/res/res/values-mcc310-mnc030-bs/strings.xml
index 1e6c7db..c17d685 100644
--- a/core/res/res/values-mcc310-mnc030-bs/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-bs/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM kartica nije dodijeljena MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM kartica nije dozvoljena MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Telefon nije dozvoljen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-ca/strings.xml b/core/res/res/values-mcc310-mnc030-ca/strings.xml
index af25f9b..1e4a752 100644
--- a/core/res/res/values-mcc310-mnc030-ca/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-ca/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"La SIM no està proporcionada a MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"La SIM no és compatible a MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Telèfon no compatible MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-cs/strings.xml b/core/res/res/values-mcc310-mnc030-cs/strings.xml
index ee0f90c..e5c0cf2 100644
--- a/core/res/res/values-mcc310-mnc030-cs/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-cs/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM karta není poskytována (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM karta není povolena (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Telefon není povolen (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-da/strings.xml b/core/res/res/values-mcc310-mnc030-da/strings.xml
index 8539f7a..dab4912 100644
--- a/core/res/res/values-mcc310-mnc030-da/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-da/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM-kort leveres ikke MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM-kort er ikke tilladt MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Telefonen har ikke adgangstilladelse MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-de/strings.xml b/core/res/res/values-mcc310-mnc030-de/strings.xml
index ad797b5..d3ff1164 100644
--- a/core/res/res/values-mcc310-mnc030-de/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-de/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM-Karte nicht eingerichtet MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM-Karte nicht zulässig MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Smartphone nicht zulässig MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-el/strings.xml b/core/res/res/values-mcc310-mnc030-el/strings.xml
index 62aa97f..22afb5f 100644
--- a/core/res/res/values-mcc310-mnc030-el/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-el/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"Δεν παρέχεται κάρτα SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"Η κάρτα SIM δεν επιτρέπεται MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Το τηλέφωνο δεν επιτρέπεται MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-en-rAU/strings.xml b/core/res/res/values-mcc310-mnc030-en-rAU/strings.xml
index 1a50ac6..c604346 100644
--- a/core/res/res/values-mcc310-mnc030-en-rAU/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-en-rAU/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-en-rCA/strings.xml b/core/res/res/values-mcc310-mnc030-en-rCA/strings.xml
index 1a50ac6..c604346 100644
--- a/core/res/res/values-mcc310-mnc030-en-rCA/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-en-rCA/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-en-rGB/strings.xml b/core/res/res/values-mcc310-mnc030-en-rGB/strings.xml
index 1a50ac6..c604346 100644
--- a/core/res/res/values-mcc310-mnc030-en-rGB/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-en-rGB/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-en-rIN/strings.xml b/core/res/res/values-mcc310-mnc030-en-rIN/strings.xml
index 1a50ac6..c604346 100644
--- a/core/res/res/values-mcc310-mnc030-en-rIN/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-en-rIN/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-en-rXC/strings.xml b/core/res/res/values-mcc310-mnc030-en-rXC/strings.xml
index 5eb9cba..6fbbcb7 100644
--- a/core/res/res/values-mcc310-mnc030-en-rXC/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-en-rXC/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‏‏‏‏‏‏‎‏‎‏‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‎‏‎‎‎‎‎‎‏‏‏‏‏‎‏‎‏‏‎‏‎‎‏‎‎‏‎‎SIM not provisioned MM#2‎‏‎‎‏‎"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‏‎‎‏‎‎‎‎‎‏‎‏‎‏‎‏‏‏‎‏‏‎‎‎‎‏‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‏‏‏‏‎‎‎SIM not allowed MM#3‎‏‎‎‏‎"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‎‏‎‎‏‏‎‏‏‎‏‎‏‎‏‎‎‎‎‎‏‏‏‎‎‎‏‎‎‎‎‏‎‎‏‏‏‏‎‏‎‎‎‎‏‎‎‎‎‏‏‎Phone not allowed MM#6‎‏‎‎‏‎"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-es-rUS/strings.xml b/core/res/res/values-mcc310-mnc030-es-rUS/strings.xml
index 87226ac..42426cb 100644
--- a/core/res/res/values-mcc310-mnc030-es-rUS/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-es-rUS/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM no provista MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM no permitida MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Teléfono no admitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-es/strings.xml b/core/res/res/values-mcc310-mnc030-es/strings.xml
index c13f5f8..ea3224d 100644
--- a/core/res/res/values-mcc310-mnc030-es/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-es/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM no proporcionada (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM no admitida (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Teléfono no admitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-et/strings.xml b/core/res/res/values-mcc310-mnc030-et/strings.xml
index 07229ab..fbcaa30 100644
--- a/core/res/res/values-mcc310-mnc030-et/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-et/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM-kaart on ette valmistamata MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM-kaart pole lubatud MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Telefon pole lubatud MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-eu/strings.xml b/core/res/res/values-mcc310-mnc030-eu/strings.xml
index 024fbab..4053e48 100644
--- a/core/res/res/values-mcc310-mnc030-eu/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-eu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"Ez dago SIM txartelik MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"Ez da onartzen SIM txartela MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Telefonoa ez da onartzen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-fa/strings.xml b/core/res/res/values-mcc310-mnc030-fa/strings.xml
index e754032..01b0ad3 100644
--- a/core/res/res/values-mcc310-mnc030-fa/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-fa/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"‏سیم‌کارت مجوز لازم را ندارد MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"‏سیم‌کارت مجاز نیست MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"‏تلفن مجاز نیست MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-fi/strings.xml b/core/res/res/values-mcc310-mnc030-fi/strings.xml
index 3b9c2ab..8e948c6 100644
--- a/core/res/res/values-mcc310-mnc030-fi/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-fi/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM-kortti ei käyttäjien hallinnassa MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM-kortti estetty MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Puhelin estetty MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-fr-rCA/strings.xml b/core/res/res/values-mcc310-mnc030-fr-rCA/strings.xml
index 31644b7..0e4f55d 100644
--- a/core/res/res/values-mcc310-mnc030-fr-rCA/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-fr-rCA/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"Carte SIM non configurée, MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"Carte SIM non autorisée, MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Téléphone non autorisé MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-fr/strings.xml b/core/res/res/values-mcc310-mnc030-fr/strings.xml
index 9c690e7..2f001db 100644
--- a/core/res/res/values-mcc310-mnc030-fr/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-fr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"Carte SIM non provisionnée MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"Carte SIM non autorisée MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Téléphone non autorisé MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-gl/strings.xml b/core/res/res/values-mcc310-mnc030-gl/strings.xml
index 59be216..fe18f6e 100644
--- a/core/res/res/values-mcc310-mnc030-gl/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-gl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"Non se introduciu ningunha tarxeta SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"Non se admite a tarxeta SIM MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Non se admite o teléfono MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-gu/strings.xml b/core/res/res/values-mcc310-mnc030-gu/strings.xml
index ac57a85..2cd3d2d 100644
--- a/core/res/res/values-mcc310-mnc030-gu/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-gu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIMને MM#2ની જોગવાઈ નથી"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIMને MM#3 કરવાની મંજૂરી નથી"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"MM#6 ફોનની મંજૂરી નથી"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-hi/strings.xml b/core/res/res/values-mcc310-mnc030-hi/strings.xml
index 244d175..a3315a8 100644
--- a/core/res/res/values-mcc310-mnc030-hi/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-hi/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM काम नहीं कर रहा है MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM की अनुमति नहीं है MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"फ़ोन की इजाज़त नहीं है MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-hr/strings.xml b/core/res/res/values-mcc310-mnc030-hr/strings.xml
index a37043c..a938a55 100644
--- a/core/res/res/values-mcc310-mnc030-hr/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-hr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"Ne pruža se usluga za SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM nije dopušten MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Telefon nije dopušten MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-hu/strings.xml b/core/res/res/values-mcc310-mnc030-hu/strings.xml
index b26b2b2..b28ce8e 100644
--- a/core/res/res/values-mcc310-mnc030-hu/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-hu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"Nem engedélyezett SIM-kártya (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"A SIM-kártya nem engedélyezett (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"A telefon nem engedélyezett (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-hy/strings.xml b/core/res/res/values-mcc310-mnc030-hy/strings.xml
index 0d052f3..34cd04e 100644
--- a/core/res/res/values-mcc310-mnc030-hy/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-hy/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM քարտը նախապատրաստված չէ (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM քարտի օգտագործումն արգելված է (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Հեռախոսի օգտագործումն արգելված է (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-in/strings.xml b/core/res/res/values-mcc310-mnc030-in/strings.xml
index f8f6613..b2a94b9 100644
--- a/core/res/res/values-mcc310-mnc030-in/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-in/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM tidak di-provisioning MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM tidak diizinkan MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Ponsel tidak diizinkan MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-is/strings.xml b/core/res/res/values-mcc310-mnc030-is/strings.xml
index 1033965..008de9d 100644
--- a/core/res/res/values-mcc310-mnc030-is/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-is/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM-korti ekki úthlutað MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM-kort ekki leyft MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Sími ekki leyfður MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-it/strings.xml b/core/res/res/values-mcc310-mnc030-it/strings.xml
index fb74a97..1b17cff2 100644
--- a/core/res/res/values-mcc310-mnc030-it/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-it/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"Scheda SIM non predisposta MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"Scheda SIM non consentita MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Telefono non consentito MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-iw/strings.xml b/core/res/res/values-mcc310-mnc030-iw/strings.xml
index 50bd517..c5350b8 100644
--- a/core/res/res/values-mcc310-mnc030-iw/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-iw/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"‏כרטיס ה-SIM לא הופעל MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"‏כרטיס ה-SIM לא מורשה לשימוש ברשת הסלולרית MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"‏הטלפון לא מורשה MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-ja/strings.xml b/core/res/res/values-mcc310-mnc030-ja/strings.xml
index 78cd78c..56fa5dd 100644
--- a/core/res/res/values-mcc310-mnc030-ja/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-ja/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM には対応していません(MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM は許可されていません(MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"電話は許可されていません(MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-ka/strings.xml b/core/res/res/values-mcc310-mnc030-ka/strings.xml
index 04d6a7d..abcaa99 100644
--- a/core/res/res/values-mcc310-mnc030-ka/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-ka/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM ბარათი უზრუნველყოფილი არ არის (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM ბარათი დაუშვებელია (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"ტელეფონი დაუშვებელია MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-kk/strings.xml b/core/res/res/values-mcc310-mnc030-kk/strings.xml
index aad588c..b84e25f 100644
--- a/core/res/res/values-mcc310-mnc030-kk/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-kk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM картасы қарастырылмаған MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM картасына рұқсат етілмеген MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Телефон пайдалануға болмайды MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-km/strings.xml b/core/res/res/values-mcc310-mnc030-km/strings.xml
index bd999274..284310a 100644
--- a/core/res/res/values-mcc310-mnc030-km/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-km/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"ស៊ីមកាត​មិនត្រូវបាន​ផ្ដល់ជូនទេ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"មិនអនុញ្ញាត​ចំពោះស៊ីមកាត​ទេ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"មិន​អនុញ្ញាត​ចំពោះ​ទូរសព្ទ​ទេ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-kn/strings.xml b/core/res/res/values-mcc310-mnc030-kn/strings.xml
index 39e9b070..402d9be 100644
--- a/core/res/res/values-mcc310-mnc030-kn/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-kn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"MM#2 ಗೆ ಸಿಮ್‌ ಸಿದ್ಧವಾಗಿಲ್ಲ"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"ಸಿಮ್‌ MM#3 ಅನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"ಫೋನ್ MM#6 ಅನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-ko/strings.xml b/core/res/res/values-mcc310-mnc030-ko/strings.xml
index 67e45b0..f9b2e5c 100644
--- a/core/res/res/values-mcc310-mnc030-ko/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-ko/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM이 프로비저닝되지 않음 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM이 허용되지 않음 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"전화가 허용되지 않음 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-ky/strings.xml b/core/res/res/values-mcc310-mnc030-ky/strings.xml
index 02ac153..a0c42fe 100644
--- a/core/res/res/values-mcc310-mnc030-ky/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-ky/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM карта таанылган жок (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM картаны колдонууга тыюу салынган (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Телефонду колдонууга тыюу салынган MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-lo/strings.xml b/core/res/res/values-mcc310-mnc030-lo/strings.xml
index b41bf91..f8f57c4 100644
--- a/core/res/res/values-mcc310-mnc030-lo/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-lo/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM ບໍ່ໄດ້ເປີດໃຊ້ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM ບໍ່ອະນຸຍາດ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ໂທລະສັບ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-lt/strings.xml b/core/res/res/values-mcc310-mnc030-lt/strings.xml
index 59c66be..2060253 100644
--- a/core/res/res/values-mcc310-mnc030-lt/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-lt/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM kortelė neteikiama (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM kortelė neleidžiama (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Telefonas neleidžiamas (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-lv/strings.xml b/core/res/res/values-mcc310-mnc030-lv/strings.xml
index 685c9b8..dd8e155 100644
--- a/core/res/res/values-mcc310-mnc030-lv/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-lv/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM karte netiek nodrošināta: MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM karti nav atļauts izmantot: MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Tālruni nav atļauts izmantot: MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-mk/strings.xml b/core/res/res/values-mcc310-mnc030-mk/strings.xml
index ce24e25..3fa9acb 100644
--- a/core/res/res/values-mcc310-mnc030-mk/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-mk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"Не е обезбедена SIM-картичка, MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"Не е дозволена SIM-картичка, MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Телефонот не е дозволен MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-ml/strings.xml b/core/res/res/values-mcc310-mnc030-ml/strings.xml
index 9adfd9c..cd69a85 100644
--- a/core/res/res/values-mcc310-mnc030-ml/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-ml/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"സിം MM#2 പ്രൊവിഷൻ ചെയ്‌തിട്ടില്ല"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"സിം MM#3 അനുവദിച്ചിട്ടില്ല"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"ഫോൺ അനുവദനീയമല്ല MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-mn/strings.xml b/core/res/res/values-mcc310-mnc030-mn/strings.xml
index 6ff2d5e..5bbbe1a 100644
--- a/core/res/res/values-mcc310-mnc030-mn/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-mn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM-г идэвхжүүлээгүй байна MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM-г зөвшөөрөөгүй байна MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Утсыг зөвшөөрөөгүй MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-mr/strings.xml b/core/res/res/values-mcc310-mnc030-mr/strings.xml
index afc40a1..56afb10 100644
--- a/core/res/res/values-mcc310-mnc030-mr/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-mr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM ने MM#2 ची तरतूद केलेली नाही"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM ने MM#3 ला परवानगी दिली नाही"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"फोन MM#6 ला अनुमती देत नाही"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-ms/strings.xml b/core/res/res/values-mcc310-mnc030-ms/strings.xml
index 9a54b04..2bcfc77 100644
--- a/core/res/res/values-mcc310-mnc030-ms/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-ms/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM tidak diperuntukkan MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM tidak dibenarkan MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Telefon tidak dibenarkan MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-my/strings.xml b/core/res/res/values-mcc310-mnc030-my/strings.xml
index 79a0791..7e8894e 100644
--- a/core/res/res/values-mcc310-mnc030-my/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-my/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"ဆင်းမ်ကို ထောက်ပံ့မထားပါ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"ဆင်းမ်ကို ခွင့်မပြုပါ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"ဖုန်းကို ခွင့်မပြုပါ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-nb/strings.xml b/core/res/res/values-mcc310-mnc030-nb/strings.xml
index 7c06dba..267353e 100644
--- a/core/res/res/values-mcc310-mnc030-nb/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-nb/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM-kortet er ikke klargjort, MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM-kortet er ikke tillatt, MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Telefonen er ikke tillatt, MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-ne/strings.xml b/core/res/res/values-mcc310-mnc030-ne/strings.xml
index 3ef06ab..dd07fc9 100644
--- a/core/res/res/values-mcc310-mnc030-ne/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-ne/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM को प्रावधान छैन MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM लाई अनुमति छैन MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"फोनलाई अनुमति छैन MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-nl/strings.xml b/core/res/res/values-mcc310-mnc030-nl/strings.xml
index 861385d1..52b52d6 100644
--- a/core/res/res/values-mcc310-mnc030-nl/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-nl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"Simkaart niet geregistreerd MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"Simkaart niet toegestaan MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Telefoon niet toegestaan MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-pa/strings.xml b/core/res/res/values-mcc310-mnc030-pa/strings.xml
index ba7b614..cefd738 100644
--- a/core/res/res/values-mcc310-mnc030-pa/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-pa/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"ਸਿਮ ਦੀ ਵਿਵਸਥਾ ਨਹੀਂ ਹੈ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"ਸਿਮ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"ਫ਼ੋਨ ਨੂੰ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-pl/strings.xml b/core/res/res/values-mcc310-mnc030-pl/strings.xml
index 84ff351..fa5720a 100644
--- a/core/res/res/values-mcc310-mnc030-pl/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-pl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"MM#2 – karta SIM nieobsługiwana"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"MM#3 – niedozwolona karta SIM"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"MM#6 – telefon niedozwolony"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-pt-rBR/strings.xml b/core/res/res/values-mcc310-mnc030-pt-rBR/strings.xml
index 2679f93..663261c 100644
--- a/core/res/res/values-mcc310-mnc030-pt-rBR/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-pt-rBR/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM não aprovisionado MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM não permitido MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Smartphone não permitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-pt-rPT/strings.xml b/core/res/res/values-mcc310-mnc030-pt-rPT/strings.xml
index 2679f93..602b59e 100644
--- a/core/res/res/values-mcc310-mnc030-pt-rPT/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-pt-rPT/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM não aprovisionado MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM não permitido MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Telemóvel não permitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-pt/strings.xml b/core/res/res/values-mcc310-mnc030-pt/strings.xml
index 2679f93..663261c 100644
--- a/core/res/res/values-mcc310-mnc030-pt/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-pt/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM não aprovisionado MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM não permitido MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Smartphone não permitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-ro/strings.xml b/core/res/res/values-mcc310-mnc030-ro/strings.xml
index 5bae0c0..77d374c 100644
--- a/core/res/res/values-mcc310-mnc030-ro/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-ro/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"Cardul SIM nu este activat MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"Cardul SIM nu este permis MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Telefonul nu este permis MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-ru/strings.xml b/core/res/res/values-mcc310-mnc030-ru/strings.xml
index 658badf..c2ca9d3 100644
--- a/core/res/res/values-mcc310-mnc030-ru/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-ru/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM-карта не активирована (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"Использование SIM-карты запрещено (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Звонки запрещены (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-si/strings.xml b/core/res/res/values-mcc310-mnc030-si/strings.xml
index 635ffa4..9b9b1b7 100644
--- a/core/res/res/values-mcc310-mnc030-si/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-si/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM MM#2 ප්‍රතිපාදනය නොකරයි"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM MM#3 ඉඩ නොදේ"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"දුරකථනය MM#6 ඉඩ නොදේ"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-sk/strings.xml b/core/res/res/values-mcc310-mnc030-sk/strings.xml
index 2a046b6..968fd2d 100644
--- a/core/res/res/values-mcc310-mnc030-sk/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-sk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM karta nie je k dispozícii – MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM karta je zakázaná – MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Telefón nie je povolený (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-sl/strings.xml b/core/res/res/values-mcc310-mnc030-sl/strings.xml
index 7321e4d..dcbf3e2 100644
--- a/core/res/res/values-mcc310-mnc030-sl/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-sl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"Kartica SIM ni omogočena za uporabo MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"Kartica SIM ni dovoljena MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Telefon ni dovoljen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-sq/strings.xml b/core/res/res/values-mcc310-mnc030-sq/strings.xml
index e553f01..4ea64fd 100644
--- a/core/res/res/values-mcc310-mnc030-sq/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-sq/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"Karta SIM nuk është dhënë MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"Karta SIM nuk lejohet MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Telefoni nuk lejohet MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-sr/strings.xml b/core/res/res/values-mcc310-mnc030-sr/strings.xml
index 945e2fc..2f36c77 100644
--- a/core/res/res/values-mcc310-mnc030-sr/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-sr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM картица није подешена MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM картица није дозвољена MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Телефон није дозвољен MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-sv/strings.xml b/core/res/res/values-mcc310-mnc030-sv/strings.xml
index 5f0cc46..bac0d61 100644
--- a/core/res/res/values-mcc310-mnc030-sv/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-sv/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM-kort tillhandahålls inte MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM-kort tillåts inte MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Mobil tillåts inte MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-sw/strings.xml b/core/res/res/values-mcc310-mnc030-sw/strings.xml
index fbd2076..c26e864 100644
--- a/core/res/res/values-mcc310-mnc030-sw/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-sw/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM haitumiki MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM hairuhusiwi MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Simu hairuhusiwi MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-ta/strings.xml b/core/res/res/values-mcc310-mnc030-ta/strings.xml
index 6fc3df6..661c813 100644
--- a/core/res/res/values-mcc310-mnc030-ta/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-ta/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"சிம் அமைக்கப்படவில்லை MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"சிம் அனுமதிக்கப்படவில்லை MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"ஃபோன் அனுமதிக்கப்படவில்லை MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-te/strings.xml b/core/res/res/values-mcc310-mnc030-te/strings.xml
index 4c61791..12a0d70 100644
--- a/core/res/res/values-mcc310-mnc030-te/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-te/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM MM#2ని సక్రియం చేయలేదు"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM MM#3ని అనుమతించలేదు"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"ఫోన్ అనుమతించబడదు MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-th/strings.xml b/core/res/res/values-mcc310-mnc030-th/strings.xml
index 9a8ee74..d4b2dc4 100644
--- a/core/res/res/values-mcc310-mnc030-th/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-th/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"ไม่มีการจัดสรรซิม MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"ไม่อนุญาตให้ใช้ซิม MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"ไม่อนุญาตให้ใช้โทรศัพท์ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-tl/strings.xml b/core/res/res/values-mcc310-mnc030-tl/strings.xml
index 6408f4e..41d3924 100644
--- a/core/res/res/values-mcc310-mnc030-tl/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-tl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"Hindi na-provision ang SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"Hindi pinapahintulutan ang SIM MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Hindi pinapahintulutan ang telepono MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-tr/strings.xml b/core/res/res/values-mcc310-mnc030-tr/strings.xml
index 361ee9c..aab27e2 100644
--- a/core/res/res/values-mcc310-mnc030-tr/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-tr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM, MM#2\'nin temel hazırlığını yapamadı"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM MM#3\'e izin vermiyor"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Telefona izin verilmiyor MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-uk/strings.xml b/core/res/res/values-mcc310-mnc030-uk/strings.xml
index efee94e..9e0cd4c 100644
--- a/core/res/res/values-mcc310-mnc030-uk/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-uk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM-карту не надано (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM-карта заборонена (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Телефон заборонено (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-ur/strings.xml b/core/res/res/values-mcc310-mnc030-ur/strings.xml
index a0e5fd6..e704516 100644
--- a/core/res/res/values-mcc310-mnc030-ur/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-ur/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"‏SIM فراہم کردہ نہیں ہے MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"‏SIM کی اجازت نہیں ہے MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"‏فون کی اجازت نہیں ہے MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-uz/strings.xml b/core/res/res/values-mcc310-mnc030-uz/strings.xml
index 7eb641a..c7ae871 100644
--- a/core/res/res/values-mcc310-mnc030-uz/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-uz/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM karta ishlatish taqiqlangan (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM karta ishlatish taqiqlangan (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Chaqiruvlar taqiqlangan (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-vi/strings.xml b/core/res/res/values-mcc310-mnc030-vi/strings.xml
index 362ee6a..bd87e0d 100644
--- a/core/res/res/values-mcc310-mnc030-vi/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-vi/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM không được cấp phép MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM không được phép MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Không cho phép điện thoại MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-zh-rCN/strings.xml b/core/res/res/values-mcc310-mnc030-zh-rCN/strings.xml
index efa43f5..441eb3f 100644
--- a/core/res/res/values-mcc310-mnc030-zh-rCN/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-zh-rCN/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"未配置的 SIM 卡 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"不被允许的 SIM 卡 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"不受允许的手机 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-zh-rHK/strings.xml b/core/res/res/values-mcc310-mnc030-zh-rHK/strings.xml
index c163544..7f3a94c4 100644
--- a/core/res/res/values-mcc310-mnc030-zh-rHK/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-zh-rHK/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"未佈建的 SIM 卡 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"不支援的 SIM 卡 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"不允許手機 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-zh-rTW/strings.xml b/core/res/res/values-mcc310-mnc030-zh-rTW/strings.xml
index c163544..a4baf62 100644
--- a/core/res/res/values-mcc310-mnc030-zh-rTW/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-zh-rTW/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"未佈建的 SIM 卡 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"不支援的 SIM 卡 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"不支援的手機 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc030-zu/strings.xml b/core/res/res/values-mcc310-mnc030-zu/strings.xml
index 720fa82..0142a35 100644
--- a/core/res/res/values-mcc310-mnc030-zu/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-zu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"I-SIM ayinikezelwe MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1930079814544869756">"I-SIM ayivunyelwe MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="2995576894416087107">"Ifoni ayivunyelwe MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc150-af/strings.xml b/core/res/res/values-mcc310-mnc150-af/strings.xml
new file mode 100644
index 0000000..bfc24ab
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-af/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Foon nie toegelaat nie MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-am/strings.xml b/core/res/res/values-mcc310-mnc150-am/strings.xml
new file mode 100644
index 0000000..c75ae67
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-am/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"ስልክ አይፈቀድም MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-ar/strings.xml b/core/res/res/values-mcc310-mnc150-ar/strings.xml
new file mode 100644
index 0000000..a3a5d85
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-ar/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"‏غير مسموح باستخدام الهاتف MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-az/strings.xml b/core/res/res/values-mcc310-mnc150-az/strings.xml
new file mode 100644
index 0000000..4c7a339
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-az/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"MM#6 telefonu dəstəklənmir"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-b+sr+Latn/strings.xml b/core/res/res/values-mcc310-mnc150-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..d40e0bf
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-b+sr+Latn/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Telefon nije dozvoljen MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-be/strings.xml b/core/res/res/values-mcc310-mnc150-be/strings.xml
new file mode 100644
index 0000000..31caa9a
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-be/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Тэлефон не дапускаецца MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-bg/strings.xml b/core/res/res/values-mcc310-mnc150-bg/strings.xml
new file mode 100644
index 0000000..70445e1
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-bg/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Телефонът не е разрешен MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-bn/strings.xml b/core/res/res/values-mcc310-mnc150-bn/strings.xml
new file mode 100644
index 0000000..25dc744
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-bn/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"ফোন অনুমোদিত নয় MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-bs/strings.xml b/core/res/res/values-mcc310-mnc150-bs/strings.xml
new file mode 100644
index 0000000..be60b92
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-bs/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Telefon nije dozvoljen  MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-ca/strings.xml b/core/res/res/values-mcc310-mnc150-ca/strings.xml
new file mode 100644
index 0000000..836aab0
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-ca/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Telèfon no compatible MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-cs/strings.xml b/core/res/res/values-mcc310-mnc150-cs/strings.xml
new file mode 100644
index 0000000..f31b34e
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-cs/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Telefon není povolen (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-da/strings.xml b/core/res/res/values-mcc310-mnc150-da/strings.xml
new file mode 100644
index 0000000..1213be0
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-da/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Telefonen har ikke adgangstilladelse MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-de/strings.xml b/core/res/res/values-mcc310-mnc150-de/strings.xml
new file mode 100644
index 0000000..7fdf306
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-de/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Smartphone nicht zulässig MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-el/strings.xml b/core/res/res/values-mcc310-mnc150-el/strings.xml
new file mode 100644
index 0000000..9dfeb6c
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-el/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Το τηλέφωνο δεν επιτρέπεται MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-en-rAU/strings.xml b/core/res/res/values-mcc310-mnc150-en-rAU/strings.xml
new file mode 100644
index 0000000..afeb95e
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-en-rAU/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Phone not allowed MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-en-rCA/strings.xml b/core/res/res/values-mcc310-mnc150-en-rCA/strings.xml
new file mode 100644
index 0000000..afeb95e
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-en-rCA/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Phone not allowed MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-en-rGB/strings.xml b/core/res/res/values-mcc310-mnc150-en-rGB/strings.xml
new file mode 100644
index 0000000..afeb95e
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-en-rGB/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Phone not allowed MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-en-rIN/strings.xml b/core/res/res/values-mcc310-mnc150-en-rIN/strings.xml
new file mode 100644
index 0000000..afeb95e
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-en-rIN/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Phone not allowed MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-en-rXC/strings.xml b/core/res/res/values-mcc310-mnc150-en-rXC/strings.xml
new file mode 100644
index 0000000..c3d43d9
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-en-rXC/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‎‎‎‏‎‏‎‎‏‎‎‎‎‎‎‎‏‏‎‎‏‏‎‎‏‎‎‏‎‎‎‏‏‎‎‎‏‏‏‏‎‏‎‎‏‏‎‏‎‏‏‎‏‏‎Phone not allowed MM#6‎‏‎‎‏‎"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-es-rUS/strings.xml b/core/res/res/values-mcc310-mnc150-es-rUS/strings.xml
new file mode 100644
index 0000000..4ed5253
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-es-rUS/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Teléfono no admitido MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-es/strings.xml b/core/res/res/values-mcc310-mnc150-es/strings.xml
new file mode 100644
index 0000000..4ed5253
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-es/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Teléfono no admitido MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-et/strings.xml b/core/res/res/values-mcc310-mnc150-et/strings.xml
new file mode 100644
index 0000000..6cb111e
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-et/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Telefon pole lubatud MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-eu/strings.xml b/core/res/res/values-mcc310-mnc150-eu/strings.xml
new file mode 100644
index 0000000..a38ed44d
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-eu/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Telefonoa ez da onartzen MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-fa/strings.xml b/core/res/res/values-mcc310-mnc150-fa/strings.xml
new file mode 100644
index 0000000..bb52d79
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-fa/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"‏تلفن مجاز نیست MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-fi/strings.xml b/core/res/res/values-mcc310-mnc150-fi/strings.xml
new file mode 100644
index 0000000..d1eff31
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-fi/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Puhelin estetty MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-fr-rCA/strings.xml b/core/res/res/values-mcc310-mnc150-fr-rCA/strings.xml
new file mode 100644
index 0000000..335a0e8
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-fr-rCA/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Téléphone non autorisé MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-fr/strings.xml b/core/res/res/values-mcc310-mnc150-fr/strings.xml
new file mode 100644
index 0000000..335a0e8
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-fr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Téléphone non autorisé MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-gl/strings.xml b/core/res/res/values-mcc310-mnc150-gl/strings.xml
new file mode 100644
index 0000000..23faa0641
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-gl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Non se admite o teléfono MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-gu/strings.xml b/core/res/res/values-mcc310-mnc150-gu/strings.xml
new file mode 100644
index 0000000..95f89a0
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-gu/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"MM#6 ફોનની મંજૂરી નથી"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-hi/strings.xml b/core/res/res/values-mcc310-mnc150-hi/strings.xml
new file mode 100644
index 0000000..1b88f5b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-hi/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"फ़ोन की इजाज़त नहीं है MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-hr/strings.xml b/core/res/res/values-mcc310-mnc150-hr/strings.xml
new file mode 100644
index 0000000..85bc29b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-hr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Telefon nije dopušten MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-hu/strings.xml b/core/res/res/values-mcc310-mnc150-hu/strings.xml
new file mode 100644
index 0000000..e741ab3
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-hu/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"A telefon nem engedélyezett (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-hy/strings.xml b/core/res/res/values-mcc310-mnc150-hy/strings.xml
new file mode 100644
index 0000000..c6ec7d3
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-hy/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Հեռախոսի օգտագործումն արգելված է (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-in/strings.xml b/core/res/res/values-mcc310-mnc150-in/strings.xml
new file mode 100644
index 0000000..8a4fb2a
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-in/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Ponsel tidak diizinkan MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-is/strings.xml b/core/res/res/values-mcc310-mnc150-is/strings.xml
new file mode 100644
index 0000000..3c1a883
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-is/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Sími ekki leyfður MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-it/strings.xml b/core/res/res/values-mcc310-mnc150-it/strings.xml
new file mode 100644
index 0000000..1fed454
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-it/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Telefono non consentito MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-iw/strings.xml b/core/res/res/values-mcc310-mnc150-iw/strings.xml
new file mode 100644
index 0000000..f5e73d5
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-iw/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"‏הטלפון לא מורשה MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-ja/strings.xml b/core/res/res/values-mcc310-mnc150-ja/strings.xml
new file mode 100644
index 0000000..9b4a071
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-ja/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"電話は許可されていません(MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-ka/strings.xml b/core/res/res/values-mcc310-mnc150-ka/strings.xml
new file mode 100644
index 0000000..5387ec5
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-ka/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"ტელეფონი დაუშვებელია MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-kk/strings.xml b/core/res/res/values-mcc310-mnc150-kk/strings.xml
new file mode 100644
index 0000000..b8b20fd
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-kk/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Телефон пайдалануға болмайды MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-km/strings.xml b/core/res/res/values-mcc310-mnc150-km/strings.xml
new file mode 100644
index 0000000..032f361
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-km/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"មិន​អនុញ្ញាត​ចំពោះ​ទូរសព្ទ​ទេ MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-kn/strings.xml b/core/res/res/values-mcc310-mnc150-kn/strings.xml
new file mode 100644
index 0000000..629d8b8
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-kn/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"ಫೋನ್ MM#6 ಅನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-ko/strings.xml b/core/res/res/values-mcc310-mnc150-ko/strings.xml
new file mode 100644
index 0000000..94314c4
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-ko/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"전화가 허용되지 않음 MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-ky/strings.xml b/core/res/res/values-mcc310-mnc150-ky/strings.xml
new file mode 100644
index 0000000..238bef7
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-ky/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Телефонду колдонууга тыюу салынган MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-lo/strings.xml b/core/res/res/values-mcc310-mnc150-lo/strings.xml
new file mode 100644
index 0000000..fb7fcc2
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-lo/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ໂທລະສັບ MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-lt/strings.xml b/core/res/res/values-mcc310-mnc150-lt/strings.xml
new file mode 100644
index 0000000..59fa06a
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-lt/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Telefonas neleidžiamas (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-lv/strings.xml b/core/res/res/values-mcc310-mnc150-lv/strings.xml
new file mode 100644
index 0000000..c1021d7
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-lv/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Tālruni nav atļauts izmantot: MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-mk/strings.xml b/core/res/res/values-mcc310-mnc150-mk/strings.xml
new file mode 100644
index 0000000..934e03c
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-mk/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Телефонот не е дозволен MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-ml/strings.xml b/core/res/res/values-mcc310-mnc150-ml/strings.xml
new file mode 100644
index 0000000..4efb94b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-ml/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"ഫോൺ അനുവദനീയമല്ല MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-mn/strings.xml b/core/res/res/values-mcc310-mnc150-mn/strings.xml
new file mode 100644
index 0000000..4a56ecf
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-mn/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Утсыг зөвшөөрөөгүй MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-mr/strings.xml b/core/res/res/values-mcc310-mnc150-mr/strings.xml
new file mode 100644
index 0000000..3797f53
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-mr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"फोन MM#6 ला अनुमती देत नाही"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-ms/strings.xml b/core/res/res/values-mcc310-mnc150-ms/strings.xml
new file mode 100644
index 0000000..7fe8b74
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-ms/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Telefon tidak dibenarkan MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-my/strings.xml b/core/res/res/values-mcc310-mnc150-my/strings.xml
new file mode 100644
index 0000000..c1b0918
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-my/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"ဖုန်းကို ခွင့်မပြုပါ MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-nb/strings.xml b/core/res/res/values-mcc310-mnc150-nb/strings.xml
new file mode 100644
index 0000000..a792c97
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-nb/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Telefonen er ikke tillatt, MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-ne/strings.xml b/core/res/res/values-mcc310-mnc150-ne/strings.xml
new file mode 100644
index 0000000..bc94555
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-ne/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"फोनलाई अनुमति छैन MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-nl/strings.xml b/core/res/res/values-mcc310-mnc150-nl/strings.xml
new file mode 100644
index 0000000..219c0c3
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-nl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Telefoon niet toegestaan MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-pa/strings.xml b/core/res/res/values-mcc310-mnc150-pa/strings.xml
new file mode 100644
index 0000000..18216f3
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-pa/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"ਫ਼ੋਨ ਨੂੰ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-pl/strings.xml b/core/res/res/values-mcc310-mnc150-pl/strings.xml
new file mode 100644
index 0000000..a696993a
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-pl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"MM#6 – telefon niedozwolony"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-pt-rBR/strings.xml b/core/res/res/values-mcc310-mnc150-pt-rBR/strings.xml
new file mode 100644
index 0000000..1163c91
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-pt-rBR/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Smartphone não permitido MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-pt-rPT/strings.xml b/core/res/res/values-mcc310-mnc150-pt-rPT/strings.xml
new file mode 100644
index 0000000..13bcac8
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-pt-rPT/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Telemóvel não permitido MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-pt/strings.xml b/core/res/res/values-mcc310-mnc150-pt/strings.xml
new file mode 100644
index 0000000..1163c91
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-pt/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Smartphone não permitido MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-ro/strings.xml b/core/res/res/values-mcc310-mnc150-ro/strings.xml
new file mode 100644
index 0000000..200b59d
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-ro/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Telefonul nu este permis MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-ru/strings.xml b/core/res/res/values-mcc310-mnc150-ru/strings.xml
new file mode 100644
index 0000000..7118395
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-ru/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Звонки запрещены (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-si/strings.xml b/core/res/res/values-mcc310-mnc150-si/strings.xml
new file mode 100644
index 0000000..c198a38
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-si/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"දුරකථනය MM#6 ඉඩ නොදේ"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-sk/strings.xml b/core/res/res/values-mcc310-mnc150-sk/strings.xml
new file mode 100644
index 0000000..0a0d119
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-sk/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Telefón nie je povolený (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-sl/strings.xml b/core/res/res/values-mcc310-mnc150-sl/strings.xml
new file mode 100644
index 0000000..cebc04a
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-sl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Telefon ni dovoljen MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-sq/strings.xml b/core/res/res/values-mcc310-mnc150-sq/strings.xml
new file mode 100644
index 0000000..2daf805
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-sq/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Telefoni nuk lejohet MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-sr/strings.xml b/core/res/res/values-mcc310-mnc150-sr/strings.xml
new file mode 100644
index 0000000..40ac0c2
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-sr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Телефон није дозвољен MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-sv/strings.xml b/core/res/res/values-mcc310-mnc150-sv/strings.xml
new file mode 100644
index 0000000..5f1a340
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-sv/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Mobil tillåts inte MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-sw/strings.xml b/core/res/res/values-mcc310-mnc150-sw/strings.xml
new file mode 100644
index 0000000..db3201d
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-sw/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Simu hairuhusiwi MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-ta/strings.xml b/core/res/res/values-mcc310-mnc150-ta/strings.xml
new file mode 100644
index 0000000..6177db2
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-ta/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"ஃபோன் அனுமதிக்கப்படவில்லை MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-te/strings.xml b/core/res/res/values-mcc310-mnc150-te/strings.xml
new file mode 100644
index 0000000..e8bb029
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-te/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"ఫోన్ అనుమతించబడదు MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-th/strings.xml b/core/res/res/values-mcc310-mnc150-th/strings.xml
new file mode 100644
index 0000000..e047ebe
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-th/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"ไม่อนุญาตให้ใช้โทรศัพท์ MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-tl/strings.xml b/core/res/res/values-mcc310-mnc150-tl/strings.xml
new file mode 100644
index 0000000..550acde
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-tl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Hindi pinapahintulutan ang telepono MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-tr/strings.xml b/core/res/res/values-mcc310-mnc150-tr/strings.xml
new file mode 100644
index 0000000..60615bb
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-tr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Telefona izin verilmiyor MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-uk/strings.xml b/core/res/res/values-mcc310-mnc150-uk/strings.xml
new file mode 100644
index 0000000..b709f6e
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-uk/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Телефон заборонено (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-ur/strings.xml b/core/res/res/values-mcc310-mnc150-ur/strings.xml
new file mode 100644
index 0000000..fe29e15
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-ur/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"‏فون کی اجازت نہیں ہے MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-uz/strings.xml b/core/res/res/values-mcc310-mnc150-uz/strings.xml
new file mode 100644
index 0000000..e1372d1
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-uz/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Chaqiruvlar taqiqlangan (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-vi/strings.xml b/core/res/res/values-mcc310-mnc150-vi/strings.xml
new file mode 100644
index 0000000..85a7c62
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-vi/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Không cho phép điện thoại MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-zh-rCN/strings.xml b/core/res/res/values-mcc310-mnc150-zh-rCN/strings.xml
new file mode 100644
index 0000000..9319941
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-zh-rCN/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"不受允许的手机 MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-zh-rHK/strings.xml b/core/res/res/values-mcc310-mnc150-zh-rHK/strings.xml
new file mode 100644
index 0000000..092d780
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-zh-rHK/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"不允許手機 MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-zh-rTW/strings.xml b/core/res/res/values-mcc310-mnc150-zh-rTW/strings.xml
new file mode 100644
index 0000000..f8d43ed
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-zh-rTW/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"不支援的手機 MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-zu/strings.xml b/core/res/res/values-mcc310-mnc150-zu/strings.xml
new file mode 100644
index 0000000..4d0f31d
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-zu/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="5207603948149789531">"Ifoni ayivunyelwe MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc170-af/strings.xml b/core/res/res/values-mcc310-mnc170-af/strings.xml
index 4256d3a..00c2835 100644
--- a/core/res/res/values-mcc310-mnc170-af/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-af/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM is nie opgestel nie MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM word nie toegelaat nie MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Foon nie toegelaat nie MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-am/strings.xml b/core/res/res/values-mcc310-mnc170-am/strings.xml
index 311d9e1..961fa69 100644
--- a/core/res/res/values-mcc310-mnc170-am/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-am/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"ሲም አልቀረበም MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"ሲም አይፈቀድም MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"ስልክ አይፈቀድም MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-ar/strings.xml b/core/res/res/values-mcc310-mnc170-ar/strings.xml
index a80ff2e2..3ad58f5 100644
--- a/core/res/res/values-mcc310-mnc170-ar/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-ar/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"‏لم يتم توفير SIM ‏MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"‏غير مسموح باستخدام SIM ‏MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"‏غير مسموح باستخدام الهاتف MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-az/strings.xml b/core/res/res/values-mcc310-mnc170-az/strings.xml
index a690668..43491fa 100644
--- a/core/res/res/values-mcc310-mnc170-az/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-az/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM MM#2 təmin etmir"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM MM#3 dəstəkləmir"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"MM#6 telefonu dəstəklənmir"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-b+sr+Latn/strings.xml b/core/res/res/values-mcc310-mnc170-b+sr+Latn/strings.xml
index b2da8a7..f47ef72 100644
--- a/core/res/res/values-mcc310-mnc170-b+sr+Latn/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-b+sr+Latn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM kartica nije podešena MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM kartica nije dozvoljena MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Telefon nije dozvoljen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-be/strings.xml b/core/res/res/values-mcc310-mnc170-be/strings.xml
index fb7f556..f596195 100644
--- a/core/res/res/values-mcc310-mnc170-be/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-be/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM-карты няма MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM-карта не дапускаецца MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Тэлефон не дапускаецца MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-bg/strings.xml b/core/res/res/values-mcc310-mnc170-bg/strings.xml
index 1158b3b..b93c5c1 100644
--- a/core/res/res/values-mcc310-mnc170-bg/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-bg/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM картата не е обезпечена MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM картата не е разрешена MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Телефонът не е разрешен MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-bn/strings.xml b/core/res/res/values-mcc310-mnc170-bn/strings.xml
index 4e6d41b..1c22bc1 100644
--- a/core/res/res/values-mcc310-mnc170-bn/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-bn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"সিমের জন্য প্রস্তুত নয় MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"সিমের অনুমতি নেই MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"ফোন অনুমোদিত নয় MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-bs/strings.xml b/core/res/res/values-mcc310-mnc170-bs/strings.xml
index d3f3e3b..4a2cb6f 100644
--- a/core/res/res/values-mcc310-mnc170-bs/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-bs/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM kartica nije dodijeljena MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM kartica nije dozvoljena MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Telefon nije dozvoljen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-ca/strings.xml b/core/res/res/values-mcc310-mnc170-ca/strings.xml
index 9abeeb7..c82d5a5 100644
--- a/core/res/res/values-mcc310-mnc170-ca/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-ca/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"La SIM no està proporcionada a MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"La SIM no és compatible a MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Telèfon no compatible MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-cs/strings.xml b/core/res/res/values-mcc310-mnc170-cs/strings.xml
index 2d4d2fb..2443292 100644
--- a/core/res/res/values-mcc310-mnc170-cs/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-cs/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM karta není poskytována (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM karta není povolena (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Telefon není povolen (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-da/strings.xml b/core/res/res/values-mcc310-mnc170-da/strings.xml
index ae2155fa..98ab336 100644
--- a/core/res/res/values-mcc310-mnc170-da/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-da/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM-kort leveres ikke MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM-kort er ikke tilladt MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Telefonen har ikke adgangstilladelse MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-de/strings.xml b/core/res/res/values-mcc310-mnc170-de/strings.xml
index f7c5eec..f3c0b9a 100644
--- a/core/res/res/values-mcc310-mnc170-de/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-de/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM-Karte nicht eingerichtet MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM-Karte nicht zulässig MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Smartphone nicht zulässig MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-el/strings.xml b/core/res/res/values-mcc310-mnc170-el/strings.xml
index 68b7008..42000eb 100644
--- a/core/res/res/values-mcc310-mnc170-el/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-el/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"Δεν παρέχεται κάρτα SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"Η κάρτα SIM δεν επιτρέπεται MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Το τηλέφωνο δεν επιτρέπεται MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-en-rAU/strings.xml b/core/res/res/values-mcc310-mnc170-en-rAU/strings.xml
index fd16620..d389436 100644
--- a/core/res/res/values-mcc310-mnc170-en-rAU/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-en-rAU/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-en-rCA/strings.xml b/core/res/res/values-mcc310-mnc170-en-rCA/strings.xml
index fd16620..d389436 100644
--- a/core/res/res/values-mcc310-mnc170-en-rCA/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-en-rCA/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-en-rGB/strings.xml b/core/res/res/values-mcc310-mnc170-en-rGB/strings.xml
index fd16620..d389436 100644
--- a/core/res/res/values-mcc310-mnc170-en-rGB/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-en-rGB/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-en-rIN/strings.xml b/core/res/res/values-mcc310-mnc170-en-rIN/strings.xml
index fd16620..d389436 100644
--- a/core/res/res/values-mcc310-mnc170-en-rIN/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-en-rIN/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-en-rXC/strings.xml b/core/res/res/values-mcc310-mnc170-en-rXC/strings.xml
index 71d087e..054db20 100644
--- a/core/res/res/values-mcc310-mnc170-en-rXC/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-en-rXC/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‏‎‏‎‏‎‏‏‎‎‎‏‎‎‎‎‏‎‎‎‏‏‎‎‏‎‎‏‎‎‏‏‎‎‎‎‎‏‎‎‏‎‎‏‎‏‎‎‎SIM not provisioned MM#2‎‏‎‎‏‎"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎‎‎‎‎‏‏‎‏‏‎‎‎‎‎‏‎‎‏‏‎‏‎‎‎‏‏‏‏‎‏‎‏‏‎‎‎‎‎‏‎‎‎‏‎‎SIM not allowed MM#3‎‏‎‎‏‎"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‎‎‎‎‏‎‏‎‏‎‏‏‎‎‏‏‏‎‏‎‎‎‎‎‏‏‏‎‏‎‎‏‏‎‎‏‏‏‏‏‎‏‎‎‏‏‎‎‎‎‏‏‎‎‎‏‎Phone not allowed MM#6‎‏‎‎‏‎"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-es-rUS/strings.xml b/core/res/res/values-mcc310-mnc170-es-rUS/strings.xml
index 50d3c12..c794ad8 100644
--- a/core/res/res/values-mcc310-mnc170-es-rUS/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-es-rUS/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM no provista MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM no permitida MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Teléfono no admitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-es/strings.xml b/core/res/res/values-mcc310-mnc170-es/strings.xml
index 7191d04..5e0852a 100644
--- a/core/res/res/values-mcc310-mnc170-es/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-es/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM no proporcionada (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM no admitida (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Teléfono no admitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-et/strings.xml b/core/res/res/values-mcc310-mnc170-et/strings.xml
index 7159bf9..24a004f 100644
--- a/core/res/res/values-mcc310-mnc170-et/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-et/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM-kaart on ette valmistamata MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM-kaart pole lubatud MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Telefon pole lubatud MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-eu/strings.xml b/core/res/res/values-mcc310-mnc170-eu/strings.xml
index 797f988..4f7b0d1 100644
--- a/core/res/res/values-mcc310-mnc170-eu/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-eu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"Ez dago SIM txartelik MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"Ez da onartzen SIM txartela MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Telefonoa ez da onartzen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-fa/strings.xml b/core/res/res/values-mcc310-mnc170-fa/strings.xml
index 968f952..1a516c4 100644
--- a/core/res/res/values-mcc310-mnc170-fa/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-fa/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"‏سیم‌کارت مجوز لازم را ندارد MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"‏سیم‌کارت مجاز نیست MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"‏تلفن مجاز نیست MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-fi/strings.xml b/core/res/res/values-mcc310-mnc170-fi/strings.xml
index c0523f4..e638085 100644
--- a/core/res/res/values-mcc310-mnc170-fi/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-fi/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM-kortti ei käyttäjien hallinnassa MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM-kortti estetty MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Puhelin estetty MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-fr-rCA/strings.xml b/core/res/res/values-mcc310-mnc170-fr-rCA/strings.xml
index 5600fa4..3b87213 100644
--- a/core/res/res/values-mcc310-mnc170-fr-rCA/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-fr-rCA/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"Carte SIM non configurée, MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"Carte SIM non autorisée, MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Téléphone non autorisé MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-fr/strings.xml b/core/res/res/values-mcc310-mnc170-fr/strings.xml
index 73b4f0e..0f6adf0 100644
--- a/core/res/res/values-mcc310-mnc170-fr/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-fr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"Carte SIM non provisionnée MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"Carte SIM non autorisée MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Téléphone non autorisé MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-gl/strings.xml b/core/res/res/values-mcc310-mnc170-gl/strings.xml
index fe13211..a2513d2 100644
--- a/core/res/res/values-mcc310-mnc170-gl/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-gl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"Non se introduciu ningunha tarxeta SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"Non se admite a tarxeta SIM MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Non se admite o teléfono MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-gu/strings.xml b/core/res/res/values-mcc310-mnc170-gu/strings.xml
index 60eba5b..adf23e4 100644
--- a/core/res/res/values-mcc310-mnc170-gu/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-gu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIMને MM#2ની જોગવાઈ નથી"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIMને MM#3 કરવાની મંજૂરી નથી"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"MM#6 ફોનની મંજૂરી નથી"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-hi/strings.xml b/core/res/res/values-mcc310-mnc170-hi/strings.xml
index eb350b0..134dbc1 100644
--- a/core/res/res/values-mcc310-mnc170-hi/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-hi/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM काम नहीं कर रहा है MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM की अनुमति नहीं है MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"फ़ोन की इजाज़त नहीं है MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-hr/strings.xml b/core/res/res/values-mcc310-mnc170-hr/strings.xml
index d5cf025..e640ae5 100644
--- a/core/res/res/values-mcc310-mnc170-hr/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-hr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"Ne pruža se usluga za SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM nije dopušten MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Telefon nije dopušten MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-hu/strings.xml b/core/res/res/values-mcc310-mnc170-hu/strings.xml
index e05e700..8d6dd9f 100644
--- a/core/res/res/values-mcc310-mnc170-hu/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-hu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"Nem engedélyezett SIM-kártya (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"A SIM-kártya nem engedélyezett (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"A telefon nem engedélyezett (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-hy/strings.xml b/core/res/res/values-mcc310-mnc170-hy/strings.xml
index 90a5f6d..3c30292 100644
--- a/core/res/res/values-mcc310-mnc170-hy/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-hy/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM քարտը նախապատրաստված չէ (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM քարտի օգտագործումն արգելված է (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Հեռախոսի օգտագործումն արգելված է (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-in/strings.xml b/core/res/res/values-mcc310-mnc170-in/strings.xml
index fc1bd0a..51a82df 100644
--- a/core/res/res/values-mcc310-mnc170-in/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-in/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM tidak di-provisioning MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM tidak diizinkan MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Ponsel tidak diizinkan MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-is/strings.xml b/core/res/res/values-mcc310-mnc170-is/strings.xml
index eef786c..e9c6d48 100644
--- a/core/res/res/values-mcc310-mnc170-is/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-is/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM-korti ekki úthlutað MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM-kort ekki leyft MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Sími ekki leyfður MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-it/strings.xml b/core/res/res/values-mcc310-mnc170-it/strings.xml
index eaf0abc..8e97b1b 100644
--- a/core/res/res/values-mcc310-mnc170-it/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-it/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"Scheda SIM non predisposta MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"Scheda SIM non consentita MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Telefono non consentito MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-iw/strings.xml b/core/res/res/values-mcc310-mnc170-iw/strings.xml
index edee703..cd818d6 100644
--- a/core/res/res/values-mcc310-mnc170-iw/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-iw/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"‏כרטיס ה-SIM לא הופעל MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"‏כרטיס ה-SIM לא מורשה לשימוש ברשת הסלולרית MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"‏הטלפון לא מורשה MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-ja/strings.xml b/core/res/res/values-mcc310-mnc170-ja/strings.xml
index 6942641..b019dd1 100644
--- a/core/res/res/values-mcc310-mnc170-ja/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-ja/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM には対応していません(MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM は許可されていません(MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"電話は許可されていません(MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-ka/strings.xml b/core/res/res/values-mcc310-mnc170-ka/strings.xml
index 6f6c4aa..fe5bc11 100644
--- a/core/res/res/values-mcc310-mnc170-ka/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-ka/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM ბარათი უზრუნველყოფილი არ არის (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM ბარათი დაუშვებელია (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"ტელეფონი დაუშვებელია MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-kk/strings.xml b/core/res/res/values-mcc310-mnc170-kk/strings.xml
index 210fb31..2f24d65 100644
--- a/core/res/res/values-mcc310-mnc170-kk/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-kk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM картасы қарастырылмаған MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM картасына рұқсат етілмеген MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Телефон пайдалануға болмайды MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-km/strings.xml b/core/res/res/values-mcc310-mnc170-km/strings.xml
index 79acf48..4a121e4 100644
--- a/core/res/res/values-mcc310-mnc170-km/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-km/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"ស៊ីមកាត​មិនត្រូវបានផ្ដល់ជូនទេ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"មិនអនុញ្ញាត​ចំពោះស៊ីមកាតទេ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"មិន​អនុញ្ញាត​ចំពោះ​ទូរសព្ទ​ទេ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-kn/strings.xml b/core/res/res/values-mcc310-mnc170-kn/strings.xml
index e11523b..5bd7f17 100644
--- a/core/res/res/values-mcc310-mnc170-kn/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-kn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"MM#2 ಗೆ ಸಿಮ್‌ ಸಿದ್ಧವಾಗಿಲ್ಲ"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"ಸಿಮ್‌ MM#3 ಅನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"ಫೋನ್ MM#6 ಅನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-ko/strings.xml b/core/res/res/values-mcc310-mnc170-ko/strings.xml
index 22d7e35..783e7d5 100644
--- a/core/res/res/values-mcc310-mnc170-ko/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-ko/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM이 프로비저닝되지 않음 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM이 허용되지 않음 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"전화가 허용되지 않음 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-ky/strings.xml b/core/res/res/values-mcc310-mnc170-ky/strings.xml
index 1f07c68..4c09085 100644
--- a/core/res/res/values-mcc310-mnc170-ky/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-ky/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM карта таанылган жок (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM картаны колдонууга тыюу салынган (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Телефонду колдонууга тыюу салынган MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-lo/strings.xml b/core/res/res/values-mcc310-mnc170-lo/strings.xml
index 3073000..e0a7379 100644
--- a/core/res/res/values-mcc310-mnc170-lo/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-lo/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM ບໍ່ໄດ້ເປີດໃຊ້ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM ບໍ່ອະນຸຍາດ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ໂທລະສັບ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-lt/strings.xml b/core/res/res/values-mcc310-mnc170-lt/strings.xml
index 127e69f..25698a9 100644
--- a/core/res/res/values-mcc310-mnc170-lt/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-lt/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM kortelė neteikiama (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM kortelė neleidžiama (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Telefonas neleidžiamas (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-lv/strings.xml b/core/res/res/values-mcc310-mnc170-lv/strings.xml
index da2ff7c..6bb0838 100644
--- a/core/res/res/values-mcc310-mnc170-lv/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-lv/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM karte netiek nodrošināta: MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM karti nav atļauts izmantot: MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Tālruni nav atļauts izmantot: MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-mk/strings.xml b/core/res/res/values-mcc310-mnc170-mk/strings.xml
index 3bc8194..de6ac62 100644
--- a/core/res/res/values-mcc310-mnc170-mk/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-mk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"Не е обезбедена SIM-картичка, MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"Не е дозволена SIM-картичка, MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Телефонот не е дозволен MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-ml/strings.xml b/core/res/res/values-mcc310-mnc170-ml/strings.xml
index 0479aef..4bfdffc 100644
--- a/core/res/res/values-mcc310-mnc170-ml/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-ml/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"സിം MM#2 പ്രൊവിഷൻ ചെയ്‌തിട്ടില്ല"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"സിം MM#3 അനുവദിച്ചിട്ടില്ല"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"ഫോൺ അനുവദനീയമല്ല MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-mn/strings.xml b/core/res/res/values-mcc310-mnc170-mn/strings.xml
index 59f24ec..6e5cfc3 100644
--- a/core/res/res/values-mcc310-mnc170-mn/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-mn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM-г идэвхжүүлээгүй байна MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM-г зөвшөөрөөгүй байна MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Утсыг зөвшөөрөөгүй MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-mr/strings.xml b/core/res/res/values-mcc310-mnc170-mr/strings.xml
index 938207c..a2fe305 100644
--- a/core/res/res/values-mcc310-mnc170-mr/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-mr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM ने MM#2 ची तरतूद केलेली नाही"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM ने MM#3 ला परवानगी दिली नाही"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"फोन MM#6 ला अनुमती देत नाही"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-ms/strings.xml b/core/res/res/values-mcc310-mnc170-ms/strings.xml
index 36be774..698c5d7 100644
--- a/core/res/res/values-mcc310-mnc170-ms/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-ms/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM tidak diperuntukkan MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM tidak dibenarkan MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Telefon tidak dibenarkan MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-my/strings.xml b/core/res/res/values-mcc310-mnc170-my/strings.xml
index 61f1a67..6c2be32 100644
--- a/core/res/res/values-mcc310-mnc170-my/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-my/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"ဆင်းမ်ကို ထောက်ပံ့မထားပါ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"ဆင်းမ်ကို ခွင့်မပြုပါ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"ဖုန်းကို ခွင့်မပြုပါ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-nb/strings.xml b/core/res/res/values-mcc310-mnc170-nb/strings.xml
index 3f213da..3a404b8 100644
--- a/core/res/res/values-mcc310-mnc170-nb/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-nb/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM-kortet er ikke klargjort, MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM-kortet er ikke tillatt, MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Telefonen er ikke tillatt, MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-ne/strings.xml b/core/res/res/values-mcc310-mnc170-ne/strings.xml
index d7febc4..65c01a1 100644
--- a/core/res/res/values-mcc310-mnc170-ne/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-ne/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM को प्रावधान छैन MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM लाई अनुमति छैन MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"फोनलाई अनुमति छैन MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-nl/strings.xml b/core/res/res/values-mcc310-mnc170-nl/strings.xml
index b1f9ba8..bdfb53a 100644
--- a/core/res/res/values-mcc310-mnc170-nl/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-nl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"Simkaart niet geregistreerd MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"Simkaart niet toegestaan MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Telefoon niet toegestaan MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-pa/strings.xml b/core/res/res/values-mcc310-mnc170-pa/strings.xml
index 9e993e3..6cdf639 100644
--- a/core/res/res/values-mcc310-mnc170-pa/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-pa/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"ਸਿਮ ਦੀ ਵਿਵਸਥਾ ਨਹੀਂ ਹੈ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"ਸਿਮ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"ਫ਼ੋਨ ਨੂੰ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-pl/strings.xml b/core/res/res/values-mcc310-mnc170-pl/strings.xml
index d1ecd5d..41100a4 100644
--- a/core/res/res/values-mcc310-mnc170-pl/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-pl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"MM#2 – karta SIM nieobsługiwana"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"MM#3 – niedozwolona karta SIM"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"MM#6 – telefon niedozwolony"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-pt-rBR/strings.xml b/core/res/res/values-mcc310-mnc170-pt-rBR/strings.xml
index fc31e9e..fcffa16 100644
--- a/core/res/res/values-mcc310-mnc170-pt-rBR/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-pt-rBR/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM não aprovisionado MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM não permitido MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Smartphone não permitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-pt-rPT/strings.xml b/core/res/res/values-mcc310-mnc170-pt-rPT/strings.xml
index fc31e9e..7d43bf3 100644
--- a/core/res/res/values-mcc310-mnc170-pt-rPT/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-pt-rPT/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM não aprovisionado MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM não permitido MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Telemóvel não permitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-pt/strings.xml b/core/res/res/values-mcc310-mnc170-pt/strings.xml
index fc31e9e..fcffa16 100644
--- a/core/res/res/values-mcc310-mnc170-pt/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-pt/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM não aprovisionado MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM não permitido MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Smartphone não permitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-ro/strings.xml b/core/res/res/values-mcc310-mnc170-ro/strings.xml
index 1ee5080..7c2c09e 100644
--- a/core/res/res/values-mcc310-mnc170-ro/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-ro/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"Cardul SIM nu este activat MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"Cardul SIM nu este permis MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Telefonul nu este permis MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-ru/strings.xml b/core/res/res/values-mcc310-mnc170-ru/strings.xml
index 0e00909..3b457da 100644
--- a/core/res/res/values-mcc310-mnc170-ru/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-ru/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM-карта не активирована (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"Использование SIM-карты запрещено (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Звонки запрещены (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-si/strings.xml b/core/res/res/values-mcc310-mnc170-si/strings.xml
index bbd1e4c..61e0143 100644
--- a/core/res/res/values-mcc310-mnc170-si/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-si/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM MM#2 ප්‍රතිපාදනය නොකරයි"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM MM#3 ඉඩ නොදේ"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"දුරකථනය MM#6 ඉඩ නොදේ"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-sk/strings.xml b/core/res/res/values-mcc310-mnc170-sk/strings.xml
index e5f9376..cf71dd3 100644
--- a/core/res/res/values-mcc310-mnc170-sk/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-sk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM karta nie je k dispozícii – MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM karta je zakázaná – MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Telefón nie je povolený (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-sl/strings.xml b/core/res/res/values-mcc310-mnc170-sl/strings.xml
index 2d4c7dd..2e600ac 100644
--- a/core/res/res/values-mcc310-mnc170-sl/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-sl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"Kartica SIM ni omogočena za uporabo MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"Kartica SIM ni dovoljena MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Telefon ni dovoljen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-sq/strings.xml b/core/res/res/values-mcc310-mnc170-sq/strings.xml
index df5b537..0b22ca2 100644
--- a/core/res/res/values-mcc310-mnc170-sq/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-sq/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"Karta SIM nuk është dhënë MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"Karta SIM nuk lejohet MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Telefoni nuk lejohet MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-sr/strings.xml b/core/res/res/values-mcc310-mnc170-sr/strings.xml
index 6bfbbb2..42057fe 100644
--- a/core/res/res/values-mcc310-mnc170-sr/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-sr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM картица није подешена MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM картица није дозвољена MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Телефон није дозвољен MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-sv/strings.xml b/core/res/res/values-mcc310-mnc170-sv/strings.xml
index 1a28db1..c609747 100644
--- a/core/res/res/values-mcc310-mnc170-sv/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-sv/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM-kort tillhandahålls inte MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM-kort tillåts inte MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Mobil tillåts inte MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-sw/strings.xml b/core/res/res/values-mcc310-mnc170-sw/strings.xml
index 0852115..7727944 100644
--- a/core/res/res/values-mcc310-mnc170-sw/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-sw/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM haitumiki MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM hairuhusiwi MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Simu hairuhusiwi MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-ta/strings.xml b/core/res/res/values-mcc310-mnc170-ta/strings.xml
index 0277cc2..cde140f 100644
--- a/core/res/res/values-mcc310-mnc170-ta/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-ta/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"சிம் அமைக்கப்படவில்லை MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"சிம் அனுமதிக்கப்படவில்லை MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"ஃபோன் அனுமதிக்கப்படவில்லை MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-te/strings.xml b/core/res/res/values-mcc310-mnc170-te/strings.xml
index a208cd3..a088bb0 100644
--- a/core/res/res/values-mcc310-mnc170-te/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-te/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM MM#2ని సక్రియం చేయలేదు"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM MM#3ని అనుమతించలేదు"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"ఫోన్ అనుమతించబడదు MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-th/strings.xml b/core/res/res/values-mcc310-mnc170-th/strings.xml
index e5d02c8..ad5f5dc 100644
--- a/core/res/res/values-mcc310-mnc170-th/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-th/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"ไม่มีการจัดสรรซิม MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"ไม่อนุญาตให้ใช้ซิม MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"ไม่อนุญาตให้ใช้โทรศัพท์ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-tl/strings.xml b/core/res/res/values-mcc310-mnc170-tl/strings.xml
index e285759..187593a 100644
--- a/core/res/res/values-mcc310-mnc170-tl/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-tl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"Hindi na-provision ang SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"Hindi pinapahintulutan ang SIM MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Hindi pinapahintulutan ang telepono MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-tr/strings.xml b/core/res/res/values-mcc310-mnc170-tr/strings.xml
index b5102ef..e4a9255 100644
--- a/core/res/res/values-mcc310-mnc170-tr/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-tr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM, MM#2\'nin temel hazırlığını yapamadı"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM MM#3\'e izin vermiyor"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Telefona izin verilmiyor MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-uk/strings.xml b/core/res/res/values-mcc310-mnc170-uk/strings.xml
index 37e3118..89ad9b3 100644
--- a/core/res/res/values-mcc310-mnc170-uk/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-uk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM-карту не надано (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM-карта заборонена (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Телефон заборонено (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-ur/strings.xml b/core/res/res/values-mcc310-mnc170-ur/strings.xml
index ea8b93e..50cd57e 100644
--- a/core/res/res/values-mcc310-mnc170-ur/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-ur/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"‏SIM فراہم کردہ نہیں ہے MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"‏SIM کی اجازت نہیں ہے MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"‏فون کی اجازت نہیں ہے MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-uz/strings.xml b/core/res/res/values-mcc310-mnc170-uz/strings.xml
index 0bb3f52..9bfecfd 100644
--- a/core/res/res/values-mcc310-mnc170-uz/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-uz/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM karta ishlatish taqiqlangan (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM karta ishlatish taqiqlangan (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Chaqiruvlar taqiqlangan (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-vi/strings.xml b/core/res/res/values-mcc310-mnc170-vi/strings.xml
index a37f48f..ad87648 100644
--- a/core/res/res/values-mcc310-mnc170-vi/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-vi/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM không được cấp phép MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM không được phép MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Không cho phép điện thoại MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-zh-rCN/strings.xml b/core/res/res/values-mcc310-mnc170-zh-rCN/strings.xml
index f072b28..de68fe1 100644
--- a/core/res/res/values-mcc310-mnc170-zh-rCN/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-zh-rCN/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"未配置的 SIM 卡 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"不被允许的 SIM 卡 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"不受允许的手机 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-zh-rHK/strings.xml b/core/res/res/values-mcc310-mnc170-zh-rHK/strings.xml
index db14b90..5fd10b3 100644
--- a/core/res/res/values-mcc310-mnc170-zh-rHK/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-zh-rHK/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"未佈建的 SIM 卡 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"不支援的 SIM 卡 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"不允許手機 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-zh-rTW/strings.xml b/core/res/res/values-mcc310-mnc170-zh-rTW/strings.xml
index db14b90..cb19625 100644
--- a/core/res/res/values-mcc310-mnc170-zh-rTW/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-zh-rTW/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"未佈建的 SIM 卡 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"不支援的 SIM 卡 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"不支援的手機 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc170-zu/strings.xml b/core/res/res/values-mcc310-mnc170-zu/strings.xml
index 282f403..26890e4e 100644
--- a/core/res/res/values-mcc310-mnc170-zu/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-zu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"I-SIM ayinikezelwe MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1130721094178658338">"I-SIM ayivunyelwe MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="3173546391131606065">"Ifoni ayivunyelwe MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-af/strings.xml b/core/res/res/values-mcc310-mnc280-af/strings.xml
index a761881..b1430773 100644
--- a/core/res/res/values-mcc310-mnc280-af/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-af/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM is nie opgestel nie MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM word nie toegelaat nie MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Foon nie toegelaat nie MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-am/strings.xml b/core/res/res/values-mcc310-mnc280-am/strings.xml
index 6750a71..ffbb1cc 100644
--- a/core/res/res/values-mcc310-mnc280-am/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-am/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"ሲም አልቀረበም MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"ሲም አይፈቀድም MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"ስልክ አይፈቀድም MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-ar/strings.xml b/core/res/res/values-mcc310-mnc280-ar/strings.xml
index a77d78e..c7c03a5 100644
--- a/core/res/res/values-mcc310-mnc280-ar/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-ar/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"‏لم يتم توفير SIM ‏MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"‏غير مسموح باستخدام SIM ‏MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"‏غير مسموح باستخدام الهاتف MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-az/strings.xml b/core/res/res/values-mcc310-mnc280-az/strings.xml
index b7ee114..7fb788a 100644
--- a/core/res/res/values-mcc310-mnc280-az/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-az/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM MM#2 təmin etmir"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM MM#3 dəstəkləmir"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"MM#6 telefonu dəstəklənmir"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-b+sr+Latn/strings.xml b/core/res/res/values-mcc310-mnc280-b+sr+Latn/strings.xml
index 0c78b5e..cd78afa 100644
--- a/core/res/res/values-mcc310-mnc280-b+sr+Latn/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-b+sr+Latn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM kartica nije podešena MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM kartica nije dozvoljena MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Telefon nije dozvoljen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-be/strings.xml b/core/res/res/values-mcc310-mnc280-be/strings.xml
index 3ee9ad9..7da834b 100644
--- a/core/res/res/values-mcc310-mnc280-be/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-be/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM-карты няма MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM-карта не дапускаецца MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Тэлефон не дапускаецца MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-bg/strings.xml b/core/res/res/values-mcc310-mnc280-bg/strings.xml
index a320898..7b0fac1 100644
--- a/core/res/res/values-mcc310-mnc280-bg/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-bg/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM картата не е обезпечена MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM картата не е разрешена MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Телефонът не е разрешен MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-bn/strings.xml b/core/res/res/values-mcc310-mnc280-bn/strings.xml
index dc950a7..ae0eaea 100644
--- a/core/res/res/values-mcc310-mnc280-bn/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-bn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"সিমের জন্য প্রস্তুত নয় MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"সিমের অনুমতি নেই MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"ফোন অনুমোদিত নয় MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-bs/strings.xml b/core/res/res/values-mcc310-mnc280-bs/strings.xml
index d61fad8..5259a9a 100644
--- a/core/res/res/values-mcc310-mnc280-bs/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-bs/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM kartica nije dodijeljena MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM kartica nije dozvoljena MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Telefon nije dozvoljen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-ca/strings.xml b/core/res/res/values-mcc310-mnc280-ca/strings.xml
index 9a9e309..061c74c 100644
--- a/core/res/res/values-mcc310-mnc280-ca/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-ca/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"La SIM no està proporcionada a MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"La SIM no és compatible a MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Telèfon no compatible MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-cs/strings.xml b/core/res/res/values-mcc310-mnc280-cs/strings.xml
index 99e2bdb..422d205 100644
--- a/core/res/res/values-mcc310-mnc280-cs/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-cs/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM karta není poskytována (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM karta není povolena (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Telefon není povolen (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-da/strings.xml b/core/res/res/values-mcc310-mnc280-da/strings.xml
index 4f444a1..180c523 100644
--- a/core/res/res/values-mcc310-mnc280-da/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-da/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM-kort leveres ikke MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM-kort er ikke tilladt MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Telefonen har ikke adgangstilladelse MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-de/strings.xml b/core/res/res/values-mcc310-mnc280-de/strings.xml
index 063c75b..0ca30c9 100644
--- a/core/res/res/values-mcc310-mnc280-de/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-de/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM-Karte nicht eingerichtet MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM-Karte nicht zulässig MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Smartphone nicht zulässig MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-el/strings.xml b/core/res/res/values-mcc310-mnc280-el/strings.xml
index 1161a7d..494e53b 100644
--- a/core/res/res/values-mcc310-mnc280-el/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-el/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"Δεν παρέχεται κάρτα SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"Η κάρτα SIM δεν επιτρέπεται MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Το τηλέφωνο δεν επιτρέπεται MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-en-rAU/strings.xml b/core/res/res/values-mcc310-mnc280-en-rAU/strings.xml
index e9c9eba..c7e6a34 100644
--- a/core/res/res/values-mcc310-mnc280-en-rAU/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-en-rAU/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-en-rCA/strings.xml b/core/res/res/values-mcc310-mnc280-en-rCA/strings.xml
index e9c9eba..c7e6a34 100644
--- a/core/res/res/values-mcc310-mnc280-en-rCA/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-en-rCA/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-en-rGB/strings.xml b/core/res/res/values-mcc310-mnc280-en-rGB/strings.xml
index e9c9eba..c7e6a34 100644
--- a/core/res/res/values-mcc310-mnc280-en-rGB/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-en-rGB/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-en-rIN/strings.xml b/core/res/res/values-mcc310-mnc280-en-rIN/strings.xml
index e9c9eba..c7e6a34 100644
--- a/core/res/res/values-mcc310-mnc280-en-rIN/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-en-rIN/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-en-rXC/strings.xml b/core/res/res/values-mcc310-mnc280-en-rXC/strings.xml
index 83640ae..7200c69 100644
--- a/core/res/res/values-mcc310-mnc280-en-rXC/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-en-rXC/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‎‎‏‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‏‎‏‏‎‏‏‏‏‎‏‎‎‏‏‏‏‏‎‎‎‎‏‎‏‎‎‎‎‏‎‏‏‎SIM not provisioned MM#2‎‏‎‎‏‎"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‏‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‏‎‏‎‏‎‏‎‎‎‏‎‎‏‎‏‎‎‏‎‏‎‏‎‏‏‎‏‏‏‏‎‎‏‏‎‏‎‎SIM not allowed MM#3‎‏‎‎‏‎"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‎‎‎‎‏‏‎‎‎‎‎‏‎‏‏‎‎‏‏‏‏‎‏‎‎‎‎‏‏‏‎‏‏‏‎‏‏‏‏‏‎‏‎‎‎‎‎‏‏‎Phone not allowed MM#6‎‏‎‎‏‎"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-es-rUS/strings.xml b/core/res/res/values-mcc310-mnc280-es-rUS/strings.xml
index 86ad4fd..00feb92 100644
--- a/core/res/res/values-mcc310-mnc280-es-rUS/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-es-rUS/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM no provista MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM no permitida MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Teléfono no admitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-es/strings.xml b/core/res/res/values-mcc310-mnc280-es/strings.xml
index 2c7aa93..27945c8 100644
--- a/core/res/res/values-mcc310-mnc280-es/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-es/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM no proporcionada (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM no admitida (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Teléfono no admitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-et/strings.xml b/core/res/res/values-mcc310-mnc280-et/strings.xml
index 7305d18..aa127fa 100644
--- a/core/res/res/values-mcc310-mnc280-et/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-et/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM-kaart on ette valmistamata MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM-kaart pole lubatud MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Telefon pole lubatud MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-eu/strings.xml b/core/res/res/values-mcc310-mnc280-eu/strings.xml
index 3c7296d..eec8d90 100644
--- a/core/res/res/values-mcc310-mnc280-eu/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-eu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"Ez dago SIM txartelik MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"Ez da onartzen SIM txartela MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Telefonoa ez da onartzen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-fa/strings.xml b/core/res/res/values-mcc310-mnc280-fa/strings.xml
index cd7ce85..219299c 100644
--- a/core/res/res/values-mcc310-mnc280-fa/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-fa/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"‏سیم‌کارت مجوز لازم را ندارد MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"‏سیم‌کارت مجاز نیست MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"‏تلفن مجاز نیست MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-fi/strings.xml b/core/res/res/values-mcc310-mnc280-fi/strings.xml
index b2ccc50..a21613f 100644
--- a/core/res/res/values-mcc310-mnc280-fi/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-fi/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM-kortti ei käyttäjien hallinnassa MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM-kortti estetty MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Puhelin estetty MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-fr-rCA/strings.xml b/core/res/res/values-mcc310-mnc280-fr-rCA/strings.xml
index 29bb9a0..c5f913f 100644
--- a/core/res/res/values-mcc310-mnc280-fr-rCA/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-fr-rCA/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"Carte SIM non configurée, MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"Carte SIM non autorisée, MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Téléphone non autorisé MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-fr/strings.xml b/core/res/res/values-mcc310-mnc280-fr/strings.xml
index ce2f931..5b6ec9d 100644
--- a/core/res/res/values-mcc310-mnc280-fr/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-fr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"Carte SIM non provisionnée MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"Carte SIM non autorisée MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Téléphone non autorisé MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-gl/strings.xml b/core/res/res/values-mcc310-mnc280-gl/strings.xml
index e941341..0a05c51 100644
--- a/core/res/res/values-mcc310-mnc280-gl/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-gl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"Non se introduciu ningunha tarxeta SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"Non se admite a tarxeta SIM MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Non se admite o teléfono MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-gu/strings.xml b/core/res/res/values-mcc310-mnc280-gu/strings.xml
index a3763be..382ce7e 100644
--- a/core/res/res/values-mcc310-mnc280-gu/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-gu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIMને MM#2ની જોગવાઈ નથી"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIMને MM#3 કરવાની મંજૂરી નથી"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"MM#6 ફોનની મંજૂરી નથી"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-hi/strings.xml b/core/res/res/values-mcc310-mnc280-hi/strings.xml
index ce866af..57218a3 100644
--- a/core/res/res/values-mcc310-mnc280-hi/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-hi/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM काम नहीं कर रहा है MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM की अनुमति नहीं है MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"फ़ोन की इजाज़त नहीं है MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-hr/strings.xml b/core/res/res/values-mcc310-mnc280-hr/strings.xml
index 0021474..e6f9abd 100644
--- a/core/res/res/values-mcc310-mnc280-hr/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-hr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"Ne pruža se usluga za SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM nije dopušten MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Telefon nije dopušten MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-hu/strings.xml b/core/res/res/values-mcc310-mnc280-hu/strings.xml
index 864faff..e673aea 100644
--- a/core/res/res/values-mcc310-mnc280-hu/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-hu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"Nem engedélyezett SIM-kártya (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"A SIM-kártya nem engedélyezett (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"A telefon nem engedélyezett (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-hy/strings.xml b/core/res/res/values-mcc310-mnc280-hy/strings.xml
index 6d027c3..b9f59e0 100644
--- a/core/res/res/values-mcc310-mnc280-hy/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-hy/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM քարտը նախապատրաստված չէ (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM քարտի օգտագործումն արգելված է (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Հեռախոսի օգտագործումն արգելված է (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-in/strings.xml b/core/res/res/values-mcc310-mnc280-in/strings.xml
index a4f3486..23e60fa 100644
--- a/core/res/res/values-mcc310-mnc280-in/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-in/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM tidak di-provisioning MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM tidak diizinkan MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Ponsel tidak diizinkan MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-is/strings.xml b/core/res/res/values-mcc310-mnc280-is/strings.xml
index 30bbea4..56034d0 100644
--- a/core/res/res/values-mcc310-mnc280-is/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-is/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM-korti ekki úthlutað MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM-kort ekki leyft MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Sími ekki leyfður MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-it/strings.xml b/core/res/res/values-mcc310-mnc280-it/strings.xml
index f83921b..b3d34cf 100644
--- a/core/res/res/values-mcc310-mnc280-it/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-it/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"Scheda SIM non predisposta MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"Scheda SIM non consentita MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Telefono non consentito MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-iw/strings.xml b/core/res/res/values-mcc310-mnc280-iw/strings.xml
index f3f87ff..4966a98 100644
--- a/core/res/res/values-mcc310-mnc280-iw/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-iw/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"‏כרטיס ה-SIM לא הופעל MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"‏כרטיס ה-SIM לא מורשה לשימוש ברשת הסלולרית MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"‏הטלפון לא מורשה MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-ja/strings.xml b/core/res/res/values-mcc310-mnc280-ja/strings.xml
index a1cfd8b..463fc2e 100644
--- a/core/res/res/values-mcc310-mnc280-ja/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-ja/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM には対応していません(MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM は許可されていません(MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"電話は許可されていません(MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-ka/strings.xml b/core/res/res/values-mcc310-mnc280-ka/strings.xml
index 91c434f..942944f 100644
--- a/core/res/res/values-mcc310-mnc280-ka/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-ka/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM ბარათი უზრუნველყოფილი არ არის (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM ბარათი დაუშვებელია (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"ტელეფონი დაუშვებელია MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-kk/strings.xml b/core/res/res/values-mcc310-mnc280-kk/strings.xml
index 44440d3..3559ee0 100644
--- a/core/res/res/values-mcc310-mnc280-kk/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-kk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM картасы қарастырылмаған MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM картасына рұқсат етілмеген MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Телефон пайдалануға болмайды MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-km/strings.xml b/core/res/res/values-mcc310-mnc280-km/strings.xml
index a016601..69777dc 100644
--- a/core/res/res/values-mcc310-mnc280-km/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-km/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"ស៊ីមកាត​មិនត្រូវបានផ្ដល់ជូនទេ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"មិនអនុញ្ញាត​ចំពោះស៊ីមកាតទេ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"មិន​អនុញ្ញាត​ចំពោះ​ទូរសព្ទ​ទេ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-kn/strings.xml b/core/res/res/values-mcc310-mnc280-kn/strings.xml
index 1d9e353..3028b6f 100644
--- a/core/res/res/values-mcc310-mnc280-kn/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-kn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"MM#2 ಗೆ ಸಿಮ್‌ ಸಿದ್ಧವಾಗಿಲ್ಲ"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"ಸಿಮ್‌ MM#3 ಅನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"ಫೋನ್ MM#6 ಅನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-ko/strings.xml b/core/res/res/values-mcc310-mnc280-ko/strings.xml
index e7bb9bb..d6ff696 100644
--- a/core/res/res/values-mcc310-mnc280-ko/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-ko/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM이 프로비저닝되지 않음 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM이 허용되지 않음 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"전화가 허용되지 않음 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-ky/strings.xml b/core/res/res/values-mcc310-mnc280-ky/strings.xml
index 85483c7..9ecbcf2 100644
--- a/core/res/res/values-mcc310-mnc280-ky/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-ky/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM карта таанылган жок (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM картаны колдонууга тыюу салынган (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Телефонду колдонууга тыюу салынган MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-lo/strings.xml b/core/res/res/values-mcc310-mnc280-lo/strings.xml
index 9415089..f72ece1 100644
--- a/core/res/res/values-mcc310-mnc280-lo/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-lo/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM ບໍ່ໄດ້ເປີດໃຊ້ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM ບໍ່ອະນຸຍາດ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ໂທລະສັບ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-lt/strings.xml b/core/res/res/values-mcc310-mnc280-lt/strings.xml
index b5ff1b9..80257df 100644
--- a/core/res/res/values-mcc310-mnc280-lt/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-lt/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM kortelė neteikiama (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM kortelė neleidžiama (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Telefonas neleidžiamas (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-lv/strings.xml b/core/res/res/values-mcc310-mnc280-lv/strings.xml
index 4034bc1..f6bb072 100644
--- a/core/res/res/values-mcc310-mnc280-lv/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-lv/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM karte netiek nodrošināta: MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM karti nav atļauts izmantot: MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Tālruni nav atļauts izmantot: MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-mk/strings.xml b/core/res/res/values-mcc310-mnc280-mk/strings.xml
index a93cb79..f9a7d91 100644
--- a/core/res/res/values-mcc310-mnc280-mk/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-mk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"Не е обезбедена SIM-картичка, MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"Не е дозволена SIM-картичка, MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Телефонот не е дозволен MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-ml/strings.xml b/core/res/res/values-mcc310-mnc280-ml/strings.xml
index 4aa7dec..9f8eee6 100644
--- a/core/res/res/values-mcc310-mnc280-ml/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-ml/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"സിം MM#2 പ്രൊവിഷൻ ചെയ്‌തിട്ടില്ല"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"സിം MM#3 അനുവദിച്ചിട്ടില്ല"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"ഫോൺ അനുവദനീയമല്ല MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-mn/strings.xml b/core/res/res/values-mcc310-mnc280-mn/strings.xml
index 54b8190..2b9d814 100644
--- a/core/res/res/values-mcc310-mnc280-mn/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-mn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM-г идэвхжүүлээгүй байна MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM-г зөвшөөрөөгүй байна MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Утсыг зөвшөөрөөгүй MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-mr/strings.xml b/core/res/res/values-mcc310-mnc280-mr/strings.xml
index cb343cb..fbf98fb 100644
--- a/core/res/res/values-mcc310-mnc280-mr/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-mr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM ने MM#2 ची तरतूद केलेली नाही"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM ने MM#3 ला परवानगी दिली नाही"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"फोन MM#6 ला अनुमती देत नाही"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-ms/strings.xml b/core/res/res/values-mcc310-mnc280-ms/strings.xml
index 27da747..d140049 100644
--- a/core/res/res/values-mcc310-mnc280-ms/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-ms/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM tidak diperuntukkan MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM tidak dibenarkan MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Telefon tidak dibenarkan MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-my/strings.xml b/core/res/res/values-mcc310-mnc280-my/strings.xml
index 40cdc63..c4ba718 100644
--- a/core/res/res/values-mcc310-mnc280-my/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-my/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"ဆင်းမ်ကို ထောက်ပံ့မထားပါ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"ဆင်းမ်ကို ခွင့်မပြုပါ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"ဖုန်းကို ခွင့်မပြုပါ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-nb/strings.xml b/core/res/res/values-mcc310-mnc280-nb/strings.xml
index 7666c3e..c9eece5 100644
--- a/core/res/res/values-mcc310-mnc280-nb/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-nb/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM-kortet er ikke klargjort, MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM-kortet er ikke tillatt, MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Telefonen er ikke tillatt, MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-ne/strings.xml b/core/res/res/values-mcc310-mnc280-ne/strings.xml
index 8735605..2108eda 100644
--- a/core/res/res/values-mcc310-mnc280-ne/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-ne/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM को प्रावधान छैन MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM लाई अनुमति छैन MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"फोनलाई अनुमति छैन MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-nl/strings.xml b/core/res/res/values-mcc310-mnc280-nl/strings.xml
index 7d7bfa7..f6c0e0b 100644
--- a/core/res/res/values-mcc310-mnc280-nl/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-nl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"Simkaart niet geregistreerd MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"Simkaart niet toegestaan MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Telefoon niet toegestaan MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-pa/strings.xml b/core/res/res/values-mcc310-mnc280-pa/strings.xml
index 3a65866..3ac0638 100644
--- a/core/res/res/values-mcc310-mnc280-pa/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-pa/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"ਸਿਮ ਦੀ ਵਿਵਸਥਾ ਨਹੀਂ ਹੈ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"ਸਿਮ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"ਫ਼ੋਨ ਨੂੰ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-pl/strings.xml b/core/res/res/values-mcc310-mnc280-pl/strings.xml
index 52410f4..ee33cf6 100644
--- a/core/res/res/values-mcc310-mnc280-pl/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-pl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"MM#2 – karta SIM nieobsługiwana"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"MM#3 – niedozwolona karta SIM"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"MM#6 – telefon niedozwolony"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-pt-rBR/strings.xml b/core/res/res/values-mcc310-mnc280-pt-rBR/strings.xml
index 03d0efb1..f7fb684 100644
--- a/core/res/res/values-mcc310-mnc280-pt-rBR/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-pt-rBR/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM não aprovisionado MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM não permitido MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Smartphone não permitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-pt-rPT/strings.xml b/core/res/res/values-mcc310-mnc280-pt-rPT/strings.xml
index 03d0efb1..1a64f5c 100644
--- a/core/res/res/values-mcc310-mnc280-pt-rPT/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-pt-rPT/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM não aprovisionado MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM não permitido MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Telemóvel não permitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-pt/strings.xml b/core/res/res/values-mcc310-mnc280-pt/strings.xml
index 03d0efb1..f7fb684 100644
--- a/core/res/res/values-mcc310-mnc280-pt/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-pt/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM não aprovisionado MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM não permitido MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Smartphone não permitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-ro/strings.xml b/core/res/res/values-mcc310-mnc280-ro/strings.xml
index d60ea0c..5ed83b3 100644
--- a/core/res/res/values-mcc310-mnc280-ro/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-ro/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"Cardul SIM nu este activat MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"Cardul SIM nu este permis MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Telefonul nu este permis MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-ru/strings.xml b/core/res/res/values-mcc310-mnc280-ru/strings.xml
index 308c353..c9e22bb 100644
--- a/core/res/res/values-mcc310-mnc280-ru/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-ru/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM-карта не активирована (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"Использование SIM-карты запрещено (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Звонки запрещены (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-si/strings.xml b/core/res/res/values-mcc310-mnc280-si/strings.xml
index 5bd6d1f..fa5b3c0 100644
--- a/core/res/res/values-mcc310-mnc280-si/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-si/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM MM#2 ප්‍රතිපාදනය නොකරයි"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM MM#3 ඉඩ නොදේ"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"දුරකථනය MM#6 ඉඩ නොදේ"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-sk/strings.xml b/core/res/res/values-mcc310-mnc280-sk/strings.xml
index 4098ac7..b116331 100644
--- a/core/res/res/values-mcc310-mnc280-sk/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-sk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM karta nie je k dispozícii – MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM karta je zakázaná – MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Telefón nie je povolený (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-sl/strings.xml b/core/res/res/values-mcc310-mnc280-sl/strings.xml
index faa78ad..1a75b94 100644
--- a/core/res/res/values-mcc310-mnc280-sl/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-sl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"Kartica SIM ni omogočena za uporabo MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"Kartica SIM ni dovoljena MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Telefon ni dovoljen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-sq/strings.xml b/core/res/res/values-mcc310-mnc280-sq/strings.xml
index 48fba2d..54072e2 100644
--- a/core/res/res/values-mcc310-mnc280-sq/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-sq/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"Karta SIM nuk është dhënë MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"Karta SIM nuk lejohet MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Telefoni nuk lejohet MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-sr/strings.xml b/core/res/res/values-mcc310-mnc280-sr/strings.xml
index 30c9df3..f4591b6 100644
--- a/core/res/res/values-mcc310-mnc280-sr/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-sr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM картица није подешена MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM картица није дозвољена MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Телефон није дозвољен MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-sv/strings.xml b/core/res/res/values-mcc310-mnc280-sv/strings.xml
index cb5b9f32..294d762 100644
--- a/core/res/res/values-mcc310-mnc280-sv/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-sv/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM-kort tillhandahålls inte MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM-kort tillåts inte MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Mobil tillåts inte MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-sw/strings.xml b/core/res/res/values-mcc310-mnc280-sw/strings.xml
index 15a1a36..4912340 100644
--- a/core/res/res/values-mcc310-mnc280-sw/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-sw/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM haitumiki MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM hairuhusiwi MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Simu hairuhusiwi MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-ta/strings.xml b/core/res/res/values-mcc310-mnc280-ta/strings.xml
index c3911d4..35cc649 100644
--- a/core/res/res/values-mcc310-mnc280-ta/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-ta/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"சிம் அமைக்கப்படவில்லை MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"சிம் அனுமதிக்கப்படவில்லை MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"ஃபோன் அனுமதிக்கப்படவில்லை MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-te/strings.xml b/core/res/res/values-mcc310-mnc280-te/strings.xml
index f5cabad..75d5b73 100644
--- a/core/res/res/values-mcc310-mnc280-te/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-te/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM MM#2ని సక్రియం చేయలేదు"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM MM#3ని అనుమతించలేదు"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"ఫోన్ అనుమతించబడదు MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-th/strings.xml b/core/res/res/values-mcc310-mnc280-th/strings.xml
index 9810ba6..2312bb4 100644
--- a/core/res/res/values-mcc310-mnc280-th/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-th/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"ไม่มีการจัดสรรซิม MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"ไม่อนุญาตให้ใช้ซิม MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"ไม่อนุญาตให้ใช้โทรศัพท์ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-tl/strings.xml b/core/res/res/values-mcc310-mnc280-tl/strings.xml
index 600ad05..8c05e82 100644
--- a/core/res/res/values-mcc310-mnc280-tl/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-tl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"Hindi na-provision ang SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"Hindi pinapahintulutan ang SIM MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Hindi pinapahintulutan ang telepono MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-tr/strings.xml b/core/res/res/values-mcc310-mnc280-tr/strings.xml
index ea90bdb..4e9cc2c 100644
--- a/core/res/res/values-mcc310-mnc280-tr/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-tr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM, MM#2\'nin temel hazırlığını yapamadı"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM MM#3\'e izin vermiyor"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Telefona izin verilmiyor MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-uk/strings.xml b/core/res/res/values-mcc310-mnc280-uk/strings.xml
index 68a34fd..aa500d6 100644
--- a/core/res/res/values-mcc310-mnc280-uk/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-uk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM-карту не надано (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM-карта заборонена (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Телефон заборонено (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-ur/strings.xml b/core/res/res/values-mcc310-mnc280-ur/strings.xml
index d61a5dc..b0d842a 100644
--- a/core/res/res/values-mcc310-mnc280-ur/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-ur/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"‏SIM فراہم کردہ نہیں ہے MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"‏SIM کی اجازت نہیں ہے MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"‏فون کی اجازت نہیں ہے MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-uz/strings.xml b/core/res/res/values-mcc310-mnc280-uz/strings.xml
index 324d364..9110cfc 100644
--- a/core/res/res/values-mcc310-mnc280-uz/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-uz/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM karta ishlatish taqiqlangan (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM karta ishlatish taqiqlangan (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Chaqiruvlar taqiqlangan (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-vi/strings.xml b/core/res/res/values-mcc310-mnc280-vi/strings.xml
index 6806e39..444f882 100644
--- a/core/res/res/values-mcc310-mnc280-vi/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-vi/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM không được cấp phép MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM không được phép MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Không cho phép điện thoại MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-zh-rCN/strings.xml b/core/res/res/values-mcc310-mnc280-zh-rCN/strings.xml
index add3f920..aa85594 100644
--- a/core/res/res/values-mcc310-mnc280-zh-rCN/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-zh-rCN/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"未配置的 SIM 卡 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"不被允许的 SIM 卡 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"不受允许的手机 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-zh-rHK/strings.xml b/core/res/res/values-mcc310-mnc280-zh-rHK/strings.xml
index 856297c..c986d5d 100644
--- a/core/res/res/values-mcc310-mnc280-zh-rHK/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-zh-rHK/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"未佈建的 SIM 卡 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"不支援的 SIM 卡 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"不允許手機 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-zh-rTW/strings.xml b/core/res/res/values-mcc310-mnc280-zh-rTW/strings.xml
index 856297c..720d097 100644
--- a/core/res/res/values-mcc310-mnc280-zh-rTW/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-zh-rTW/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"未佈建的 SIM 卡 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"不支援的 SIM 卡 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"不支援的手機 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc280-zu/strings.xml b/core/res/res/values-mcc310-mnc280-zu/strings.xml
index 6c5147c..a198302 100644
--- a/core/res/res/values-mcc310-mnc280-zu/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-zu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"I-SIM ayinikezelwe MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="5562215652599183258">"I-SIM ayivunyelwe MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="822496463303720579">"Ifoni ayivunyelwe MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-af/strings.xml b/core/res/res/values-mcc310-mnc410-af/strings.xml
index 81688f1..7aea163 100644
--- a/core/res/res/values-mcc310-mnc410-af/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-af/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM is nie opgestel nie MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM word nie toegelaat nie MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Foon nie toegelaat nie MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-am/strings.xml b/core/res/res/values-mcc310-mnc410-am/strings.xml
index 176a628d..b5f5356 100644
--- a/core/res/res/values-mcc310-mnc410-am/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-am/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"ሲም አልቀረበም MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"ሲም አይፈቀድም MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"ስልክ አይፈቀድም MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-ar/strings.xml b/core/res/res/values-mcc310-mnc410-ar/strings.xml
index 884e18e..829ea43 100644
--- a/core/res/res/values-mcc310-mnc410-ar/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-ar/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"‏لم يتم توفير SIM ‏MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"‏غير مسموح باستخدام SIM ‏MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"‏غير مسموح باستخدام الهاتف MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-az/strings.xml b/core/res/res/values-mcc310-mnc410-az/strings.xml
index 178451c..497f37a 100644
--- a/core/res/res/values-mcc310-mnc410-az/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-az/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM MM#2 təmin etmir"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM MM#3 dəstəkləmir"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"MM#6 telefonu dəstəklənmir"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-b+sr+Latn/strings.xml b/core/res/res/values-mcc310-mnc410-b+sr+Latn/strings.xml
index 8981a35..95b9e00 100644
--- a/core/res/res/values-mcc310-mnc410-b+sr+Latn/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-b+sr+Latn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM kartica nije podešena MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM kartica nije dozvoljena MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Telefon nije dozvoljen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-be/strings.xml b/core/res/res/values-mcc310-mnc410-be/strings.xml
index 8ae8639..291eb12 100644
--- a/core/res/res/values-mcc310-mnc410-be/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-be/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM-карты няма MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM-карта не дапускаецца MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Тэлефон не дапускаецца MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-bg/strings.xml b/core/res/res/values-mcc310-mnc410-bg/strings.xml
index fc6f3e5..9ea8ddf 100644
--- a/core/res/res/values-mcc310-mnc410-bg/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-bg/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM картата не е обезпечена MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM картата не е разрешена MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Телефонът не е разрешен MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-bn/strings.xml b/core/res/res/values-mcc310-mnc410-bn/strings.xml
index e42a375..8fe788b 100644
--- a/core/res/res/values-mcc310-mnc410-bn/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-bn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"সিমের জন্য প্রস্তুত নয় MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"সিমের অনুমতি নেই MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"ফোন অনুমোদিত নয় MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-bs/strings.xml b/core/res/res/values-mcc310-mnc410-bs/strings.xml
index 4d7da3a..550a5ca 100644
--- a/core/res/res/values-mcc310-mnc410-bs/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-bs/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM kartica nije dodijeljena MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM kartica nije dozvoljena MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Telefon nije dozvoljen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-ca/strings.xml b/core/res/res/values-mcc310-mnc410-ca/strings.xml
index 19ab945b..2827e20 100644
--- a/core/res/res/values-mcc310-mnc410-ca/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-ca/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"La SIM no està proporcionada a MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"La SIM no és compatible a MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Telèfon no compatible MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-cs/strings.xml b/core/res/res/values-mcc310-mnc410-cs/strings.xml
index 3e36325..22610b0 100644
--- a/core/res/res/values-mcc310-mnc410-cs/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-cs/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM karta není poskytována (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM karta není povolena (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Telefon není povolen (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-da/strings.xml b/core/res/res/values-mcc310-mnc410-da/strings.xml
index e99ab57..38c47b3 100644
--- a/core/res/res/values-mcc310-mnc410-da/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-da/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM-kort leveres ikke MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM-kort er ikke tilladt MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Telefonen har ikke adgangstilladelse MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-de/strings.xml b/core/res/res/values-mcc310-mnc410-de/strings.xml
index c5f64f4a..ed8cd5d 100644
--- a/core/res/res/values-mcc310-mnc410-de/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-de/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM-Karte nicht eingerichtet MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM-Karte nicht zulässig MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Smartphone nicht zulässig MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-el/strings.xml b/core/res/res/values-mcc310-mnc410-el/strings.xml
index 128d1bf..9c9bafa 100644
--- a/core/res/res/values-mcc310-mnc410-el/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-el/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"Δεν παρέχεται κάρτα SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"Η κάρτα SIM δεν επιτρέπεται MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Το τηλέφωνο δεν επιτρέπεται MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-en-rAU/strings.xml b/core/res/res/values-mcc310-mnc410-en-rAU/strings.xml
index eb56351..5258201 100644
--- a/core/res/res/values-mcc310-mnc410-en-rAU/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-en-rAU/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-en-rCA/strings.xml b/core/res/res/values-mcc310-mnc410-en-rCA/strings.xml
index eb56351..5258201 100644
--- a/core/res/res/values-mcc310-mnc410-en-rCA/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-en-rCA/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-en-rGB/strings.xml b/core/res/res/values-mcc310-mnc410-en-rGB/strings.xml
index eb56351..5258201 100644
--- a/core/res/res/values-mcc310-mnc410-en-rGB/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-en-rGB/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-en-rIN/strings.xml b/core/res/res/values-mcc310-mnc410-en-rIN/strings.xml
index eb56351..5258201 100644
--- a/core/res/res/values-mcc310-mnc410-en-rIN/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-en-rIN/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-en-rXC/strings.xml b/core/res/res/values-mcc310-mnc410-en-rXC/strings.xml
index 4799e38..32a723f 100644
--- a/core/res/res/values-mcc310-mnc410-en-rXC/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-en-rXC/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‏‏‏‏‎‎‎‏‎‏‏‎‏‏‎‏‎‎‎‏‎‎‏‎‎‏‎‎‏‎‎‎SIM not provisioned MM#2‎‏‎‎‏‎"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‏‏‎‏‏‏‎‏‏‎‎‏‎‎‏‏‎‎‏‎‎‎‎‎‎‎‏‏‎‏‎‏‏‏‎‎‏‎‎‏‎‎‏‏‎‎‏‎‎‏‏‎‎‎SIM not allowed MM#3‎‏‎‎‏‎"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‎‎‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‏‏‎‏‏‎‏‏‏‎‎‏‏‎‎‏‎‎‎‎‎‏‎‎‎‎‏‎‏‎‎‎‏‎Phone not allowed MM#6‎‏‎‎‏‎"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-es-rUS/strings.xml b/core/res/res/values-mcc310-mnc410-es-rUS/strings.xml
index 85b0344..d9748af 100644
--- a/core/res/res/values-mcc310-mnc410-es-rUS/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-es-rUS/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM no provista MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM no permitida MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Teléfono no admitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-es/strings.xml b/core/res/res/values-mcc310-mnc410-es/strings.xml
index 248069e..0459bbb 100644
--- a/core/res/res/values-mcc310-mnc410-es/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-es/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM no proporcionada (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM no admitida (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Teléfono no admitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-et/strings.xml b/core/res/res/values-mcc310-mnc410-et/strings.xml
index 6ef7802..02f60b3 100644
--- a/core/res/res/values-mcc310-mnc410-et/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-et/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM-kaart on ette valmistamata MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM-kaart pole lubatud MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Telefon pole lubatud MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-eu/strings.xml b/core/res/res/values-mcc310-mnc410-eu/strings.xml
index 966511b..ef42cb9 100644
--- a/core/res/res/values-mcc310-mnc410-eu/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-eu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"Ez dago SIM txartelik MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"Ez da onartzen SIM txartela MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Telefonoa ez da onartzen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-fa/strings.xml b/core/res/res/values-mcc310-mnc410-fa/strings.xml
index 82f6272..e9dcc07 100644
--- a/core/res/res/values-mcc310-mnc410-fa/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-fa/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"‏سیم‌کارت مجوز لازم را ندارد MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"‏سیم‌کارت مجاز نیست MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"‏تلفن مجاز نیست MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-fi/strings.xml b/core/res/res/values-mcc310-mnc410-fi/strings.xml
index c5a4ef6..38485c3 100644
--- a/core/res/res/values-mcc310-mnc410-fi/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-fi/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM-kortti ei käyttäjien hallinnassa MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM-kortti estetty MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Puhelin estetty MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-fr-rCA/strings.xml b/core/res/res/values-mcc310-mnc410-fr-rCA/strings.xml
index cec2491..fe8c960 100644
--- a/core/res/res/values-mcc310-mnc410-fr-rCA/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-fr-rCA/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"Carte SIM non configurée, MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"Carte SIM non autorisée, MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Téléphone non autorisé MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-fr/strings.xml b/core/res/res/values-mcc310-mnc410-fr/strings.xml
index f715e71..c0fb381 100644
--- a/core/res/res/values-mcc310-mnc410-fr/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-fr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"Carte SIM non provisionnée MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"Carte SIM non autorisée MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Téléphone non autorisé MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-gl/strings.xml b/core/res/res/values-mcc310-mnc410-gl/strings.xml
index c3aba8e..56ce287 100644
--- a/core/res/res/values-mcc310-mnc410-gl/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-gl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"Non se introduciu ningunha tarxeta SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"Non se admite a tarxeta SIM MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Non se admite o teléfono MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-gu/strings.xml b/core/res/res/values-mcc310-mnc410-gu/strings.xml
index 26898f4..0637f9e 100644
--- a/core/res/res/values-mcc310-mnc410-gu/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-gu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIMને MM#2ની જોગવાઈ નથી"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIMને MM#3 કરવાની મંજૂરી નથી"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"MM#6 ફોનની મંજૂરી નથી"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-hi/strings.xml b/core/res/res/values-mcc310-mnc410-hi/strings.xml
index a01845a..3b574c3 100644
--- a/core/res/res/values-mcc310-mnc410-hi/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-hi/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM काम नहीं कर रहा है MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM की अनुमति नहीं है MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"फ़ोन की इजाज़त नहीं है MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-hr/strings.xml b/core/res/res/values-mcc310-mnc410-hr/strings.xml
index 47062c4..0ee4ae6 100644
--- a/core/res/res/values-mcc310-mnc410-hr/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-hr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"Ne pruža se usluga za SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM nije dopušten MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Telefon nije dopušten MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-hu/strings.xml b/core/res/res/values-mcc310-mnc410-hu/strings.xml
index 194d865..8abc27d 100644
--- a/core/res/res/values-mcc310-mnc410-hu/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-hu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"Nem engedélyezett SIM-kártya (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"A SIM-kártya nem engedélyezett (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"A telefon nem engedélyezett (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-hy/strings.xml b/core/res/res/values-mcc310-mnc410-hy/strings.xml
index 85129cc..79bc531 100644
--- a/core/res/res/values-mcc310-mnc410-hy/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-hy/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM քարտը նախապատրաստված չէ (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM քարտի օգտագործումն արգելված է (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Հեռախոսի օգտագործումն արգելված է (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-in/strings.xml b/core/res/res/values-mcc310-mnc410-in/strings.xml
index c065221..5750563 100644
--- a/core/res/res/values-mcc310-mnc410-in/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-in/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM tidak di-provisioning MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM tidak diizinkan MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Ponsel tidak diizinkan MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-is/strings.xml b/core/res/res/values-mcc310-mnc410-is/strings.xml
index a40a643..a786285 100644
--- a/core/res/res/values-mcc310-mnc410-is/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-is/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM-korti ekki úthlutað MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM-kort ekki leyft MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Sími ekki leyfður MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-it/strings.xml b/core/res/res/values-mcc310-mnc410-it/strings.xml
index ab5c731..135d39d 100644
--- a/core/res/res/values-mcc310-mnc410-it/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-it/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"Scheda SIM non predisposta MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"Scheda SIM non consentita MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Telefono non consentito MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-iw/strings.xml b/core/res/res/values-mcc310-mnc410-iw/strings.xml
index b675f64..8e505a9 100644
--- a/core/res/res/values-mcc310-mnc410-iw/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-iw/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"‏כרטיס ה-SIM לא הופעל MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"‏כרטיס ה-SIM לא מורשה לשימוש ברשת הסלולרית MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"‏הטלפון לא מורשה MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-ja/strings.xml b/core/res/res/values-mcc310-mnc410-ja/strings.xml
index 1961a75b..e0e98e3 100644
--- a/core/res/res/values-mcc310-mnc410-ja/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-ja/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM には対応していません(MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM は許可されていません(MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"電話は許可されていません(MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-ka/strings.xml b/core/res/res/values-mcc310-mnc410-ka/strings.xml
index 5216e8f..63af51c 100644
--- a/core/res/res/values-mcc310-mnc410-ka/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-ka/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM ბარათი უზრუნველყოფილი არ არის (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM ბარათი დაუშვებელია (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"ტელეფონი დაუშვებელია MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-kk/strings.xml b/core/res/res/values-mcc310-mnc410-kk/strings.xml
index 137c73a..5a52be2 100644
--- a/core/res/res/values-mcc310-mnc410-kk/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-kk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM картасы қарастырылмаған MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM картасына рұқсат етілмеген MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Телефон пайдалануға болмайды MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-km/strings.xml b/core/res/res/values-mcc310-mnc410-km/strings.xml
index 94babe1..809ffd1 100644
--- a/core/res/res/values-mcc310-mnc410-km/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-km/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"ស៊ីមកាត​មិនត្រូវបានផ្ដល់ជូនទេ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"មិនអនុញ្ញាត​ចំពោះស៊ីមកាតទេ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"មិន​អនុញ្ញាត​ចំពោះ​ទូរសព្ទ​ទេ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-kn/strings.xml b/core/res/res/values-mcc310-mnc410-kn/strings.xml
index b003dcc..40d05d4 100644
--- a/core/res/res/values-mcc310-mnc410-kn/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-kn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"MM#2 ಗೆ ಸಿಮ್‌ ಸಿದ್ಧವಾಗಿಲ್ಲ"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"ಸಿಮ್‌ MM#3 ಅನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"ಫೋನ್ MM#6 ಅನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-ko/strings.xml b/core/res/res/values-mcc310-mnc410-ko/strings.xml
index 7824d1e6..dc1a9a5 100644
--- a/core/res/res/values-mcc310-mnc410-ko/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-ko/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM이 프로비저닝되지 않음 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM이 허용되지 않음 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"전화가 허용되지 않음 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-ky/strings.xml b/core/res/res/values-mcc310-mnc410-ky/strings.xml
index 9e4f23e..05314ed 100644
--- a/core/res/res/values-mcc310-mnc410-ky/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-ky/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM карта таанылган жок (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM картаны колдонууга тыюу салынган (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Телефонду колдонууга тыюу салынган MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-lo/strings.xml b/core/res/res/values-mcc310-mnc410-lo/strings.xml
index 9684e7a7..9e095ba 100644
--- a/core/res/res/values-mcc310-mnc410-lo/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-lo/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM ບໍ່ໄດ້ເປີດໃຊ້ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM ບໍ່ອະນຸຍາດ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ໂທລະສັບ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-lt/strings.xml b/core/res/res/values-mcc310-mnc410-lt/strings.xml
index c4a646a..72b9a08 100644
--- a/core/res/res/values-mcc310-mnc410-lt/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-lt/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM kortelė neteikiama (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM kortelė neleidžiama (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Telefonas neleidžiamas (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-lv/strings.xml b/core/res/res/values-mcc310-mnc410-lv/strings.xml
index e95d62b..e3c04f8 100644
--- a/core/res/res/values-mcc310-mnc410-lv/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-lv/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM karte netiek nodrošināta: MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM karti nav atļauts izmantot: MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Tālruni nav atļauts izmantot: MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-mk/strings.xml b/core/res/res/values-mcc310-mnc410-mk/strings.xml
index 76bba96..d34261d 100644
--- a/core/res/res/values-mcc310-mnc410-mk/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-mk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"Не е обезбедена SIM-картичка, MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"Не е дозволена SIM-картичка, MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Телефонот не е дозволен MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-ml/strings.xml b/core/res/res/values-mcc310-mnc410-ml/strings.xml
index 94436bd..474814d 100644
--- a/core/res/res/values-mcc310-mnc410-ml/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-ml/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"സിം MM#2 പ്രൊവിഷൻ ചെയ്‌തിട്ടില്ല"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"സിം MM#3 അനുവദിച്ചിട്ടില്ല"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"ഫോൺ അനുവദനീയമല്ല MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-mn/strings.xml b/core/res/res/values-mcc310-mnc410-mn/strings.xml
index 2667aab..70cc206 100644
--- a/core/res/res/values-mcc310-mnc410-mn/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-mn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM-г идэвхжүүлээгүй байна MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM-г зөвшөөрөөгүй байна MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Утсыг зөвшөөрөөгүй MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-mr/strings.xml b/core/res/res/values-mcc310-mnc410-mr/strings.xml
index e7b0644..db40711 100644
--- a/core/res/res/values-mcc310-mnc410-mr/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-mr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM ने MM#2 ची तरतूद केलेली नाही"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM ने MM#3 ला परवानगी दिली नाही"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"फोन MM#6 ला अनुमती देत नाही"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-ms/strings.xml b/core/res/res/values-mcc310-mnc410-ms/strings.xml
index 85b8621..b896e67 100644
--- a/core/res/res/values-mcc310-mnc410-ms/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-ms/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM tidak diperuntukkan MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM tidak dibenarkan MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Telefon tidak dibenarkan MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-my/strings.xml b/core/res/res/values-mcc310-mnc410-my/strings.xml
index faa80ec..07a2967 100644
--- a/core/res/res/values-mcc310-mnc410-my/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-my/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"ဆင်းမ်ကို ထောက်ပံ့မထားပါ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"ဆင်းမ်ကို ခွင့်မပြုပါ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"ဖုန်းကို ခွင့်မပြုပါ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-nb/strings.xml b/core/res/res/values-mcc310-mnc410-nb/strings.xml
index 79be7af..4f6e125 100644
--- a/core/res/res/values-mcc310-mnc410-nb/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-nb/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM-kortet er ikke klargjort, MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM-kortet er ikke tillatt, MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Telefonen er ikke tillatt, MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-ne/strings.xml b/core/res/res/values-mcc310-mnc410-ne/strings.xml
index e270c7c..65adf0b 100644
--- a/core/res/res/values-mcc310-mnc410-ne/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-ne/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM को प्रावधान छैन MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM लाई अनुमति छैन MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"फोनलाई अनुमति छैन MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-nl/strings.xml b/core/res/res/values-mcc310-mnc410-nl/strings.xml
index 2995beb..7da7fab 100644
--- a/core/res/res/values-mcc310-mnc410-nl/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-nl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"Simkaart niet geregistreerd MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"Simkaart niet toegestaan MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Telefoon niet toegestaan MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-pa/strings.xml b/core/res/res/values-mcc310-mnc410-pa/strings.xml
index 70195f1..dd44bed 100644
--- a/core/res/res/values-mcc310-mnc410-pa/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-pa/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"ਸਿਮ ਦੀ ਵਿਵਸਥਾ ਨਹੀਂ ਹੈ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"ਸਿਮ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"ਫ਼ੋਨ ਨੂੰ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-pl/strings.xml b/core/res/res/values-mcc310-mnc410-pl/strings.xml
index 8677ad6..f74650f 100644
--- a/core/res/res/values-mcc310-mnc410-pl/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-pl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"MM#2 – karta SIM nieobsługiwana"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"MM#3 – niedozwolona karta SIM"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"MM#6 – telefon niedozwolony"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-pt-rBR/strings.xml b/core/res/res/values-mcc310-mnc410-pt-rBR/strings.xml
index 4f41e5e..f6bfc67 100644
--- a/core/res/res/values-mcc310-mnc410-pt-rBR/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-pt-rBR/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM não aprovisionado MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM não permitido MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Smartphone não permitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-pt-rPT/strings.xml b/core/res/res/values-mcc310-mnc410-pt-rPT/strings.xml
index 4f41e5e..5457416 100644
--- a/core/res/res/values-mcc310-mnc410-pt-rPT/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-pt-rPT/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM não aprovisionado MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM não permitido MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Telemóvel não permitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-pt/strings.xml b/core/res/res/values-mcc310-mnc410-pt/strings.xml
index 4f41e5e..f6bfc67 100644
--- a/core/res/res/values-mcc310-mnc410-pt/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-pt/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM não aprovisionado MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM não permitido MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Smartphone não permitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-ro/strings.xml b/core/res/res/values-mcc310-mnc410-ro/strings.xml
index fea0609..0fc9400 100644
--- a/core/res/res/values-mcc310-mnc410-ro/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-ro/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"Cardul SIM nu este activat MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"Cardul SIM nu este permis MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Telefonul nu este permis MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-ru/strings.xml b/core/res/res/values-mcc310-mnc410-ru/strings.xml
index a00e59c..8702e83 100644
--- a/core/res/res/values-mcc310-mnc410-ru/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-ru/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM-карта не активирована (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"Использование SIM-карты запрещено (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Звонки запрещены (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-si/strings.xml b/core/res/res/values-mcc310-mnc410-si/strings.xml
index 8f66f3d..cddc168 100644
--- a/core/res/res/values-mcc310-mnc410-si/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-si/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM MM#2 ප්‍රතිපාදනය නොකරයි"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM MM#3 ඉඩ නොදේ"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"දුරකථනය MM#6 ඉඩ නොදේ"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-sk/strings.xml b/core/res/res/values-mcc310-mnc410-sk/strings.xml
index e4d4bc6..354b138 100644
--- a/core/res/res/values-mcc310-mnc410-sk/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-sk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM karta nie je k dispozícii – MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM karta je zakázaná – MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Telefón nie je povolený (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-sl/strings.xml b/core/res/res/values-mcc310-mnc410-sl/strings.xml
index 2d03b04..d65d619 100644
--- a/core/res/res/values-mcc310-mnc410-sl/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-sl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"Kartica SIM ni omogočena za uporabo MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"Kartica SIM ni dovoljena MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Telefon ni dovoljen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-sq/strings.xml b/core/res/res/values-mcc310-mnc410-sq/strings.xml
index 51626d7..95ec705 100644
--- a/core/res/res/values-mcc310-mnc410-sq/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-sq/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"Karta SIM nuk është dhënë MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"Karta SIM nuk lejohet MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Telefoni nuk lejohet MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-sr/strings.xml b/core/res/res/values-mcc310-mnc410-sr/strings.xml
index b4a9006..66fe4e7 100644
--- a/core/res/res/values-mcc310-mnc410-sr/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-sr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM картица није подешена MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM картица није дозвољена MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Телефон није дозвољен MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-sv/strings.xml b/core/res/res/values-mcc310-mnc410-sv/strings.xml
index c270b04..77e0829 100644
--- a/core/res/res/values-mcc310-mnc410-sv/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-sv/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM-kort tillhandahålls inte MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM-kort tillåts inte MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Mobil tillåts inte MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-sw/strings.xml b/core/res/res/values-mcc310-mnc410-sw/strings.xml
index a6e6018..50c2e74 100644
--- a/core/res/res/values-mcc310-mnc410-sw/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-sw/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM haitumiki MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM hairuhusiwi MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Simu hairuhusiwi MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-ta/strings.xml b/core/res/res/values-mcc310-mnc410-ta/strings.xml
index 4ac46ce..61f922d 100644
--- a/core/res/res/values-mcc310-mnc410-ta/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-ta/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"சிம் அமைக்கப்படவில்லை MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"சிம் அனுமதிக்கப்படவில்லை MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"ஃபோன் அனுமதிக்கப்படவில்லை MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-te/strings.xml b/core/res/res/values-mcc310-mnc410-te/strings.xml
index 5b56435..133b332 100644
--- a/core/res/res/values-mcc310-mnc410-te/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-te/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM MM#2ని సక్రియం చేయలేదు"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM MM#3ని అనుమతించలేదు"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"ఫోన్ అనుమతించబడదు MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-th/strings.xml b/core/res/res/values-mcc310-mnc410-th/strings.xml
index cf51029..0b728bf 100644
--- a/core/res/res/values-mcc310-mnc410-th/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-th/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"ไม่มีการจัดสรรซิม MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"ไม่อนุญาตให้ใช้ซิม MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"ไม่อนุญาตให้ใช้โทรศัพท์ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-tl/strings.xml b/core/res/res/values-mcc310-mnc410-tl/strings.xml
index b2aa68a..3bf972d 100644
--- a/core/res/res/values-mcc310-mnc410-tl/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-tl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"Hindi na-provision ang SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"Hindi pinapahintulutan ang SIM MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Hindi pinapahintulutan ang telepono MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-tr/strings.xml b/core/res/res/values-mcc310-mnc410-tr/strings.xml
index 9e5c38e..34ce123 100644
--- a/core/res/res/values-mcc310-mnc410-tr/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-tr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM, MM#2\'nin temel hazırlığını yapamadı"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM MM#3\'e izin vermiyor"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Telefona izin verilmiyor MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-uk/strings.xml b/core/res/res/values-mcc310-mnc410-uk/strings.xml
index 5d74f80..9d8ccb2 100644
--- a/core/res/res/values-mcc310-mnc410-uk/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-uk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM-карту не надано (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM-карта заборонена (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Телефон заборонено (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-ur/strings.xml b/core/res/res/values-mcc310-mnc410-ur/strings.xml
index 8cf16e4..0a0032c 100644
--- a/core/res/res/values-mcc310-mnc410-ur/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-ur/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"‏SIM فراہم کردہ نہیں ہے MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"‏SIM کی اجازت نہیں ہے MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"‏فون کی اجازت نہیں ہے MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-uz/strings.xml b/core/res/res/values-mcc310-mnc410-uz/strings.xml
index 4618525..fdfad9b 100644
--- a/core/res/res/values-mcc310-mnc410-uz/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-uz/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM karta ishlatish taqiqlangan (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM karta ishlatish taqiqlangan (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Chaqiruvlar taqiqlangan (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-vi/strings.xml b/core/res/res/values-mcc310-mnc410-vi/strings.xml
index e6fc334..77cff43 100644
--- a/core/res/res/values-mcc310-mnc410-vi/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-vi/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM không được cấp phép MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM không được phép MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Không cho phép điện thoại MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-zh-rCN/strings.xml b/core/res/res/values-mcc310-mnc410-zh-rCN/strings.xml
index a00316a..ec8d371 100644
--- a/core/res/res/values-mcc310-mnc410-zh-rCN/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-zh-rCN/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"未配置的 SIM 卡 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"不被允许的 SIM 卡 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"不受允许的手机 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-zh-rHK/strings.xml b/core/res/res/values-mcc310-mnc410-zh-rHK/strings.xml
index 66a622e..7f54efb 100644
--- a/core/res/res/values-mcc310-mnc410-zh-rHK/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-zh-rHK/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"未佈建的 SIM 卡 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"不支援的 SIM 卡 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"不允許手機 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-zh-rTW/strings.xml b/core/res/res/values-mcc310-mnc410-zh-rTW/strings.xml
index 66a622e..a0aaaa5 100644
--- a/core/res/res/values-mcc310-mnc410-zh-rTW/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-zh-rTW/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"未佈建的 SIM 卡 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"不支援的 SIM 卡 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"不支援的手機 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410-zu/strings.xml b/core/res/res/values-mcc310-mnc410-zu/strings.xml
index a52049f..67cc1ac 100644
--- a/core/res/res/values-mcc310-mnc410-zu/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-zu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"I-SIM ayinikezelwe MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="1593063035884873292">"I-SIM ayivunyelwe MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="4477688981805467729">"Ifoni ayivunyelwe MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-af/strings.xml b/core/res/res/values-mcc310-mnc560-af/strings.xml
index ecbb954..87f698c 100644
--- a/core/res/res/values-mcc310-mnc560-af/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-af/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM is nie opgestel nie MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM word nie toegelaat nie MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Foon nie toegelaat nie MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-am/strings.xml b/core/res/res/values-mcc310-mnc560-am/strings.xml
index 297c059..c1f8350 100644
--- a/core/res/res/values-mcc310-mnc560-am/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-am/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"ሲም አልቀረበም MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"ሲም አይፈቀድም MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"ስልክ አይፈቀድም MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-ar/strings.xml b/core/res/res/values-mcc310-mnc560-ar/strings.xml
index 12a06fa..d5c684f 100644
--- a/core/res/res/values-mcc310-mnc560-ar/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-ar/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"‏لم يتم توفير SIM ‏MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"‏غير مسموح باستخدام SIM ‏MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"‏غير مسموح باستخدام الهاتف MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-az/strings.xml b/core/res/res/values-mcc310-mnc560-az/strings.xml
index 9acc2c1..1edff5e 100644
--- a/core/res/res/values-mcc310-mnc560-az/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-az/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM MM#2 təmin etmir"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM MM#3 dəstəkləmir"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"MM#6 telefonu dəstəklənmir"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-b+sr+Latn/strings.xml b/core/res/res/values-mcc310-mnc560-b+sr+Latn/strings.xml
index 616f871..d362bad 100644
--- a/core/res/res/values-mcc310-mnc560-b+sr+Latn/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-b+sr+Latn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM kartica nije podešena MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM kartica nije dozvoljena MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Telefon nije dozvoljen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-be/strings.xml b/core/res/res/values-mcc310-mnc560-be/strings.xml
index 0e70cf2..3f62d3c 100644
--- a/core/res/res/values-mcc310-mnc560-be/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-be/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM-карты няма MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM-карта не дапускаецца MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Тэлефон не дапускаецца MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-bg/strings.xml b/core/res/res/values-mcc310-mnc560-bg/strings.xml
index 49c2d2f..98c362d 100644
--- a/core/res/res/values-mcc310-mnc560-bg/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-bg/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM картата не е обезпечена MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM картата не е разрешена MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Телефонът не е разрешен MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-bn/strings.xml b/core/res/res/values-mcc310-mnc560-bn/strings.xml
index 438791d..989da8d 100644
--- a/core/res/res/values-mcc310-mnc560-bn/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-bn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"সিমের জন্য প্রস্তুত নয় MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"সিমের অনুমতি নেই MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"ফোন অনুমোদিত নয় MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-bs/strings.xml b/core/res/res/values-mcc310-mnc560-bs/strings.xml
index 82046a6..3dccc4be 100644
--- a/core/res/res/values-mcc310-mnc560-bs/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-bs/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM kartica nije dodijeljena MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM kartica nije dozvoljena MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Telefon nije dozvoljen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-ca/strings.xml b/core/res/res/values-mcc310-mnc560-ca/strings.xml
index 1eac589..00fc4ed 100644
--- a/core/res/res/values-mcc310-mnc560-ca/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-ca/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"La SIM no està proporcionada a MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"La SIM no és compatible a MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Telèfon no compatible MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-cs/strings.xml b/core/res/res/values-mcc310-mnc560-cs/strings.xml
index 4701f99..9a68265 100644
--- a/core/res/res/values-mcc310-mnc560-cs/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-cs/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM karta není poskytována (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM karta není povolena (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Telefon není povolen (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-da/strings.xml b/core/res/res/values-mcc310-mnc560-da/strings.xml
index 2c63d87..857e040 100644
--- a/core/res/res/values-mcc310-mnc560-da/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-da/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM-kort leveres ikke MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM-kort er ikke tilladt MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Telefonen har ikke adgangstilladelse MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-de/strings.xml b/core/res/res/values-mcc310-mnc560-de/strings.xml
index e8fec2c..a5d594b 100644
--- a/core/res/res/values-mcc310-mnc560-de/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-de/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM-Karte nicht eingerichtet MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM-Karte nicht zulässig MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Smartphone nicht zulässig MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-el/strings.xml b/core/res/res/values-mcc310-mnc560-el/strings.xml
index efd81f7..803ecdd 100644
--- a/core/res/res/values-mcc310-mnc560-el/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-el/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"Δεν παρέχεται κάρτα SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"Η κάρτα SIM δεν επιτρέπεται MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Το τηλέφωνο δεν επιτρέπεται MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-en-rAU/strings.xml b/core/res/res/values-mcc310-mnc560-en-rAU/strings.xml
index c218c64..d24a056 100644
--- a/core/res/res/values-mcc310-mnc560-en-rAU/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-en-rAU/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-en-rCA/strings.xml b/core/res/res/values-mcc310-mnc560-en-rCA/strings.xml
index c218c64..d24a056 100644
--- a/core/res/res/values-mcc310-mnc560-en-rCA/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-en-rCA/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-en-rGB/strings.xml b/core/res/res/values-mcc310-mnc560-en-rGB/strings.xml
index c218c64..d24a056 100644
--- a/core/res/res/values-mcc310-mnc560-en-rGB/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-en-rGB/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-en-rIN/strings.xml b/core/res/res/values-mcc310-mnc560-en-rIN/strings.xml
index c218c64..d24a056 100644
--- a/core/res/res/values-mcc310-mnc560-en-rIN/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-en-rIN/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-en-rXC/strings.xml b/core/res/res/values-mcc310-mnc560-en-rXC/strings.xml
index 67c05b2..694aa31 100644
--- a/core/res/res/values-mcc310-mnc560-en-rXC/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-en-rXC/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‎‏‎‎‏‏‏‎‎‏‏‏‏‏‎‎‏‎‎‏‎‎‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‎‎‎‏‏‏‎‎‏‏‏‎‎‏‏‎‏‎‏‎SIM not provisioned MM#2‎‏‎‎‏‎"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‏‏‏‏‎‏‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‎‎‎‎‎‏‎‎‎‎‎‏‏‎‏‎‎‎‎‎‏‏‏‏‏‎‎SIM not allowed MM#3‎‏‎‎‏‎"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‏‎‎‎‏‎‏‎‏‎‎‎‎‎‎‏‏‎‎‏‎‎‏‎‎‎‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‎‎‏‏‎‎‎Phone not allowed MM#6‎‏‎‎‏‎"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-es-rUS/strings.xml b/core/res/res/values-mcc310-mnc560-es-rUS/strings.xml
index 62d61ba..52b2554 100644
--- a/core/res/res/values-mcc310-mnc560-es-rUS/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-es-rUS/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM no provista MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM no permitida MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Teléfono no admitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-es/strings.xml b/core/res/res/values-mcc310-mnc560-es/strings.xml
index dbd71d5..8fb818b 100644
--- a/core/res/res/values-mcc310-mnc560-es/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-es/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM no proporcionada (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM no admitida (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Teléfono no admitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-et/strings.xml b/core/res/res/values-mcc310-mnc560-et/strings.xml
index b269ace..1bb5bd5 100644
--- a/core/res/res/values-mcc310-mnc560-et/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-et/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM-kaart on ette valmistamata MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM-kaart pole lubatud MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Telefon pole lubatud MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-eu/strings.xml b/core/res/res/values-mcc310-mnc560-eu/strings.xml
index cee0106..1fd51a9 100644
--- a/core/res/res/values-mcc310-mnc560-eu/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-eu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"Ez dago SIM txartelik MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"Ez da onartzen SIM txartela MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Telefonoa ez da onartzen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-fa/strings.xml b/core/res/res/values-mcc310-mnc560-fa/strings.xml
index b4683c7..d2c8c41 100644
--- a/core/res/res/values-mcc310-mnc560-fa/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-fa/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"‏سیم‌کارت مجوز لازم را ندارد MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"‏سیم‌کارت مجاز نیست MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"‏تلفن مجاز نیست MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-fi/strings.xml b/core/res/res/values-mcc310-mnc560-fi/strings.xml
index 54c80ed..fc7629d 100644
--- a/core/res/res/values-mcc310-mnc560-fi/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-fi/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM-kortti ei käyttäjien hallinnassa MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM-kortti estetty MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Puhelin estetty MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-fr-rCA/strings.xml b/core/res/res/values-mcc310-mnc560-fr-rCA/strings.xml
index 8b6c4ec..246b434 100644
--- a/core/res/res/values-mcc310-mnc560-fr-rCA/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-fr-rCA/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"Carte SIM non configurée, MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"Carte SIM non autorisée, MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Téléphone non autorisé MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-fr/strings.xml b/core/res/res/values-mcc310-mnc560-fr/strings.xml
index b52eaf7..9601bc5bd 100644
--- a/core/res/res/values-mcc310-mnc560-fr/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-fr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"Carte SIM non provisionnée MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"Carte SIM non autorisée MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Téléphone non autorisé MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-gl/strings.xml b/core/res/res/values-mcc310-mnc560-gl/strings.xml
index a8c04d2..1f78daa 100644
--- a/core/res/res/values-mcc310-mnc560-gl/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-gl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"Non se introduciu ningunha tarxeta SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"Non se admite a tarxeta SIM MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Non se admite o teléfono MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-gu/strings.xml b/core/res/res/values-mcc310-mnc560-gu/strings.xml
index c3892da..f14a72b 100644
--- a/core/res/res/values-mcc310-mnc560-gu/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-gu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIMને MM#2ની જોગવાઈ નથી"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIMને MM#3 કરવાની મંજૂરી નથી"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"MM#6 ફોનની મંજૂરી નથી"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-hi/strings.xml b/core/res/res/values-mcc310-mnc560-hi/strings.xml
index 4e07e4f..7c52266 100644
--- a/core/res/res/values-mcc310-mnc560-hi/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-hi/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM काम नहीं कर रहा है MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM की अनुमति नहीं है MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"फ़ोन की इजाज़त नहीं है MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-hr/strings.xml b/core/res/res/values-mcc310-mnc560-hr/strings.xml
index dc6653e..f51599c 100644
--- a/core/res/res/values-mcc310-mnc560-hr/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-hr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"Ne pruža se usluga za SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM nije dopušten MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Telefon nije dopušten MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-hu/strings.xml b/core/res/res/values-mcc310-mnc560-hu/strings.xml
index 1a7a6b3..f23dd04 100644
--- a/core/res/res/values-mcc310-mnc560-hu/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-hu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"Nem engedélyezett SIM-kártya (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"A SIM-kártya nem engedélyezett (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"A telefon nem engedélyezett (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-hy/strings.xml b/core/res/res/values-mcc310-mnc560-hy/strings.xml
index c398877..072c0c5 100644
--- a/core/res/res/values-mcc310-mnc560-hy/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-hy/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM քարտը նախապատրաստված չէ (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM քարտի օգտագործումն արգելված է (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Հեռախոսի օգտագործումն արգելված է (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-in/strings.xml b/core/res/res/values-mcc310-mnc560-in/strings.xml
index c3c7df3..9b56660 100644
--- a/core/res/res/values-mcc310-mnc560-in/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-in/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM tidak di-provisioning MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM tidak diizinkan MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Ponsel tidak diizinkan MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-is/strings.xml b/core/res/res/values-mcc310-mnc560-is/strings.xml
index 4a59abd..3ae1361 100644
--- a/core/res/res/values-mcc310-mnc560-is/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-is/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM-korti ekki úthlutað MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM-kort ekki leyft MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Sími ekki leyfður MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-it/strings.xml b/core/res/res/values-mcc310-mnc560-it/strings.xml
index d2c966c..201e5b3 100644
--- a/core/res/res/values-mcc310-mnc560-it/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-it/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"Scheda SIM non predisposta MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"Scheda SIM non consentita MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Telefono non consentito MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-iw/strings.xml b/core/res/res/values-mcc310-mnc560-iw/strings.xml
index 68f0aa9..168f5ea 100644
--- a/core/res/res/values-mcc310-mnc560-iw/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-iw/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"‏כרטיס ה-SIM לא הופעל MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"‏כרטיס ה-SIM לא מורשה לשימוש ברשת הסלולרית MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"‏הטלפון לא מורשה MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-ja/strings.xml b/core/res/res/values-mcc310-mnc560-ja/strings.xml
index 0429996..244c93a 100644
--- a/core/res/res/values-mcc310-mnc560-ja/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-ja/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM には対応していません(MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM は許可されていません(MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"電話は許可されていません(MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-ka/strings.xml b/core/res/res/values-mcc310-mnc560-ka/strings.xml
index b0371f0..c89674b 100644
--- a/core/res/res/values-mcc310-mnc560-ka/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-ka/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM ბარათი უზრუნველყოფილი არ არის (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM ბარათი დაუშვებელია (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"ტელეფონი დაუშვებელია MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-kk/strings.xml b/core/res/res/values-mcc310-mnc560-kk/strings.xml
index 2015f8c..33aa902 100644
--- a/core/res/res/values-mcc310-mnc560-kk/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-kk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM картасы қарастырылмаған MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM картасына рұқсат етілмеген MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Телефон пайдалануға болмайды MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-km/strings.xml b/core/res/res/values-mcc310-mnc560-km/strings.xml
index a13ca7d..b01e283 100644
--- a/core/res/res/values-mcc310-mnc560-km/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-km/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"ស៊ីមកាត​មិនត្រូវបានផ្ដល់ជូនទេ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"មិនអនុញ្ញាត​ចំពោះស៊ីមកាតទេ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"មិន​អនុញ្ញាត​ចំពោះ​ទូរសព្ទ​ទេ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-kn/strings.xml b/core/res/res/values-mcc310-mnc560-kn/strings.xml
index da75904..0879d4d 100644
--- a/core/res/res/values-mcc310-mnc560-kn/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-kn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"MM#2 ಗೆ ಸಿಮ್‌ ಸಿದ್ಧವಾಗಿಲ್ಲ"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"ಸಿಮ್‌ MM#3 ಅನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"ಫೋನ್ MM#6 ಅನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-ko/strings.xml b/core/res/res/values-mcc310-mnc560-ko/strings.xml
index ee71a09c..74d6064 100644
--- a/core/res/res/values-mcc310-mnc560-ko/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-ko/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM이 프로비저닝되지 않음 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM이 허용되지 않음 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"전화가 허용되지 않음 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-ky/strings.xml b/core/res/res/values-mcc310-mnc560-ky/strings.xml
index 856bebc..75e4794 100644
--- a/core/res/res/values-mcc310-mnc560-ky/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-ky/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM карта таанылган жок (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM картаны колдонууга тыюу салынган (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Телефонду колдонууга тыюу салынган MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-lo/strings.xml b/core/res/res/values-mcc310-mnc560-lo/strings.xml
index 702470e..9244031 100644
--- a/core/res/res/values-mcc310-mnc560-lo/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-lo/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM ບໍ່ໄດ້ເປີດໃຊ້ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM ບໍ່ອະນຸຍາດ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ໂທລະສັບ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-lt/strings.xml b/core/res/res/values-mcc310-mnc560-lt/strings.xml
index c3c5a9e..8ced4c0 100644
--- a/core/res/res/values-mcc310-mnc560-lt/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-lt/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM kortelė neteikiama (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM kortelė neleidžiama (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Telefonas neleidžiamas (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-lv/strings.xml b/core/res/res/values-mcc310-mnc560-lv/strings.xml
index dcf7805..fc565d6 100644
--- a/core/res/res/values-mcc310-mnc560-lv/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-lv/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM karte netiek nodrošināta: MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM karti nav atļauts izmantot: MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Tālruni nav atļauts izmantot: MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-mk/strings.xml b/core/res/res/values-mcc310-mnc560-mk/strings.xml
index cf0ae7e..6d159f4 100644
--- a/core/res/res/values-mcc310-mnc560-mk/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-mk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"Не е обезбедена SIM-картичка, MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"Не е дозволена SIM-картичка, MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Телефонот не е дозволен MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-ml/strings.xml b/core/res/res/values-mcc310-mnc560-ml/strings.xml
index fb506bf..859e887 100644
--- a/core/res/res/values-mcc310-mnc560-ml/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-ml/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"സിം MM#2 പ്രൊവിഷൻ ചെയ്‌തിട്ടില്ല"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"സിം MM#3 അനുവദിച്ചിട്ടില്ല"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"ഫോൺ അനുവദനീയമല്ല MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-mn/strings.xml b/core/res/res/values-mcc310-mnc560-mn/strings.xml
index 0bf1599..1d01e8c 100644
--- a/core/res/res/values-mcc310-mnc560-mn/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-mn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM-г идэвхжүүлээгүй байна MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM-г зөвшөөрөөгүй байна MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Утсыг зөвшөөрөөгүй MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-mr/strings.xml b/core/res/res/values-mcc310-mnc560-mr/strings.xml
index 69e81ad..8a737e4 100644
--- a/core/res/res/values-mcc310-mnc560-mr/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-mr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM ने MM#2 ची तरतूद केलेली नाही"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM ने MM#3 ला परवानगी दिली नाही"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"फोन MM#6 ला अनुमती देत नाही"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-ms/strings.xml b/core/res/res/values-mcc310-mnc560-ms/strings.xml
index cd0aed7..3c5c712 100644
--- a/core/res/res/values-mcc310-mnc560-ms/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-ms/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM tidak diperuntukkan MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM tidak dibenarkan MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Telefon tidak dibenarkan MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-my/strings.xml b/core/res/res/values-mcc310-mnc560-my/strings.xml
index 58fba87..00600be 100644
--- a/core/res/res/values-mcc310-mnc560-my/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-my/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"ဆင်းမ်ကို ထောက်ပံ့မထားပါ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"ဆင်းမ်ကို ခွင့်မပြုပါ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"ဖုန်းကို ခွင့်မပြုပါ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-nb/strings.xml b/core/res/res/values-mcc310-mnc560-nb/strings.xml
index bc90ae1..ce9dd874 100644
--- a/core/res/res/values-mcc310-mnc560-nb/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-nb/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM-kortet er ikke klargjort, MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM-kortet er ikke tillatt, MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Telefonen er ikke tillatt, MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-ne/strings.xml b/core/res/res/values-mcc310-mnc560-ne/strings.xml
index 75c493d..923db94 100644
--- a/core/res/res/values-mcc310-mnc560-ne/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-ne/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM को प्रावधान छैन MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM लाई अनुमति छैन MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"फोनलाई अनुमति छैन MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-nl/strings.xml b/core/res/res/values-mcc310-mnc560-nl/strings.xml
index 7241627..eadbb84 100644
--- a/core/res/res/values-mcc310-mnc560-nl/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-nl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"Simkaart niet geregistreerd MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"Simkaart niet toegestaan MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Telefoon niet toegestaan MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-pa/strings.xml b/core/res/res/values-mcc310-mnc560-pa/strings.xml
index a2b76be..3c48708 100644
--- a/core/res/res/values-mcc310-mnc560-pa/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-pa/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"ਸਿਮ ਦੀ ਵਿਵਸਥਾ ਨਹੀਂ ਹੈ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"ਸਿਮ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"ਫ਼ੋਨ ਨੂੰ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-pl/strings.xml b/core/res/res/values-mcc310-mnc560-pl/strings.xml
index f844db6..0f4b474 100644
--- a/core/res/res/values-mcc310-mnc560-pl/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-pl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"MM#2 – karta SIM nieobsługiwana"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"MM#3 – niedozwolona karta SIM"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"MM#6 – telefon niedozwolony"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-pt-rBR/strings.xml b/core/res/res/values-mcc310-mnc560-pt-rBR/strings.xml
index 4c10ef9..fba400c 100644
--- a/core/res/res/values-mcc310-mnc560-pt-rBR/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-pt-rBR/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM não aprovisionado MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM não permitido MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Smartphone não permitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-pt-rPT/strings.xml b/core/res/res/values-mcc310-mnc560-pt-rPT/strings.xml
index 4c10ef9..991627c 100644
--- a/core/res/res/values-mcc310-mnc560-pt-rPT/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-pt-rPT/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM não aprovisionado MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM não permitido MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Telemóvel não permitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-pt/strings.xml b/core/res/res/values-mcc310-mnc560-pt/strings.xml
index 4c10ef9..fba400c 100644
--- a/core/res/res/values-mcc310-mnc560-pt/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-pt/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM não aprovisionado MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM não permitido MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Smartphone não permitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-ro/strings.xml b/core/res/res/values-mcc310-mnc560-ro/strings.xml
index e24b74c..1e6c63a 100644
--- a/core/res/res/values-mcc310-mnc560-ro/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-ro/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"Cardul SIM nu este activat MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"Cardul SIM nu este permis MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Telefonul nu este permis MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-ru/strings.xml b/core/res/res/values-mcc310-mnc560-ru/strings.xml
index 35bf36f..948c8c8 100644
--- a/core/res/res/values-mcc310-mnc560-ru/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-ru/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM-карта не активирована (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"Использование SIM-карты запрещено (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Звонки запрещены (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-si/strings.xml b/core/res/res/values-mcc310-mnc560-si/strings.xml
index 4c60ce4..b65d067 100644
--- a/core/res/res/values-mcc310-mnc560-si/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-si/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM MM#2 ප්‍රතිපාදනය නොකරයි"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM MM#3 ඉඩ නොදේ"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"දුරකථනය MM#6 ඉඩ නොදේ"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-sk/strings.xml b/core/res/res/values-mcc310-mnc560-sk/strings.xml
index ad4aba4..cae65ff 100644
--- a/core/res/res/values-mcc310-mnc560-sk/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-sk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM karta nie je k dispozícii – MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM karta je zakázaná – MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Telefón nie je povolený (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-sl/strings.xml b/core/res/res/values-mcc310-mnc560-sl/strings.xml
index 7855987..15c495e 100644
--- a/core/res/res/values-mcc310-mnc560-sl/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-sl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"Kartica SIM ni omogočena za uporabo MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"Kartica SIM ni dovoljena MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Telefon ni dovoljen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-sq/strings.xml b/core/res/res/values-mcc310-mnc560-sq/strings.xml
index 527430e..a554e81 100644
--- a/core/res/res/values-mcc310-mnc560-sq/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-sq/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"Karta SIM nuk është dhënë MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"Karta SIM nuk lejohet MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Telefoni nuk lejohet MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-sr/strings.xml b/core/res/res/values-mcc310-mnc560-sr/strings.xml
index ec5a2b6..3a2d6c0 100644
--- a/core/res/res/values-mcc310-mnc560-sr/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-sr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM картица није подешена MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM картица није дозвољена MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Телефон није дозвољен MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-sv/strings.xml b/core/res/res/values-mcc310-mnc560-sv/strings.xml
index d113989..ef712b4 100644
--- a/core/res/res/values-mcc310-mnc560-sv/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-sv/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM-kort tillhandahålls inte MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM-kort tillåts inte MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Mobil tillåts inte MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-sw/strings.xml b/core/res/res/values-mcc310-mnc560-sw/strings.xml
index 4e3df8b..2f989a7 100644
--- a/core/res/res/values-mcc310-mnc560-sw/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-sw/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM haitumiki MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM hairuhusiwi MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Simu hairuhusiwi MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-ta/strings.xml b/core/res/res/values-mcc310-mnc560-ta/strings.xml
index 78f8243..dc98cca 100644
--- a/core/res/res/values-mcc310-mnc560-ta/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-ta/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"சிம் அமைக்கப்படவில்லை MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"சிம் அனுமதிக்கப்படவில்லை MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"ஃபோன் அனுமதிக்கப்படவில்லை MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-te/strings.xml b/core/res/res/values-mcc310-mnc560-te/strings.xml
index aeda941..f5e09ba 100644
--- a/core/res/res/values-mcc310-mnc560-te/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-te/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM MM#2ని సక్రియం చేయలేదు"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM MM#3ని అనుమతించలేదు"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"ఫోన్ అనుమతించబడదు MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-th/strings.xml b/core/res/res/values-mcc310-mnc560-th/strings.xml
index 7896973..881f797 100644
--- a/core/res/res/values-mcc310-mnc560-th/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-th/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"ไม่มีการจัดสรรซิม MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"ไม่อนุญาตให้ใช้ซิม MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"ไม่อนุญาตให้ใช้โทรศัพท์ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-tl/strings.xml b/core/res/res/values-mcc310-mnc560-tl/strings.xml
index ac87cb5..2e32d53 100644
--- a/core/res/res/values-mcc310-mnc560-tl/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-tl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"Hindi na-provision ang SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"Hindi pinapahintulutan ang SIM MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Hindi pinapahintulutan ang telepono MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-tr/strings.xml b/core/res/res/values-mcc310-mnc560-tr/strings.xml
index 5ea1d80..2b41e2c 100644
--- a/core/res/res/values-mcc310-mnc560-tr/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-tr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM, MM#2\'nin temel hazırlığını yapamadı"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM MM#3\'e izin vermiyor"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Telefona izin verilmiyor MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-uk/strings.xml b/core/res/res/values-mcc310-mnc560-uk/strings.xml
index 7ee6b88..bd75240 100644
--- a/core/res/res/values-mcc310-mnc560-uk/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-uk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM-карту не надано (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM-карта заборонена (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Телефон заборонено (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-ur/strings.xml b/core/res/res/values-mcc310-mnc560-ur/strings.xml
index 609d3e8..c8c20d6 100644
--- a/core/res/res/values-mcc310-mnc560-ur/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-ur/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"‏SIM فراہم کردہ نہیں ہے MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"‏SIM کی اجازت نہیں ہے MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"‏فون کی اجازت نہیں ہے MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-uz/strings.xml b/core/res/res/values-mcc310-mnc560-uz/strings.xml
index 4157041..92b86e1 100644
--- a/core/res/res/values-mcc310-mnc560-uz/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-uz/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM karta ishlatish taqiqlangan (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM karta ishlatish taqiqlangan (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Chaqiruvlar taqiqlangan (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-vi/strings.xml b/core/res/res/values-mcc310-mnc560-vi/strings.xml
index b2284e1..7023d51 100644
--- a/core/res/res/values-mcc310-mnc560-vi/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-vi/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM không được cấp phép MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM không được phép MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Không cho phép điện thoại MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-zh-rCN/strings.xml b/core/res/res/values-mcc310-mnc560-zh-rCN/strings.xml
index 050ea01..bf168bd 100644
--- a/core/res/res/values-mcc310-mnc560-zh-rCN/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-zh-rCN/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"未配置的 SIM 卡 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"不被允许的 SIM 卡 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"不受允许的手机 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-zh-rHK/strings.xml b/core/res/res/values-mcc310-mnc560-zh-rHK/strings.xml
index 43cfc01..ea8dcab 100644
--- a/core/res/res/values-mcc310-mnc560-zh-rHK/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-zh-rHK/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"未佈建的 SIM 卡 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"不支援的 SIM 卡 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"不允許手機 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-zh-rTW/strings.xml b/core/res/res/values-mcc310-mnc560-zh-rTW/strings.xml
index 43cfc01..3674ee2 100644
--- a/core/res/res/values-mcc310-mnc560-zh-rTW/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-zh-rTW/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"未佈建的 SIM 卡 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"不支援的 SIM 卡 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"不支援的手機 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc560-zu/strings.xml b/core/res/res/values-mcc310-mnc560-zu/strings.xml
index e1b7abb..7b17fed 100644
--- a/core/res/res/values-mcc310-mnc560-zu/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-zu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"I-SIM ayinikezelwe MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2519618694918727742">"I-SIM ayivunyelwe MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="7030488670186895244">"Ifoni ayivunyelwe MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-af/strings.xml b/core/res/res/values-mcc310-mnc950-af/strings.xml
index 19ae78d..95b73b91 100644
--- a/core/res/res/values-mcc310-mnc950-af/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-af/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM is nie opgestel nie MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM word nie toegelaat nie MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Foon nie toegelaat nie MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-am/strings.xml b/core/res/res/values-mcc310-mnc950-am/strings.xml
index e81745d..ca5d603 100644
--- a/core/res/res/values-mcc310-mnc950-am/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-am/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"ሲም አልቀረበም MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"ሲም አይፈቀድም MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"ስልክ አይፈቀድም MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-ar/strings.xml b/core/res/res/values-mcc310-mnc950-ar/strings.xml
index 1aab01c..bc2248b 100644
--- a/core/res/res/values-mcc310-mnc950-ar/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-ar/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"‏لم يتم توفير SIM ‏MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"‏غير مسموح باستخدام SIM ‏MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"‏غير مسموح باستخدام الهاتف MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-az/strings.xml b/core/res/res/values-mcc310-mnc950-az/strings.xml
index 26d91ef..ceb15ea 100644
--- a/core/res/res/values-mcc310-mnc950-az/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-az/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM MM#2 təmin etmir"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM MM#3 dəstəkləmir"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"MM#6 telefonu dəstəklənmir"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-b+sr+Latn/strings.xml b/core/res/res/values-mcc310-mnc950-b+sr+Latn/strings.xml
index 44c5d19..def86da 100644
--- a/core/res/res/values-mcc310-mnc950-b+sr+Latn/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-b+sr+Latn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM kartica nije podešena MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM kartica nije dozvoljena MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Telefon nije dozvoljen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-be/strings.xml b/core/res/res/values-mcc310-mnc950-be/strings.xml
index 2bae8c4..4dd80ff 100644
--- a/core/res/res/values-mcc310-mnc950-be/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-be/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM-карты няма MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM-карта не дапускаецца MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Тэлефон не дапускаецца MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-bg/strings.xml b/core/res/res/values-mcc310-mnc950-bg/strings.xml
index 761b439..5342fa8 100644
--- a/core/res/res/values-mcc310-mnc950-bg/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-bg/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM картата не е обезпечена MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM картата не е разрешена MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Телефонът не е разрешен MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-bn/strings.xml b/core/res/res/values-mcc310-mnc950-bn/strings.xml
index 32ba8b8..d12c75a 100644
--- a/core/res/res/values-mcc310-mnc950-bn/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-bn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"সিমের জন্য প্রস্তুত নয় MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"সিমের অনুমতি নেই MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"ফোন অনুমোদিত নয় MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-bs/strings.xml b/core/res/res/values-mcc310-mnc950-bs/strings.xml
index b06b586..4fbaa3c1 100644
--- a/core/res/res/values-mcc310-mnc950-bs/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-bs/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM kartica nije dodijeljena MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM kartica nije dozvoljena MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Telefon nije dozvoljen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-ca/strings.xml b/core/res/res/values-mcc310-mnc950-ca/strings.xml
index 9b77ce7..adb12e8 100644
--- a/core/res/res/values-mcc310-mnc950-ca/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-ca/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"La SIM no està proporcionada a MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"La SIM no és compatible a MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Telèfon no compatible MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-cs/strings.xml b/core/res/res/values-mcc310-mnc950-cs/strings.xml
index 3f8b8aa..49cc25f 100644
--- a/core/res/res/values-mcc310-mnc950-cs/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-cs/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM karta není poskytována (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM karta není povolena (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Telefon není povolen (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-da/strings.xml b/core/res/res/values-mcc310-mnc950-da/strings.xml
index 6cd8306..e63a586 100644
--- a/core/res/res/values-mcc310-mnc950-da/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-da/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM-kort leveres ikke MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM-kort er ikke tilladt MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Telefonen har ikke adgangstilladelse MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-de/strings.xml b/core/res/res/values-mcc310-mnc950-de/strings.xml
index 70e3068..60d81e6 100644
--- a/core/res/res/values-mcc310-mnc950-de/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-de/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM-Karte nicht eingerichtet MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM-Karte nicht zulässig MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Smartphone nicht zulässig MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-el/strings.xml b/core/res/res/values-mcc310-mnc950-el/strings.xml
index 1a2542c..bffaa00 100644
--- a/core/res/res/values-mcc310-mnc950-el/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-el/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"Δεν παρέχεται κάρτα SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"Η κάρτα SIM δεν επιτρέπεται MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Το τηλέφωνο δεν επιτρέπεται MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-en-rAU/strings.xml b/core/res/res/values-mcc310-mnc950-en-rAU/strings.xml
index 7ef6605..d2d137c 100644
--- a/core/res/res/values-mcc310-mnc950-en-rAU/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-en-rAU/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-en-rCA/strings.xml b/core/res/res/values-mcc310-mnc950-en-rCA/strings.xml
index 7ef6605..d2d137c 100644
--- a/core/res/res/values-mcc310-mnc950-en-rCA/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-en-rCA/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-en-rGB/strings.xml b/core/res/res/values-mcc310-mnc950-en-rGB/strings.xml
index 7ef6605..d2d137c 100644
--- a/core/res/res/values-mcc310-mnc950-en-rGB/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-en-rGB/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-en-rIN/strings.xml b/core/res/res/values-mcc310-mnc950-en-rIN/strings.xml
index 7ef6605..d2d137c 100644
--- a/core/res/res/values-mcc310-mnc950-en-rIN/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-en-rIN/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-en-rXC/strings.xml b/core/res/res/values-mcc310-mnc950-en-rXC/strings.xml
index 243d731..89619c4 100644
--- a/core/res/res/values-mcc310-mnc950-en-rXC/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-en-rXC/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‎‏‎‏‎‎‎‎‎‏‎‏‏‎‏‎‏‏‎‎‎‎‏‎‎‏‎‎‎‎‎‎‏‏‎‎‏‎‎‏‏‎‏‏‎‏‎‏‎‏‎‏‎‏‏‏‎SIM not provisioned MM#2‎‏‎‎‏‎"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‎‎‎‏‏‏‏‎‎‏‎‎‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‏‏‏‏‏‎‎‎‎‎‏‎‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‎‎SIM not allowed MM#3‎‏‎‎‏‎"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‎‎‏‏‎‎‎‎‎‏‎‎‏‏‏‏‎‎‎‏‏‎‏‎‏‎‎‏‎‏‎‎‏‎‏‏‎‏‏‎‎‏‎‎‏‏‎‎‏‎Phone not allowed MM#6‎‏‎‎‏‎"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-es-rUS/strings.xml b/core/res/res/values-mcc310-mnc950-es-rUS/strings.xml
index 31a863c..d194180 100644
--- a/core/res/res/values-mcc310-mnc950-es-rUS/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-es-rUS/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM no provista MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM no permitida MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Teléfono no admitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-es/strings.xml b/core/res/res/values-mcc310-mnc950-es/strings.xml
index ba8c78b..bbb0acf 100644
--- a/core/res/res/values-mcc310-mnc950-es/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-es/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM no proporcionada (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM no admitida (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Teléfono no admitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-et/strings.xml b/core/res/res/values-mcc310-mnc950-et/strings.xml
index 013243a..14b4d45 100644
--- a/core/res/res/values-mcc310-mnc950-et/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-et/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM-kaart on ette valmistamata MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM-kaart pole lubatud MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Telefon pole lubatud MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-eu/strings.xml b/core/res/res/values-mcc310-mnc950-eu/strings.xml
index 097e423..2e33d02 100644
--- a/core/res/res/values-mcc310-mnc950-eu/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-eu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"Ez dago SIM txartelik MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"Ez da onartzen SIM txartela MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Telefonoa ez da onartzen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-fa/strings.xml b/core/res/res/values-mcc310-mnc950-fa/strings.xml
index 3281bb5..f889d5e 100644
--- a/core/res/res/values-mcc310-mnc950-fa/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-fa/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"‏سیم‌کارت مجوز لازم را ندارد MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"‏سیم‌کارت مجاز نیست MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"‏تلفن مجاز نیست MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-fi/strings.xml b/core/res/res/values-mcc310-mnc950-fi/strings.xml
index 01e04f7..846ee78 100644
--- a/core/res/res/values-mcc310-mnc950-fi/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-fi/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM-kortti ei käyttäjien hallinnassa MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM-kortti estetty MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Puhelin estetty MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-fr-rCA/strings.xml b/core/res/res/values-mcc310-mnc950-fr-rCA/strings.xml
index a310f82..08a3e55 100644
--- a/core/res/res/values-mcc310-mnc950-fr-rCA/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-fr-rCA/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"Carte SIM non configurée, MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"Carte SIM non autorisée, MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Téléphone non autorisé MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-fr/strings.xml b/core/res/res/values-mcc310-mnc950-fr/strings.xml
index 7b0fb2c..a0f6016 100644
--- a/core/res/res/values-mcc310-mnc950-fr/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-fr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"Carte SIM non provisionnée MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"Carte SIM non autorisée MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Téléphone non autorisé MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-gl/strings.xml b/core/res/res/values-mcc310-mnc950-gl/strings.xml
index 55ff461..e771683 100644
--- a/core/res/res/values-mcc310-mnc950-gl/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-gl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"Non se introduciu ningunha tarxeta SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"Non se admite a tarxeta SIM MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Non se admite o teléfono MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-gu/strings.xml b/core/res/res/values-mcc310-mnc950-gu/strings.xml
index a6e1a83..9f4596b 100644
--- a/core/res/res/values-mcc310-mnc950-gu/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-gu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIMને MM#2ની જોગવાઈ નથી"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIMને MM#3 કરવાની મંજૂરી નથી"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"MM#6 ફોનની મંજૂરી નથી"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-hi/strings.xml b/core/res/res/values-mcc310-mnc950-hi/strings.xml
index 41b9bc9..e71aa25 100644
--- a/core/res/res/values-mcc310-mnc950-hi/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-hi/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM काम नहीं कर रहा है MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM की अनुमति नहीं है MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"फ़ोन की इजाज़त नहीं है MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-hr/strings.xml b/core/res/res/values-mcc310-mnc950-hr/strings.xml
index 1c39a09..c7f6b22 100644
--- a/core/res/res/values-mcc310-mnc950-hr/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-hr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"Ne pruža se usluga za SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM nije dopušten MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Telefon nije dopušten MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-hu/strings.xml b/core/res/res/values-mcc310-mnc950-hu/strings.xml
index 6b8ee76..22b5e9b 100644
--- a/core/res/res/values-mcc310-mnc950-hu/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-hu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"Nem engedélyezett SIM-kártya (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"A SIM-kártya nem engedélyezett (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"A telefon nem engedélyezett (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-hy/strings.xml b/core/res/res/values-mcc310-mnc950-hy/strings.xml
index 63dfa46..5136640 100644
--- a/core/res/res/values-mcc310-mnc950-hy/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-hy/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM քարտը նախապատրաստված չէ (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM քարտի օգտագործումն արգելված է (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Հեռախոսի օգտագործումն արգելված է (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-in/strings.xml b/core/res/res/values-mcc310-mnc950-in/strings.xml
index a7c0232..bb9e380 100644
--- a/core/res/res/values-mcc310-mnc950-in/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-in/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM tidak di-provisioning MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM tidak diizinkan MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Ponsel tidak diizinkan MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-is/strings.xml b/core/res/res/values-mcc310-mnc950-is/strings.xml
index ceee15a..d8b847f 100644
--- a/core/res/res/values-mcc310-mnc950-is/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-is/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM-korti ekki úthlutað MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM-kort ekki leyft MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Sími ekki leyfður MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-it/strings.xml b/core/res/res/values-mcc310-mnc950-it/strings.xml
index 21e2a4a..bf6d8bb 100644
--- a/core/res/res/values-mcc310-mnc950-it/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-it/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"Scheda SIM non predisposta MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"Scheda SIM non consentita MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Telefono non consentito MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-iw/strings.xml b/core/res/res/values-mcc310-mnc950-iw/strings.xml
index 041408f..fd0ac8fc 100644
--- a/core/res/res/values-mcc310-mnc950-iw/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-iw/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"‏כרטיס ה-SIM לא הופעל MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"‏כרטיס ה-SIM לא מורשה לשימוש ברשת הסלולרית MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"‏הטלפון לא מורשה MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-ja/strings.xml b/core/res/res/values-mcc310-mnc950-ja/strings.xml
index 97f697e..4224a8a 100644
--- a/core/res/res/values-mcc310-mnc950-ja/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-ja/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM には対応していません(MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM は許可されていません(MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"電話は許可されていません(MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-ka/strings.xml b/core/res/res/values-mcc310-mnc950-ka/strings.xml
index 4d8c8a8..0cbd72c 100644
--- a/core/res/res/values-mcc310-mnc950-ka/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-ka/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM ბარათი უზრუნველყოფილი არ არის (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM ბარათი დაუშვებელია (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"ტელეფონი დაუშვებელია MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-kk/strings.xml b/core/res/res/values-mcc310-mnc950-kk/strings.xml
index 899a9a2..271083a 100644
--- a/core/res/res/values-mcc310-mnc950-kk/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-kk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM картасы қарастырылмаған MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM картасына рұқсат етілмеген MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Телефон пайдалануға болмайды MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-km/strings.xml b/core/res/res/values-mcc310-mnc950-km/strings.xml
index 3c80d9f..d5a98d5 100644
--- a/core/res/res/values-mcc310-mnc950-km/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-km/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"ស៊ីមកាត​មិនត្រូវបានផ្ដល់ជូនទេ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"មិនអនុញ្ញាត​ចំពោះស៊ីមកាតទេ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"មិន​អនុញ្ញាត​ចំពោះ​ទូរសព្ទ​ទេ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-kn/strings.xml b/core/res/res/values-mcc310-mnc950-kn/strings.xml
index 1c7ab20..f15aec8 100644
--- a/core/res/res/values-mcc310-mnc950-kn/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-kn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"MM#2 ಗೆ ಸಿಮ್‌ ಸಿದ್ಧವಾಗಿಲ್ಲ"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"ಸಿಮ್‌ MM#3 ಅನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"ಫೋನ್ MM#6 ಅನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-ko/strings.xml b/core/res/res/values-mcc310-mnc950-ko/strings.xml
index 2419c2a..96c9b62 100644
--- a/core/res/res/values-mcc310-mnc950-ko/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-ko/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM이 프로비저닝되지 않음 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM이 허용되지 않음 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"전화가 허용되지 않음 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-ky/strings.xml b/core/res/res/values-mcc310-mnc950-ky/strings.xml
index 2583338..f8c7313 100644
--- a/core/res/res/values-mcc310-mnc950-ky/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-ky/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM карта таанылган жок (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM картаны колдонууга тыюу салынган (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Телефонду колдонууга тыюу салынган MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-lo/strings.xml b/core/res/res/values-mcc310-mnc950-lo/strings.xml
index b69536f..38f82b4 100644
--- a/core/res/res/values-mcc310-mnc950-lo/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-lo/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM ບໍ່ໄດ້ເປີດໃຊ້ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM ບໍ່ອະນຸຍາດ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ໂທລະສັບ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-lt/strings.xml b/core/res/res/values-mcc310-mnc950-lt/strings.xml
index 8ef0869..4c51da7 100644
--- a/core/res/res/values-mcc310-mnc950-lt/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-lt/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM kortelė neteikiama (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM kortelė neleidžiama (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Telefonas neleidžiamas (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-lv/strings.xml b/core/res/res/values-mcc310-mnc950-lv/strings.xml
index 2a491c0..0ed0ae7 100644
--- a/core/res/res/values-mcc310-mnc950-lv/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-lv/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM karte netiek nodrošināta: MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM karti nav atļauts izmantot: MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Tālruni nav atļauts izmantot: MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-mk/strings.xml b/core/res/res/values-mcc310-mnc950-mk/strings.xml
index a1da44b..375b09a 100644
--- a/core/res/res/values-mcc310-mnc950-mk/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-mk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"Не е обезбедена SIM-картичка, MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"Не е дозволена SIM-картичка, MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Телефонот не е дозволен MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-ml/strings.xml b/core/res/res/values-mcc310-mnc950-ml/strings.xml
index 0079c08..b1defa6 100644
--- a/core/res/res/values-mcc310-mnc950-ml/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-ml/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"സിം MM#2 പ്രൊവിഷൻ ചെയ്‌തിട്ടില്ല"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"സിം MM#3 അനുവദിച്ചിട്ടില്ല"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"ഫോൺ അനുവദനീയമല്ല MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-mn/strings.xml b/core/res/res/values-mcc310-mnc950-mn/strings.xml
index 2d4b5f53..e8ef11c 100644
--- a/core/res/res/values-mcc310-mnc950-mn/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-mn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM-г идэвхжүүлээгүй байна MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM-г зөвшөөрөөгүй байна MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Утсыг зөвшөөрөөгүй MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-mr/strings.xml b/core/res/res/values-mcc310-mnc950-mr/strings.xml
index eca7dca..088d800 100644
--- a/core/res/res/values-mcc310-mnc950-mr/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-mr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM ने MM#2 ची तरतूद केलेली नाही"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM ने MM#3 ला परवानगी दिली नाही"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"फोन MM#6 ला अनुमती देत नाही"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-ms/strings.xml b/core/res/res/values-mcc310-mnc950-ms/strings.xml
index 4f5c781..bb4600d 100644
--- a/core/res/res/values-mcc310-mnc950-ms/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-ms/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM tidak diperuntukkan MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM tidak dibenarkan MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Telefon tidak dibenarkan MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-my/strings.xml b/core/res/res/values-mcc310-mnc950-my/strings.xml
index ecf9f61..ed581ef 100644
--- a/core/res/res/values-mcc310-mnc950-my/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-my/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"ဆင်းမ်ကို ထောက်ပံ့မထားပါ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"ဆင်းမ်ကို ခွင့်မပြုပါ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"ဖုန်းကို ခွင့်မပြုပါ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-nb/strings.xml b/core/res/res/values-mcc310-mnc950-nb/strings.xml
index 907482e..5134e7d 100644
--- a/core/res/res/values-mcc310-mnc950-nb/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-nb/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM-kortet er ikke klargjort, MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM-kortet er ikke tillatt, MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Telefonen er ikke tillatt, MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-ne/strings.xml b/core/res/res/values-mcc310-mnc950-ne/strings.xml
index 380f01c..0b3c815 100644
--- a/core/res/res/values-mcc310-mnc950-ne/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-ne/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM को प्रावधान छैन MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM लाई अनुमति छैन MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"फोनलाई अनुमति छैन MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-nl/strings.xml b/core/res/res/values-mcc310-mnc950-nl/strings.xml
index a01896c..d1e39df 100644
--- a/core/res/res/values-mcc310-mnc950-nl/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-nl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"Simkaart niet geregistreerd MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"Simkaart niet toegestaan MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Telefoon niet toegestaan MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-pa/strings.xml b/core/res/res/values-mcc310-mnc950-pa/strings.xml
index a67b0fb..05ef594 100644
--- a/core/res/res/values-mcc310-mnc950-pa/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-pa/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"ਸਿਮ ਦੀ ਵਿਵਸਥਾ ਨਹੀਂ ਹੈ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"ਸਿਮ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"ਫ਼ੋਨ ਨੂੰ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-pl/strings.xml b/core/res/res/values-mcc310-mnc950-pl/strings.xml
index ce40c22..ab6e8fb 100644
--- a/core/res/res/values-mcc310-mnc950-pl/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-pl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"MM#2 – karta SIM nieobsługiwana"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"MM#3 – niedozwolona karta SIM"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"MM#6 – telefon niedozwolony"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-pt-rBR/strings.xml b/core/res/res/values-mcc310-mnc950-pt-rBR/strings.xml
index 1f89e47..83c84ce 100644
--- a/core/res/res/values-mcc310-mnc950-pt-rBR/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-pt-rBR/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM não aprovisionado MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM não permitido MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Smartphone não permitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-pt-rPT/strings.xml b/core/res/res/values-mcc310-mnc950-pt-rPT/strings.xml
index 1f89e47..7b657fd 100644
--- a/core/res/res/values-mcc310-mnc950-pt-rPT/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-pt-rPT/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM não aprovisionado MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM não permitido MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Telemóvel não permitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-pt/strings.xml b/core/res/res/values-mcc310-mnc950-pt/strings.xml
index 1f89e47..83c84ce 100644
--- a/core/res/res/values-mcc310-mnc950-pt/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-pt/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM não aprovisionado MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM não permitido MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Smartphone não permitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-ro/strings.xml b/core/res/res/values-mcc310-mnc950-ro/strings.xml
index 7fb3f2e..e51800b 100644
--- a/core/res/res/values-mcc310-mnc950-ro/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-ro/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"Cardul SIM nu este activat MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"Cardul SIM nu este permis MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Telefonul nu este permis MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-ru/strings.xml b/core/res/res/values-mcc310-mnc950-ru/strings.xml
index 16deeed..1dbdd7b 100644
--- a/core/res/res/values-mcc310-mnc950-ru/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-ru/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM-карта не активирована (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"Использование SIM-карты запрещено (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Звонки запрещены (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-si/strings.xml b/core/res/res/values-mcc310-mnc950-si/strings.xml
index dd512d9..bb0f22f 100644
--- a/core/res/res/values-mcc310-mnc950-si/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-si/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM MM#2 ප්‍රතිපාදනය නොකරයි"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM MM#3 ඉඩ නොදේ"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"දුරකථනය MM#6 ඉඩ නොදේ"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-sk/strings.xml b/core/res/res/values-mcc310-mnc950-sk/strings.xml
index 6a8e6f0..7bba3ae 100644
--- a/core/res/res/values-mcc310-mnc950-sk/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-sk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM karta nie je k dispozícii – MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM karta je zakázaná – MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Telefón nie je povolený (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-sl/strings.xml b/core/res/res/values-mcc310-mnc950-sl/strings.xml
index 391ee78..cd08650 100644
--- a/core/res/res/values-mcc310-mnc950-sl/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-sl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"Kartica SIM ni omogočena za uporabo MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"Kartica SIM ni dovoljena MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Telefon ni dovoljen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-sq/strings.xml b/core/res/res/values-mcc310-mnc950-sq/strings.xml
index ebc978c..8230755 100644
--- a/core/res/res/values-mcc310-mnc950-sq/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-sq/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"Karta SIM nuk është dhënë MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"Karta SIM nuk lejohet MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Telefoni nuk lejohet MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-sr/strings.xml b/core/res/res/values-mcc310-mnc950-sr/strings.xml
index 4f3f86f..cac39e2 100644
--- a/core/res/res/values-mcc310-mnc950-sr/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-sr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM картица није подешена MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM картица није дозвољена MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Телефон није дозвољен MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-sv/strings.xml b/core/res/res/values-mcc310-mnc950-sv/strings.xml
index 4739f06..7ac957d 100644
--- a/core/res/res/values-mcc310-mnc950-sv/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-sv/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM-kort tillhandahålls inte MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM-kort tillåts inte MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Mobil tillåts inte MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-sw/strings.xml b/core/res/res/values-mcc310-mnc950-sw/strings.xml
index 903b4a5..8967e18 100644
--- a/core/res/res/values-mcc310-mnc950-sw/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-sw/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM haitumiki MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM hairuhusiwi MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Simu hairuhusiwi MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-ta/strings.xml b/core/res/res/values-mcc310-mnc950-ta/strings.xml
index 8838aed7..35a7202 100644
--- a/core/res/res/values-mcc310-mnc950-ta/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-ta/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"சிம் அமைக்கப்படவில்லை MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"சிம் அனுமதிக்கப்படவில்லை MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"ஃபோன் அனுமதிக்கப்படவில்லை MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-te/strings.xml b/core/res/res/values-mcc310-mnc950-te/strings.xml
index dc9625b..4611a72 100644
--- a/core/res/res/values-mcc310-mnc950-te/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-te/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM MM#2ని సక్రియం చేయలేదు"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM MM#3ని అనుమతించలేదు"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"ఫోన్ అనుమతించబడదు MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-th/strings.xml b/core/res/res/values-mcc310-mnc950-th/strings.xml
index 3feb1f6..d8c61dd 100644
--- a/core/res/res/values-mcc310-mnc950-th/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-th/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"ไม่มีการจัดสรรซิม MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"ไม่อนุญาตให้ใช้ซิม MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"ไม่อนุญาตให้ใช้โทรศัพท์ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-tl/strings.xml b/core/res/res/values-mcc310-mnc950-tl/strings.xml
index 55e0bfd..66f686c 100644
--- a/core/res/res/values-mcc310-mnc950-tl/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-tl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"Hindi na-provision ang SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"Hindi pinapahintulutan ang SIM MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Hindi pinapahintulutan ang telepono MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-tr/strings.xml b/core/res/res/values-mcc310-mnc950-tr/strings.xml
index 7a274a4..54e8e7d 100644
--- a/core/res/res/values-mcc310-mnc950-tr/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-tr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM, MM#2\'nin temel hazırlığını yapamadı"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM MM#3\'e izin vermiyor"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Telefona izin verilmiyor MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-uk/strings.xml b/core/res/res/values-mcc310-mnc950-uk/strings.xml
index bf5e6411..be0cd2b 100644
--- a/core/res/res/values-mcc310-mnc950-uk/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-uk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM-карту не надано (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM-карта заборонена (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Телефон заборонено (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-ur/strings.xml b/core/res/res/values-mcc310-mnc950-ur/strings.xml
index 35857cd..7b925c4 100644
--- a/core/res/res/values-mcc310-mnc950-ur/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-ur/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"‏SIM فراہم کردہ نہیں ہے MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"‏SIM کی اجازت نہیں ہے MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"‏فون کی اجازت نہیں ہے MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-uz/strings.xml b/core/res/res/values-mcc310-mnc950-uz/strings.xml
index e31c7b6..99ac738 100644
--- a/core/res/res/values-mcc310-mnc950-uz/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-uz/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM karta ishlatish taqiqlangan (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM karta ishlatish taqiqlangan (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Chaqiruvlar taqiqlangan (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-vi/strings.xml b/core/res/res/values-mcc310-mnc950-vi/strings.xml
index b9360b5..829a4dc 100644
--- a/core/res/res/values-mcc310-mnc950-vi/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-vi/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM không được cấp phép MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM không được phép MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Không cho phép điện thoại MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-zh-rCN/strings.xml b/core/res/res/values-mcc310-mnc950-zh-rCN/strings.xml
index 3b4ba0a..240dd0b 100644
--- a/core/res/res/values-mcc310-mnc950-zh-rCN/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-zh-rCN/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"未配置的 SIM 卡 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"不被允许的 SIM 卡 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"不受允许的手机 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-zh-rHK/strings.xml b/core/res/res/values-mcc310-mnc950-zh-rHK/strings.xml
index 763e498..97a13bc 100644
--- a/core/res/res/values-mcc310-mnc950-zh-rHK/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-zh-rHK/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"未佈建的 SIM 卡 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"不支援的 SIM 卡 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"不允許手機 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-zh-rTW/strings.xml b/core/res/res/values-mcc310-mnc950-zh-rTW/strings.xml
index 763e498..934aea0 100644
--- a/core/res/res/values-mcc310-mnc950-zh-rTW/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-zh-rTW/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"未佈建的 SIM 卡 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"不支援的 SIM 卡 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"不支援的手機 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc950-zu/strings.xml b/core/res/res/values-mcc310-mnc950-zu/strings.xml
index 1c29754..9dc4403 100644
--- a/core/res/res/values-mcc310-mnc950-zu/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-zu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"I-SIM ayinikezelwe MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="2418195136279399212">"I-SIM ayivunyelwe MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="8920048244573695129">"Ifoni ayivunyelwe MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-af/strings.xml b/core/res/res/values-mcc311-mnc180-af/strings.xml
index ead8992..73c9a6c 100644
--- a/core/res/res/values-mcc311-mnc180-af/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-af/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM is nie opgestel nie MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM word nie toegelaat nie MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Foon nie toegelaat nie MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-am/strings.xml b/core/res/res/values-mcc311-mnc180-am/strings.xml
index a7d0d1d..935312e 100644
--- a/core/res/res/values-mcc311-mnc180-am/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-am/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"ሲም አልቀረበም MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"ሲም አይፈቀድም MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"ስልክ አይፈቀድም MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-ar/strings.xml b/core/res/res/values-mcc311-mnc180-ar/strings.xml
index f5412bd..cdb14c5 100644
--- a/core/res/res/values-mcc311-mnc180-ar/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-ar/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"‏لم يتم توفير SIM ‏MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"‏غير مسموح باستخدام SIM ‏MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"‏غير مسموح باستخدام الهاتف MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-az/strings.xml b/core/res/res/values-mcc311-mnc180-az/strings.xml
index c2c06be..7471fca 100644
--- a/core/res/res/values-mcc311-mnc180-az/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-az/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM MM#2 təmin etmir"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM MM#3 dəstəkləmir"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"MM#6 telefonu dəstəklənmir"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-b+sr+Latn/strings.xml b/core/res/res/values-mcc311-mnc180-b+sr+Latn/strings.xml
index e8b35c3..2d0af9e 100644
--- a/core/res/res/values-mcc311-mnc180-b+sr+Latn/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-b+sr+Latn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM kartica nije podešena MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM kartica nije dozvoljena MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Telefon nije dozvoljen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-be/strings.xml b/core/res/res/values-mcc311-mnc180-be/strings.xml
index f2c1069..0b2f7cf 100644
--- a/core/res/res/values-mcc311-mnc180-be/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-be/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM-карты няма MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM-карта не дапускаецца MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Тэлефон не дапускаецца MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-bg/strings.xml b/core/res/res/values-mcc311-mnc180-bg/strings.xml
index faf5a42..542557e 100644
--- a/core/res/res/values-mcc311-mnc180-bg/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-bg/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM картата не е обезпечена MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM картата не е разрешена MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Телефонът не е разрешен MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-bn/strings.xml b/core/res/res/values-mcc311-mnc180-bn/strings.xml
index 80efd0f..59d1624 100644
--- a/core/res/res/values-mcc311-mnc180-bn/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-bn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"সিমের জন্য প্রস্তুত নয় MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"সিমের অনুমতি নেই MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"ফোন অনুমোদিত নয় MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-bs/strings.xml b/core/res/res/values-mcc311-mnc180-bs/strings.xml
index 7c3e5b3..409df22 100644
--- a/core/res/res/values-mcc311-mnc180-bs/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-bs/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM kartica nije dodijeljena MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM kartica nije dozvoljena MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Telefon nije dozvoljen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-ca/strings.xml b/core/res/res/values-mcc311-mnc180-ca/strings.xml
index e33a901..505f396 100644
--- a/core/res/res/values-mcc311-mnc180-ca/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-ca/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"La SIM no està proporcionada a MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"La SIM no és compatible a MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Telèfon no compatible MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-cs/strings.xml b/core/res/res/values-mcc311-mnc180-cs/strings.xml
index 653a55a..29c8fdf 100644
--- a/core/res/res/values-mcc311-mnc180-cs/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-cs/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM karta není poskytována (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM karta není povolena (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Telefon není povolen (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-da/strings.xml b/core/res/res/values-mcc311-mnc180-da/strings.xml
index 04c89a5..6fadac1 100644
--- a/core/res/res/values-mcc311-mnc180-da/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-da/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM-kort leveres ikke MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM-kort er ikke tilladt MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Telefonen har ikke adgangstilladelse MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-de/strings.xml b/core/res/res/values-mcc311-mnc180-de/strings.xml
index 8fef081..714eac9 100644
--- a/core/res/res/values-mcc311-mnc180-de/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-de/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM-Karte nicht eingerichtet MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM-Karte nicht zulässig MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Smartphone nicht zulässig MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-el/strings.xml b/core/res/res/values-mcc311-mnc180-el/strings.xml
index 795f48f..2e29b12 100644
--- a/core/res/res/values-mcc311-mnc180-el/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-el/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"Δεν παρέχεται κάρτα SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"Η κάρτα SIM δεν επιτρέπεται MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Το τηλέφωνο δεν επιτρέπεται MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-en-rAU/strings.xml b/core/res/res/values-mcc311-mnc180-en-rAU/strings.xml
index 9c972bc..b284371 100644
--- a/core/res/res/values-mcc311-mnc180-en-rAU/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-en-rAU/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-en-rCA/strings.xml b/core/res/res/values-mcc311-mnc180-en-rCA/strings.xml
index 9c972bc..b284371 100644
--- a/core/res/res/values-mcc311-mnc180-en-rCA/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-en-rCA/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-en-rGB/strings.xml b/core/res/res/values-mcc311-mnc180-en-rGB/strings.xml
index 9c972bc..b284371 100644
--- a/core/res/res/values-mcc311-mnc180-en-rGB/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-en-rGB/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-en-rIN/strings.xml b/core/res/res/values-mcc311-mnc180-en-rIN/strings.xml
index 9c972bc..b284371 100644
--- a/core/res/res/values-mcc311-mnc180-en-rIN/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-en-rIN/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM not provisioned MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM not allowed MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Phone not allowed MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-en-rXC/strings.xml b/core/res/res/values-mcc311-mnc180-en-rXC/strings.xml
index f1a6cc7..53832df 100644
--- a/core/res/res/values-mcc311-mnc180-en-rXC/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-en-rXC/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‏‎‎‏‎‏‏‏‎‎‎‏‎‎‎‎‏‏‏‎‏‏‏‎‎‎‎‏‏‎‎‏‎‎‎‎‏‎‎‎‎‎‎‎‎‎‎‎SIM not provisioned MM#2‎‏‎‎‏‎"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‎‏‎‏‏‎‏‏‎‏‎‎‎‎‏‎‏‎‎‏‏‎‎‏‏‎‏‏‏‎‏‏‎‎‏‎‏‎‏‏‏‏‎‎‏‏‎‎‎‏‎‏‎‎‎‏‎SIM not allowed MM#3‎‏‎‎‏‎"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‏‎‎‎‎‎‎‏‏‎‏‎‏‏‎‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‎‏‏‎‎‏‏‎‎‎‎‎‎‎Phone not allowed MM#6‎‏‎‎‏‎"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-es-rUS/strings.xml b/core/res/res/values-mcc311-mnc180-es-rUS/strings.xml
index 694cd76..cb06a6e 100644
--- a/core/res/res/values-mcc311-mnc180-es-rUS/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-es-rUS/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM no provista MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM no permitida MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Teléfono no admitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-es/strings.xml b/core/res/res/values-mcc311-mnc180-es/strings.xml
index 605e314..6368483 100644
--- a/core/res/res/values-mcc311-mnc180-es/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-es/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM no proporcionada (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM no admitida (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Teléfono no admitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-et/strings.xml b/core/res/res/values-mcc311-mnc180-et/strings.xml
index 39dfa1b..142824f 100644
--- a/core/res/res/values-mcc311-mnc180-et/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-et/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM-kaart on ette valmistamata MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM-kaart pole lubatud MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Telefon pole lubatud MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-eu/strings.xml b/core/res/res/values-mcc311-mnc180-eu/strings.xml
index 84732c9..4bb3cd3 100644
--- a/core/res/res/values-mcc311-mnc180-eu/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-eu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"Ez dago SIM txartelik MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"Ez da onartzen SIM txartela MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Telefonoa ez da onartzen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-fa/strings.xml b/core/res/res/values-mcc311-mnc180-fa/strings.xml
index 902d821..3354859 100644
--- a/core/res/res/values-mcc311-mnc180-fa/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-fa/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"‏سیم‌کارت مجوز لازم را ندارد MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"‏سیم‌کارت مجاز نیست MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"‏تلفن مجاز نیست MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-fi/strings.xml b/core/res/res/values-mcc311-mnc180-fi/strings.xml
index 004e645..c66d593 100644
--- a/core/res/res/values-mcc311-mnc180-fi/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-fi/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM-kortti ei käyttäjien hallinnassa MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM-kortti estetty MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Puhelin estetty MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-fr-rCA/strings.xml b/core/res/res/values-mcc311-mnc180-fr-rCA/strings.xml
index c0aaf99..b17c342 100644
--- a/core/res/res/values-mcc311-mnc180-fr-rCA/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-fr-rCA/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"Carte SIM non configurée, MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"Carte SIM non autorisée, MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Téléphone non autorisé MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-fr/strings.xml b/core/res/res/values-mcc311-mnc180-fr/strings.xml
index b9adf79..0cc7264 100644
--- a/core/res/res/values-mcc311-mnc180-fr/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-fr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"Carte SIM non provisionnée MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"Carte SIM non autorisée MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Téléphone non autorisé MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-gl/strings.xml b/core/res/res/values-mcc311-mnc180-gl/strings.xml
index cb59c97..8acb5c1 100644
--- a/core/res/res/values-mcc311-mnc180-gl/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-gl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"Non se introduciu ningunha tarxeta SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"Non se admite a tarxeta SIM MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Non se admite o teléfono MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-gu/strings.xml b/core/res/res/values-mcc311-mnc180-gu/strings.xml
index 556416e..529491e 100644
--- a/core/res/res/values-mcc311-mnc180-gu/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-gu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIMને MM#2ની જોગવાઈ નથી"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIMને MM#3 કરવાની મંજૂરી નથી"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"MM#6 ફોનની મંજૂરી નથી"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-hi/strings.xml b/core/res/res/values-mcc311-mnc180-hi/strings.xml
index da1f9e1..69303e7 100644
--- a/core/res/res/values-mcc311-mnc180-hi/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-hi/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM काम नहीं कर रहा है MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM की अनुमति नहीं है MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"फ़ोन की इजाज़त नहीं है MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-hr/strings.xml b/core/res/res/values-mcc311-mnc180-hr/strings.xml
index a1f0b0e..84d36b7 100644
--- a/core/res/res/values-mcc311-mnc180-hr/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-hr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"Ne pruža se usluga za SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM nije dopušten MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Telefon nije dopušten MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-hu/strings.xml b/core/res/res/values-mcc311-mnc180-hu/strings.xml
index 917c2ee9..5d3507d 100644
--- a/core/res/res/values-mcc311-mnc180-hu/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-hu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"Nem engedélyezett SIM-kártya (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"A SIM-kártya nem engedélyezett (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"A telefon nem engedélyezett (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-hy/strings.xml b/core/res/res/values-mcc311-mnc180-hy/strings.xml
index a832d02..aeaaeb9 100644
--- a/core/res/res/values-mcc311-mnc180-hy/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-hy/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM քարտը նախապատրաստված չէ (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM քարտի օգտագործումն արգելված է (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Հեռախոսի օգտագործումն արգելված է (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-in/strings.xml b/core/res/res/values-mcc311-mnc180-in/strings.xml
index bdc8d20..8a96e4c 100644
--- a/core/res/res/values-mcc311-mnc180-in/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-in/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM tidak di-provisioning MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM tidak diizinkan MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Ponsel tidak diizinkan MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-is/strings.xml b/core/res/res/values-mcc311-mnc180-is/strings.xml
index 35966f7..bd6223b 100644
--- a/core/res/res/values-mcc311-mnc180-is/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-is/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM-korti ekki úthlutað MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM-kort ekki leyft MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Sími ekki leyfður MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-it/strings.xml b/core/res/res/values-mcc311-mnc180-it/strings.xml
index 25f301b..7757a25 100644
--- a/core/res/res/values-mcc311-mnc180-it/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-it/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"Scheda SIM non predisposta MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"Scheda SIM non consentita MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Telefono non consentito MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-iw/strings.xml b/core/res/res/values-mcc311-mnc180-iw/strings.xml
index c6bdc14..dbb180b 100644
--- a/core/res/res/values-mcc311-mnc180-iw/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-iw/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"‏כרטיס ה-SIM לא הופעל MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"‏כרטיס ה-SIM לא מורשה לשימוש ברשת הסלולרית MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"‏הטלפון לא מורשה MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-ja/strings.xml b/core/res/res/values-mcc311-mnc180-ja/strings.xml
index 6d30808..3defd2e 100644
--- a/core/res/res/values-mcc311-mnc180-ja/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-ja/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM には対応していません(MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM は許可されていません(MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"電話は許可されていません(MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-ka/strings.xml b/core/res/res/values-mcc311-mnc180-ka/strings.xml
index b86ce07..2fa76c4 100644
--- a/core/res/res/values-mcc311-mnc180-ka/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-ka/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM ბარათი უზრუნველყოფილი არ არის (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM ბარათი დაუშვებელია (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"ტელეფონი დაუშვებელია MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-kk/strings.xml b/core/res/res/values-mcc311-mnc180-kk/strings.xml
index 539fbe4..91fd767 100644
--- a/core/res/res/values-mcc311-mnc180-kk/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-kk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM картасы қарастырылмаған MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM картасына рұқсат етілмеген MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Телефон пайдалануға болмайды MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-km/strings.xml b/core/res/res/values-mcc311-mnc180-km/strings.xml
index 970532e..c2f29a5 100644
--- a/core/res/res/values-mcc311-mnc180-km/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-km/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"ស៊ីមកាត​មិនត្រូវបានផ្ដល់ជូនទេ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"មិនអនុញ្ញាត​ចំពោះស៊ីមកាតទេ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"មិន​អនុញ្ញាត​ចំពោះ​ទូរសព្ទ​ទេ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-kn/strings.xml b/core/res/res/values-mcc311-mnc180-kn/strings.xml
index 53a0419..08568fa 100644
--- a/core/res/res/values-mcc311-mnc180-kn/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-kn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"MM#2 ಗೆ ಸಿಮ್‌ ಸಿದ್ಧವಾಗಿಲ್ಲ"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"ಸಿಮ್‌ MM#3 ಅನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"ಫೋನ್ MM#6 ಅನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-ko/strings.xml b/core/res/res/values-mcc311-mnc180-ko/strings.xml
index 01d6fec..b9bd3c8 100644
--- a/core/res/res/values-mcc311-mnc180-ko/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-ko/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM이 프로비저닝되지 않음 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM이 허용되지 않음 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"전화가 허용되지 않음 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-ky/strings.xml b/core/res/res/values-mcc311-mnc180-ky/strings.xml
index 7339e40..305d81e 100644
--- a/core/res/res/values-mcc311-mnc180-ky/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-ky/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM карта таанылган жок (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM картаны колдонууга тыюу салынган (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Телефонду колдонууга тыюу салынган MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-lo/strings.xml b/core/res/res/values-mcc311-mnc180-lo/strings.xml
index 5cbd1c8..f662b44 100644
--- a/core/res/res/values-mcc311-mnc180-lo/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-lo/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM ບໍ່ໄດ້ເປີດໃຊ້ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM ບໍ່ອະນຸຍາດ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ໂທລະສັບ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-lt/strings.xml b/core/res/res/values-mcc311-mnc180-lt/strings.xml
index 40a7e4a..fbffbae 100644
--- a/core/res/res/values-mcc311-mnc180-lt/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-lt/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM kortelė neteikiama (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM kortelė neleidžiama (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Telefonas neleidžiamas (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-lv/strings.xml b/core/res/res/values-mcc311-mnc180-lv/strings.xml
index 74b6818..747b5ea 100644
--- a/core/res/res/values-mcc311-mnc180-lv/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-lv/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM karte netiek nodrošināta: MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM karti nav atļauts izmantot: MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Tālruni nav atļauts izmantot: MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-mk/strings.xml b/core/res/res/values-mcc311-mnc180-mk/strings.xml
index 7db80fa..9077dc2 100644
--- a/core/res/res/values-mcc311-mnc180-mk/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-mk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"Не е обезбедена SIM-картичка, MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"Не е дозволена SIM-картичка, MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Телефонот не е дозволен MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-ml/strings.xml b/core/res/res/values-mcc311-mnc180-ml/strings.xml
index 7cdd126..fc23728 100644
--- a/core/res/res/values-mcc311-mnc180-ml/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-ml/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"സിം MM#2 പ്രൊവിഷൻ ചെയ്‌തിട്ടില്ല"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"സിം MM#3 അനുവദിച്ചിട്ടില്ല"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"ഫോൺ അനുവദനീയമല്ല MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-mn/strings.xml b/core/res/res/values-mcc311-mnc180-mn/strings.xml
index 1be055c..4960154 100644
--- a/core/res/res/values-mcc311-mnc180-mn/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-mn/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM-г идэвхжүүлээгүй байна MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM-г зөвшөөрөөгүй байна MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Утсыг зөвшөөрөөгүй MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-mr/strings.xml b/core/res/res/values-mcc311-mnc180-mr/strings.xml
index f8e08ae..f6886fe 100644
--- a/core/res/res/values-mcc311-mnc180-mr/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-mr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM ने MM#2 ची तरतूद केलेली नाही"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM ने MM#3 ला परवानगी दिली नाही"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"फोन MM#6 ला अनुमती देत नाही"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-ms/strings.xml b/core/res/res/values-mcc311-mnc180-ms/strings.xml
index 305a10d..222d346 100644
--- a/core/res/res/values-mcc311-mnc180-ms/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-ms/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM tidak diperuntukkan MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM tidak dibenarkan MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Telefon tidak dibenarkan MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-my/strings.xml b/core/res/res/values-mcc311-mnc180-my/strings.xml
index 306c0dd..d68c8ba 100644
--- a/core/res/res/values-mcc311-mnc180-my/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-my/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"ဆင်းမ်ကို ထောက်ပံ့မထားပါ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"ဆင်းမ်ကို ခွင့်မပြုပါ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"ဖုန်းကို ခွင့်မပြုပါ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-nb/strings.xml b/core/res/res/values-mcc311-mnc180-nb/strings.xml
index e1296f4..d2c4758 100644
--- a/core/res/res/values-mcc311-mnc180-nb/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-nb/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM-kortet er ikke klargjort, MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM-kortet er ikke tillatt, MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Telefonen er ikke tillatt, MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-ne/strings.xml b/core/res/res/values-mcc311-mnc180-ne/strings.xml
index 6177a83..f98b5b5 100644
--- a/core/res/res/values-mcc311-mnc180-ne/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-ne/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM को प्रावधान छैन MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM लाई अनुमति छैन MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"फोनलाई अनुमति छैन MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-nl/strings.xml b/core/res/res/values-mcc311-mnc180-nl/strings.xml
index 3f12e64..fbfd787 100644
--- a/core/res/res/values-mcc311-mnc180-nl/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-nl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"Simkaart niet geregistreerd MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"Simkaart niet toegestaan MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Telefoon niet toegestaan MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-pa/strings.xml b/core/res/res/values-mcc311-mnc180-pa/strings.xml
index 32f6a7e..3e69e8b 100644
--- a/core/res/res/values-mcc311-mnc180-pa/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-pa/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"ਸਿਮ ਦੀ ਵਿਵਸਥਾ ਨਹੀਂ ਹੈ MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"ਸਿਮ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"ਫ਼ੋਨ ਨੂੰ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-pl/strings.xml b/core/res/res/values-mcc311-mnc180-pl/strings.xml
index 0744491..296000e3 100644
--- a/core/res/res/values-mcc311-mnc180-pl/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-pl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"MM#2 – karta SIM nieobsługiwana"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"MM#3 – niedozwolona karta SIM"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"MM#6 – telefon niedozwolony"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-pt-rBR/strings.xml b/core/res/res/values-mcc311-mnc180-pt-rBR/strings.xml
index c4d2240..637a91c 100644
--- a/core/res/res/values-mcc311-mnc180-pt-rBR/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-pt-rBR/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM não aprovisionado MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM não permitido MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Smartphone não permitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-pt-rPT/strings.xml b/core/res/res/values-mcc311-mnc180-pt-rPT/strings.xml
index c4d2240..7938a5f 100644
--- a/core/res/res/values-mcc311-mnc180-pt-rPT/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-pt-rPT/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM não aprovisionado MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM não permitido MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Telemóvel não permitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-pt/strings.xml b/core/res/res/values-mcc311-mnc180-pt/strings.xml
index c4d2240..637a91c 100644
--- a/core/res/res/values-mcc311-mnc180-pt/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-pt/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM não aprovisionado MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM não permitido MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Smartphone não permitido MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-ro/strings.xml b/core/res/res/values-mcc311-mnc180-ro/strings.xml
index 68cab29..c5126e7 100644
--- a/core/res/res/values-mcc311-mnc180-ro/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-ro/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"Cardul SIM nu este activat MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"Cardul SIM nu este permis MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Telefonul nu este permis MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-ru/strings.xml b/core/res/res/values-mcc311-mnc180-ru/strings.xml
index 90a3a09..a6f6785 100644
--- a/core/res/res/values-mcc311-mnc180-ru/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-ru/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM-карта не активирована (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"Использование SIM-карты запрещено (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Звонки запрещены (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-si/strings.xml b/core/res/res/values-mcc311-mnc180-si/strings.xml
index 1907d3e..b9ef425 100644
--- a/core/res/res/values-mcc311-mnc180-si/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-si/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM MM#2 ප්‍රතිපාදනය නොකරයි"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM MM#3 ඉඩ නොදේ"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"දුරකථනය MM#6 ඉඩ නොදේ"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-sk/strings.xml b/core/res/res/values-mcc311-mnc180-sk/strings.xml
index a456431..ecd9222 100644
--- a/core/res/res/values-mcc311-mnc180-sk/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-sk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM karta nie je k dispozícii – MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM karta je zakázaná – MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Telefón nie je povolený (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-sl/strings.xml b/core/res/res/values-mcc311-mnc180-sl/strings.xml
index 454a1cd..33d9621 100644
--- a/core/res/res/values-mcc311-mnc180-sl/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-sl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"Kartica SIM ni omogočena za uporabo MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"Kartica SIM ni dovoljena MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Telefon ni dovoljen MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-sq/strings.xml b/core/res/res/values-mcc311-mnc180-sq/strings.xml
index 23da1a3..b5b28fa 100644
--- a/core/res/res/values-mcc311-mnc180-sq/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-sq/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"Karta SIM nuk është dhënë MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"Karta SIM nuk lejohet MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Telefoni nuk lejohet MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-sr/strings.xml b/core/res/res/values-mcc311-mnc180-sr/strings.xml
index 182a7bc..e8b6017 100644
--- a/core/res/res/values-mcc311-mnc180-sr/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-sr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM картица није подешена MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM картица није дозвољена MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Телефон није дозвољен MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-sv/strings.xml b/core/res/res/values-mcc311-mnc180-sv/strings.xml
index fee7a1f..9ca48e0c 100644
--- a/core/res/res/values-mcc311-mnc180-sv/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-sv/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM-kort tillhandahålls inte MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM-kort tillåts inte MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Mobil tillåts inte MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-sw/strings.xml b/core/res/res/values-mcc311-mnc180-sw/strings.xml
index e49b3d1..5b76485 100644
--- a/core/res/res/values-mcc311-mnc180-sw/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-sw/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM haitumiki MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM hairuhusiwi MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Simu hairuhusiwi MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-ta/strings.xml b/core/res/res/values-mcc311-mnc180-ta/strings.xml
index 6c11c4f..9242b4d 100644
--- a/core/res/res/values-mcc311-mnc180-ta/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-ta/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"சிம் அமைக்கப்படவில்லை MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"சிம் அனுமதிக்கப்படவில்லை MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"ஃபோன் அனுமதிக்கப்படவில்லை MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-te/strings.xml b/core/res/res/values-mcc311-mnc180-te/strings.xml
index 5bb9f97..90fe4ca 100644
--- a/core/res/res/values-mcc311-mnc180-te/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-te/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM MM#2ని సక్రియం చేయలేదు"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM MM#3ని అనుమతించలేదు"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"ఫోన్ అనుమతించబడదు MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-th/strings.xml b/core/res/res/values-mcc311-mnc180-th/strings.xml
index be4b08e..d587bcd 100644
--- a/core/res/res/values-mcc311-mnc180-th/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-th/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"ไม่มีการจัดสรรซิม MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"ไม่อนุญาตให้ใช้ซิม MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"ไม่อนุญาตให้ใช้โทรศัพท์ MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-tl/strings.xml b/core/res/res/values-mcc311-mnc180-tl/strings.xml
index 6aacf16..963db42 100644
--- a/core/res/res/values-mcc311-mnc180-tl/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-tl/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"Hindi na-provision ang SIM MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"Hindi pinapahintulutan ang SIM MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Hindi pinapahintulutan ang telepono MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-tr/strings.xml b/core/res/res/values-mcc311-mnc180-tr/strings.xml
index cf4fd77..28280f0 100644
--- a/core/res/res/values-mcc311-mnc180-tr/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-tr/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM, MM#2\'nin temel hazırlığını yapamadı"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM MM#3\'e izin vermiyor"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Telefona izin verilmiyor MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-uk/strings.xml b/core/res/res/values-mcc311-mnc180-uk/strings.xml
index fae40ac..00b22d9 100644
--- a/core/res/res/values-mcc311-mnc180-uk/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-uk/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM-карту не надано (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM-карта заборонена (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Телефон заборонено (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-ur/strings.xml b/core/res/res/values-mcc311-mnc180-ur/strings.xml
index ebceb5e..a9685c4 100644
--- a/core/res/res/values-mcc311-mnc180-ur/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-ur/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"‏SIM فراہم کردہ نہیں ہے MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"‏SIM کی اجازت نہیں ہے MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"‏فون کی اجازت نہیں ہے MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-uz/strings.xml b/core/res/res/values-mcc311-mnc180-uz/strings.xml
index ebcdd3b..c6f9b37 100644
--- a/core/res/res/values-mcc311-mnc180-uz/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-uz/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM karta ishlatish taqiqlangan (MM#2)"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM karta ishlatish taqiqlangan (MM#3)"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Chaqiruvlar taqiqlangan (MM#6)"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-vi/strings.xml b/core/res/res/values-mcc311-mnc180-vi/strings.xml
index 0d7ff96..b5a6567 100644
--- a/core/res/res/values-mcc311-mnc180-vi/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-vi/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM không được cấp phép MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM không được phép MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Không cho phép điện thoại MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-zh-rCN/strings.xml b/core/res/res/values-mcc311-mnc180-zh-rCN/strings.xml
index d8ff182..cd27edf 100644
--- a/core/res/res/values-mcc311-mnc180-zh-rCN/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-zh-rCN/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"未配置的 SIM 卡 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"不被允许的 SIM 卡 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"不受允许的手机 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-zh-rHK/strings.xml b/core/res/res/values-mcc311-mnc180-zh-rHK/strings.xml
index 14332bf..9f2f8b9 100644
--- a/core/res/res/values-mcc311-mnc180-zh-rHK/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-zh-rHK/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"未佈建的 SIM 卡 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM 卡不允許 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"不允許手機 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-zh-rTW/strings.xml b/core/res/res/values-mcc311-mnc180-zh-rTW/strings.xml
index 775a70b..9336296 100644
--- a/core/res/res/values-mcc311-mnc180-zh-rTW/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-zh-rTW/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"未佈建的 SIM 卡 MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"不支援的 SIM 卡 MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"不支援的手機 MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc180-zu/strings.xml b/core/res/res/values-mcc311-mnc180-zu/strings.xml
index a66760f..5708a22 100644
--- a/core/res/res/values-mcc311-mnc180-zu/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-zu/strings.xml
@@ -22,4 +22,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"I-SIM ayinikezelwe MM#2"</string>
     <string name="mmcc_illegal_ms" msgid="97745044956236881">"I-SIM ayivunyelwe MM#3"</string>
+    <string name="mmcc_illegal_me" msgid="5766888847785331904">"Ifoni ayivunyelwe MM#6"</string>
 </resources>
diff --git a/core/res/res/values-mcc312-mnc670-af/strings.xml b/core/res/res/values-mcc312-mnc670-af/strings.xml
new file mode 100644
index 0000000..8884326
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-af/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Foon nie toegelaat nie MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-am/strings.xml b/core/res/res/values-mcc312-mnc670-am/strings.xml
new file mode 100644
index 0000000..26c082b
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-am/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"ስልክ አይፈቀድም MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-ar/strings.xml b/core/res/res/values-mcc312-mnc670-ar/strings.xml
new file mode 100644
index 0000000..133e2b0
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-ar/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"‏غير مسموح باستخدام الهاتف MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-az/strings.xml b/core/res/res/values-mcc312-mnc670-az/strings.xml
new file mode 100644
index 0000000..80a1926
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-az/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"MM#6 telefonu dəstəklənmir"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-b+sr+Latn/strings.xml b/core/res/res/values-mcc312-mnc670-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..47b219e
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-b+sr+Latn/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Telefon nije dozvoljen MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-be/strings.xml b/core/res/res/values-mcc312-mnc670-be/strings.xml
new file mode 100644
index 0000000..ad5d190
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-be/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Тэлефон не дапускаецца MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-bg/strings.xml b/core/res/res/values-mcc312-mnc670-bg/strings.xml
new file mode 100644
index 0000000..98a60c5
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-bg/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Телефонът не е разрешен MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-bn/strings.xml b/core/res/res/values-mcc312-mnc670-bn/strings.xml
new file mode 100644
index 0000000..6b5a1d0
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-bn/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"ফোন অনুমোদিত নয় MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-bs/strings.xml b/core/res/res/values-mcc312-mnc670-bs/strings.xml
new file mode 100644
index 0000000..47b219e
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-bs/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Telefon nije dozvoljen MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-ca/strings.xml b/core/res/res/values-mcc312-mnc670-ca/strings.xml
new file mode 100644
index 0000000..adaa2ba
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-ca/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Telèfon no compatible MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-cs/strings.xml b/core/res/res/values-mcc312-mnc670-cs/strings.xml
new file mode 100644
index 0000000..b88b619
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-cs/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Telefon není povolen (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-da/strings.xml b/core/res/res/values-mcc312-mnc670-da/strings.xml
new file mode 100644
index 0000000..50fdbd4
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-da/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Telefonen har ikke adgangstilladelse MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-de/strings.xml b/core/res/res/values-mcc312-mnc670-de/strings.xml
new file mode 100644
index 0000000..18b33e5
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-de/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Smartphone nicht zulässig MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-el/strings.xml b/core/res/res/values-mcc312-mnc670-el/strings.xml
new file mode 100644
index 0000000..22ea1db
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-el/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Το τηλέφωνο δεν επιτρέπεται MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-en-rAU/strings.xml b/core/res/res/values-mcc312-mnc670-en-rAU/strings.xml
new file mode 100644
index 0000000..3eb880a
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-en-rAU/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Phone not allowed MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-en-rCA/strings.xml b/core/res/res/values-mcc312-mnc670-en-rCA/strings.xml
new file mode 100644
index 0000000..3eb880a
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-en-rCA/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Phone not allowed MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-en-rGB/strings.xml b/core/res/res/values-mcc312-mnc670-en-rGB/strings.xml
new file mode 100644
index 0000000..3eb880a
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-en-rGB/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Phone not allowed MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-en-rIN/strings.xml b/core/res/res/values-mcc312-mnc670-en-rIN/strings.xml
new file mode 100644
index 0000000..3eb880a
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-en-rIN/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Phone not allowed MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-en-rXC/strings.xml b/core/res/res/values-mcc312-mnc670-en-rXC/strings.xml
new file mode 100644
index 0000000..be68f41
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-en-rXC/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‎‎‏‎‎‏‏‏‏‎‎‎‏‎‎‏‎‏‏‎‎‏‏‏‏‎‏‎‏‏‎‎‏‏‎‏‎‏‏‎‎‏‏‏‎‏‎‏‏‎‎‏‎‎Phone not allowed MM#6‎‏‎‎‏‎"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-es-rUS/strings.xml b/core/res/res/values-mcc312-mnc670-es-rUS/strings.xml
new file mode 100644
index 0000000..89b28f5
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-es-rUS/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Teléfono no admitido MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-es/strings.xml b/core/res/res/values-mcc312-mnc670-es/strings.xml
new file mode 100644
index 0000000..89b28f5
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-es/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Teléfono no admitido MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-et/strings.xml b/core/res/res/values-mcc312-mnc670-et/strings.xml
new file mode 100644
index 0000000..1ed4b41
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-et/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Telefon pole lubatud MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-eu/strings.xml b/core/res/res/values-mcc312-mnc670-eu/strings.xml
new file mode 100644
index 0000000..8f0daba
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-eu/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Telefonoa ez da onartzen MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-fa/strings.xml b/core/res/res/values-mcc312-mnc670-fa/strings.xml
new file mode 100644
index 0000000..bd87bdf
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-fa/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"‏تلفن مجاز نیست MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-fi/strings.xml b/core/res/res/values-mcc312-mnc670-fi/strings.xml
new file mode 100644
index 0000000..5ec33a3
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-fi/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Puhelin estetty MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-fr-rCA/strings.xml b/core/res/res/values-mcc312-mnc670-fr-rCA/strings.xml
new file mode 100644
index 0000000..2110dda
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-fr-rCA/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Téléphone non autorisé MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-fr/strings.xml b/core/res/res/values-mcc312-mnc670-fr/strings.xml
new file mode 100644
index 0000000..2110dda
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-fr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Téléphone non autorisé MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-gl/strings.xml b/core/res/res/values-mcc312-mnc670-gl/strings.xml
new file mode 100644
index 0000000..dc66c1d
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-gl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Non se admite o teléfono MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-gu/strings.xml b/core/res/res/values-mcc312-mnc670-gu/strings.xml
new file mode 100644
index 0000000..bc0db0b
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-gu/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"MM#6 ફોનની મંજૂરી નથી"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-hi/strings.xml b/core/res/res/values-mcc312-mnc670-hi/strings.xml
new file mode 100644
index 0000000..1db4db2
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-hi/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"फ़ोन की इजाज़त नहीं है MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-hr/strings.xml b/core/res/res/values-mcc312-mnc670-hr/strings.xml
new file mode 100644
index 0000000..e3b49c9
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-hr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Telefon nije dopušten MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-hu/strings.xml b/core/res/res/values-mcc312-mnc670-hu/strings.xml
new file mode 100644
index 0000000..85b947c
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-hu/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"A telefon nem engedélyezett (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-hy/strings.xml b/core/res/res/values-mcc312-mnc670-hy/strings.xml
new file mode 100644
index 0000000..bc39d50
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-hy/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Հեռախոսի օգտագործումն արգելված է (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-in/strings.xml b/core/res/res/values-mcc312-mnc670-in/strings.xml
new file mode 100644
index 0000000..0f526dd
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-in/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Ponsel tidak diizinkan MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-is/strings.xml b/core/res/res/values-mcc312-mnc670-is/strings.xml
new file mode 100644
index 0000000..cad2282
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-is/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Sími ekki leyfður MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-it/strings.xml b/core/res/res/values-mcc312-mnc670-it/strings.xml
new file mode 100644
index 0000000..1763bdc
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-it/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Telefono non consentito MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-iw/strings.xml b/core/res/res/values-mcc312-mnc670-iw/strings.xml
new file mode 100644
index 0000000..a042e10
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-iw/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"‏הטלפון לא מורשה MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-ja/strings.xml b/core/res/res/values-mcc312-mnc670-ja/strings.xml
new file mode 100644
index 0000000..c5de3af
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-ja/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"電話は許可されていません(MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-ka/strings.xml b/core/res/res/values-mcc312-mnc670-ka/strings.xml
new file mode 100644
index 0000000..a2c7b8a
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-ka/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"ტელეფონი დაუშვებელია MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-kk/strings.xml b/core/res/res/values-mcc312-mnc670-kk/strings.xml
new file mode 100644
index 0000000..1ac2314
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-kk/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Телефон пайдалануға болмайды MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-km/strings.xml b/core/res/res/values-mcc312-mnc670-km/strings.xml
new file mode 100644
index 0000000..8786411
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-km/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"មិន​អនុញ្ញាត​ចំពោះ​ទូរសព្ទ​ទេ MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-kn/strings.xml b/core/res/res/values-mcc312-mnc670-kn/strings.xml
new file mode 100644
index 0000000..581fe17
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-kn/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"ಫೋನ್ MM#6 ಅನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-ko/strings.xml b/core/res/res/values-mcc312-mnc670-ko/strings.xml
new file mode 100644
index 0000000..fcd98f9
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-ko/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"전화가 허용되지 않음 MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-ky/strings.xml b/core/res/res/values-mcc312-mnc670-ky/strings.xml
new file mode 100644
index 0000000..ed830f6
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-ky/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Телефонду колдонууга тыюу салынган MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-lo/strings.xml b/core/res/res/values-mcc312-mnc670-lo/strings.xml
new file mode 100644
index 0000000..04bb1c9
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-lo/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ໂທລະສັບ MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-lt/strings.xml b/core/res/res/values-mcc312-mnc670-lt/strings.xml
new file mode 100644
index 0000000..c416a9a
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-lt/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Telefonas neleidžiamas (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-lv/strings.xml b/core/res/res/values-mcc312-mnc670-lv/strings.xml
new file mode 100644
index 0000000..dfed609
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-lv/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Tālruni nav atļauts izmantot: MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-mk/strings.xml b/core/res/res/values-mcc312-mnc670-mk/strings.xml
new file mode 100644
index 0000000..0bf51cc
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-mk/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Телефонот не е дозволен MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-ml/strings.xml b/core/res/res/values-mcc312-mnc670-ml/strings.xml
new file mode 100644
index 0000000..78dc1ec
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-ml/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"ഫോൺ അനുവദനീയമല്ല MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-mn/strings.xml b/core/res/res/values-mcc312-mnc670-mn/strings.xml
new file mode 100644
index 0000000..682cf86
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-mn/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Утсыг зөвшөөрөөгүй MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-mr/strings.xml b/core/res/res/values-mcc312-mnc670-mr/strings.xml
new file mode 100644
index 0000000..b9dd523
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-mr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"फोन MM#6 ला अनुमती देत नाही"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-ms/strings.xml b/core/res/res/values-mcc312-mnc670-ms/strings.xml
new file mode 100644
index 0000000..3e807a0
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-ms/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Telefon tidak dibenarkan MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-my/strings.xml b/core/res/res/values-mcc312-mnc670-my/strings.xml
new file mode 100644
index 0000000..292e8db
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-my/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"ဖုန်းကို ခွင့်မပြုပါ MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-nb/strings.xml b/core/res/res/values-mcc312-mnc670-nb/strings.xml
new file mode 100644
index 0000000..431fda6
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-nb/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Telefonen er ikke tillatt, MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-ne/strings.xml b/core/res/res/values-mcc312-mnc670-ne/strings.xml
new file mode 100644
index 0000000..ce2ce77
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-ne/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"फोनलाई अनुमति छैन MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-nl/strings.xml b/core/res/res/values-mcc312-mnc670-nl/strings.xml
new file mode 100644
index 0000000..d7eb032
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-nl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Telefoon niet toegestaan MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-pa/strings.xml b/core/res/res/values-mcc312-mnc670-pa/strings.xml
new file mode 100644
index 0000000..6b98d49
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-pa/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"ਫ਼ੋਨ ਨੂੰ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-pl/strings.xml b/core/res/res/values-mcc312-mnc670-pl/strings.xml
new file mode 100644
index 0000000..dd39c79
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-pl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"MM#6 – telefon niedozwolony"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-pt-rBR/strings.xml b/core/res/res/values-mcc312-mnc670-pt-rBR/strings.xml
new file mode 100644
index 0000000..bb58d18
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-pt-rBR/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Smartphone não permitido MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-pt-rPT/strings.xml b/core/res/res/values-mcc312-mnc670-pt-rPT/strings.xml
new file mode 100644
index 0000000..f04d740
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-pt-rPT/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Telemóvel não permitido MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-pt/strings.xml b/core/res/res/values-mcc312-mnc670-pt/strings.xml
new file mode 100644
index 0000000..bb58d18
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-pt/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Smartphone não permitido MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-ro/strings.xml b/core/res/res/values-mcc312-mnc670-ro/strings.xml
new file mode 100644
index 0000000..3129943
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-ro/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Telefonul nu este permis MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-ru/strings.xml b/core/res/res/values-mcc312-mnc670-ru/strings.xml
new file mode 100644
index 0000000..46080e0
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-ru/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Звонки запрещены (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-si/strings.xml b/core/res/res/values-mcc312-mnc670-si/strings.xml
new file mode 100644
index 0000000..6fdac6b
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-si/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"දුරකථනය MM#6 ඉඩ නොදේ"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-sk/strings.xml b/core/res/res/values-mcc312-mnc670-sk/strings.xml
new file mode 100644
index 0000000..c717019
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-sk/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Telefón nie je povolený (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-sl/strings.xml b/core/res/res/values-mcc312-mnc670-sl/strings.xml
new file mode 100644
index 0000000..15c7670
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-sl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Telefon ni dovoljen MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-sq/strings.xml b/core/res/res/values-mcc312-mnc670-sq/strings.xml
new file mode 100644
index 0000000..5c97026
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-sq/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Telefoni nuk lejohet MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-sr/strings.xml b/core/res/res/values-mcc312-mnc670-sr/strings.xml
new file mode 100644
index 0000000..9fdf70d
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-sr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Телефон није дозвољен MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-sv/strings.xml b/core/res/res/values-mcc312-mnc670-sv/strings.xml
new file mode 100644
index 0000000..0f9d454
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-sv/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Mobil tillåts inte MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-sw/strings.xml b/core/res/res/values-mcc312-mnc670-sw/strings.xml
new file mode 100644
index 0000000..e2c461e
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-sw/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Simu hairuhusiwi MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-ta/strings.xml b/core/res/res/values-mcc312-mnc670-ta/strings.xml
new file mode 100644
index 0000000..2c56a7e
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-ta/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"ஃபோன் அனுமதிக்கப்படவில்லை MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-te/strings.xml b/core/res/res/values-mcc312-mnc670-te/strings.xml
new file mode 100644
index 0000000..f9bd60a
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-te/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"ఫోన్ అనుమతించబడదు MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-th/strings.xml b/core/res/res/values-mcc312-mnc670-th/strings.xml
new file mode 100644
index 0000000..b144ca3
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-th/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"ไม่อนุญาตให้ใช้โทรศัพท์ MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-tl/strings.xml b/core/res/res/values-mcc312-mnc670-tl/strings.xml
new file mode 100644
index 0000000..79b88ec
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-tl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Hindi pinapahintulutan ang telepono MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-tr/strings.xml b/core/res/res/values-mcc312-mnc670-tr/strings.xml
new file mode 100644
index 0000000..1e3dcea
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-tr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Telefona izin verilmiyor MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-uk/strings.xml b/core/res/res/values-mcc312-mnc670-uk/strings.xml
new file mode 100644
index 0000000..d2dd817
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-uk/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Телефон заборонено (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-ur/strings.xml b/core/res/res/values-mcc312-mnc670-ur/strings.xml
new file mode 100644
index 0000000..f7ef38c
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-ur/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"‏فون کی اجازت نہیں ہے MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-uz/strings.xml b/core/res/res/values-mcc312-mnc670-uz/strings.xml
new file mode 100644
index 0000000..4bf0f74
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-uz/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Chaqiruvlar taqiqlangan (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-vi/strings.xml b/core/res/res/values-mcc312-mnc670-vi/strings.xml
new file mode 100644
index 0000000..4bae4af
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-vi/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Không cho phép điện thoại MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-zh-rCN/strings.xml b/core/res/res/values-mcc312-mnc670-zh-rCN/strings.xml
new file mode 100644
index 0000000..317531a
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-zh-rCN/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"不受允许的手机 MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-zh-rHK/strings.xml b/core/res/res/values-mcc312-mnc670-zh-rHK/strings.xml
new file mode 100644
index 0000000..bef6362
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-zh-rHK/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"不允許手機 MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-zh-rTW/strings.xml b/core/res/res/values-mcc312-mnc670-zh-rTW/strings.xml
new file mode 100644
index 0000000..1fa82ed
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-zh-rTW/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"不支援的手機 MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-zu/strings.xml b/core/res/res/values-mcc312-mnc670-zu/strings.xml
new file mode 100644
index 0000000..35c2cbf
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-zu/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="3649306773478362802">"Ifoni ayivunyelwe MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-af/strings.xml b/core/res/res/values-mcc313-mnc100-af/strings.xml
new file mode 100644
index 0000000..7645fc8
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-af/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Foon nie toegelaat nie MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-am/strings.xml b/core/res/res/values-mcc313-mnc100-am/strings.xml
new file mode 100644
index 0000000..b76ed04
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-am/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"ስልክ አይፈቀድም MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-ar/strings.xml b/core/res/res/values-mcc313-mnc100-ar/strings.xml
new file mode 100644
index 0000000..640fb8a
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-ar/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"‏غير مسموح باستخدام الهاتف MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-az/strings.xml b/core/res/res/values-mcc313-mnc100-az/strings.xml
new file mode 100644
index 0000000..44796df
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-az/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"MM#6 telefonu dəstəklənmir"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-b+sr+Latn/strings.xml b/core/res/res/values-mcc313-mnc100-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..d5bf39e
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-b+sr+Latn/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Telefon nije dozvoljen MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-be/strings.xml b/core/res/res/values-mcc313-mnc100-be/strings.xml
new file mode 100644
index 0000000..c9f4633
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-be/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Тэлефон не дапускаецца MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-bg/strings.xml b/core/res/res/values-mcc313-mnc100-bg/strings.xml
new file mode 100644
index 0000000..8c946ed
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-bg/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Телефонът не е разрешен MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-bn/strings.xml b/core/res/res/values-mcc313-mnc100-bn/strings.xml
new file mode 100644
index 0000000..5292241
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-bn/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"ফোন অনুমোদিত নয় MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-bs/strings.xml b/core/res/res/values-mcc313-mnc100-bs/strings.xml
new file mode 100644
index 0000000..d5bf39e
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-bs/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Telefon nije dozvoljen MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-ca/strings.xml b/core/res/res/values-mcc313-mnc100-ca/strings.xml
new file mode 100644
index 0000000..f6846cb
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-ca/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Telèfon no compatible MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-cs/strings.xml b/core/res/res/values-mcc313-mnc100-cs/strings.xml
new file mode 100644
index 0000000..4e57d15
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-cs/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Telefon není povolen (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-da/strings.xml b/core/res/res/values-mcc313-mnc100-da/strings.xml
new file mode 100644
index 0000000..c00d95c
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-da/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Telefonen har ikke adgangstilladelse MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-de/strings.xml b/core/res/res/values-mcc313-mnc100-de/strings.xml
new file mode 100644
index 0000000..df08b13
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-de/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Smartphone nicht zulässig MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-el/strings.xml b/core/res/res/values-mcc313-mnc100-el/strings.xml
new file mode 100644
index 0000000..0fcb42e
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-el/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Το τηλέφωνο δεν επιτρέπεται MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-en-rAU/strings.xml b/core/res/res/values-mcc313-mnc100-en-rAU/strings.xml
new file mode 100644
index 0000000..f1a3611
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-en-rAU/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Phone not allowed MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-en-rCA/strings.xml b/core/res/res/values-mcc313-mnc100-en-rCA/strings.xml
new file mode 100644
index 0000000..f1a3611
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-en-rCA/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Phone not allowed MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-en-rGB/strings.xml b/core/res/res/values-mcc313-mnc100-en-rGB/strings.xml
new file mode 100644
index 0000000..f1a3611
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-en-rGB/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Phone not allowed MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-en-rIN/strings.xml b/core/res/res/values-mcc313-mnc100-en-rIN/strings.xml
new file mode 100644
index 0000000..f1a3611
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-en-rIN/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Phone not allowed MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-en-rXC/strings.xml b/core/res/res/values-mcc313-mnc100-en-rXC/strings.xml
new file mode 100644
index 0000000..8a8bf7e
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-en-rXC/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‎‏‏‎‎‏‎‏‎‎‎‎‏‎‎‏‎‎‎‏‎‎‏‎‎‎‎‏‎‏‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‏‎‎‏‎‎‏‎‎‎Phone not allowed MM#6‎‏‎‎‏‎"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-es-rUS/strings.xml b/core/res/res/values-mcc313-mnc100-es-rUS/strings.xml
new file mode 100644
index 0000000..122d4b9
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-es-rUS/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Teléfono no admitido MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-es/strings.xml b/core/res/res/values-mcc313-mnc100-es/strings.xml
new file mode 100644
index 0000000..122d4b9
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-es/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Teléfono no admitido MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-et/strings.xml b/core/res/res/values-mcc313-mnc100-et/strings.xml
new file mode 100644
index 0000000..83cfbaf
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-et/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Telefon pole lubatud MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-eu/strings.xml b/core/res/res/values-mcc313-mnc100-eu/strings.xml
new file mode 100644
index 0000000..028ca37
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-eu/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Telefonoa ez da onartzen MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-fa/strings.xml b/core/res/res/values-mcc313-mnc100-fa/strings.xml
new file mode 100644
index 0000000..f29da6b
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-fa/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"‏تلفن مجاز نیست MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-fi/strings.xml b/core/res/res/values-mcc313-mnc100-fi/strings.xml
new file mode 100644
index 0000000..f64a38a
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-fi/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Puhelin estetty MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-fr-rCA/strings.xml b/core/res/res/values-mcc313-mnc100-fr-rCA/strings.xml
new file mode 100644
index 0000000..89c50ea
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-fr-rCA/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Téléphone non autorisé MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-fr/strings.xml b/core/res/res/values-mcc313-mnc100-fr/strings.xml
new file mode 100644
index 0000000..89c50ea
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-fr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Téléphone non autorisé MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-gl/strings.xml b/core/res/res/values-mcc313-mnc100-gl/strings.xml
new file mode 100644
index 0000000..04390a0
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-gl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Non se admite o teléfono MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-gu/strings.xml b/core/res/res/values-mcc313-mnc100-gu/strings.xml
new file mode 100644
index 0000000..6291d57
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-gu/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"MM#6 ફોનની મંજૂરી નથી"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-hi/strings.xml b/core/res/res/values-mcc313-mnc100-hi/strings.xml
new file mode 100644
index 0000000..f31e6bf
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-hi/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"फ़ोन की इजाज़त नहीं है MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-hr/strings.xml b/core/res/res/values-mcc313-mnc100-hr/strings.xml
new file mode 100644
index 0000000..290e92b
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-hr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Telefon nije dopušten MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-hu/strings.xml b/core/res/res/values-mcc313-mnc100-hu/strings.xml
new file mode 100644
index 0000000..31605dd
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-hu/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"A telefon nem engedélyezett (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-hy/strings.xml b/core/res/res/values-mcc313-mnc100-hy/strings.xml
new file mode 100644
index 0000000..62acde3
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-hy/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Հեռախոսի օգտագործումն արգելված է (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-in/strings.xml b/core/res/res/values-mcc313-mnc100-in/strings.xml
new file mode 100644
index 0000000..d95657f
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-in/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Ponsel tidak diizinkan MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-is/strings.xml b/core/res/res/values-mcc313-mnc100-is/strings.xml
new file mode 100644
index 0000000..3ad7b3c
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-is/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Sími ekki leyfður MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-it/strings.xml b/core/res/res/values-mcc313-mnc100-it/strings.xml
new file mode 100644
index 0000000..1d3deeb
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-it/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Telefono non consentito MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-iw/strings.xml b/core/res/res/values-mcc313-mnc100-iw/strings.xml
new file mode 100644
index 0000000..383e3d1
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-iw/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"‏הטלפון לא מורשה MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-ja/strings.xml b/core/res/res/values-mcc313-mnc100-ja/strings.xml
new file mode 100644
index 0000000..6a89e3d
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-ja/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"電話は許可されていません(MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-ka/strings.xml b/core/res/res/values-mcc313-mnc100-ka/strings.xml
new file mode 100644
index 0000000..a063fc4
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-ka/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"ტელეფონი დაუშვებელია MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-kk/strings.xml b/core/res/res/values-mcc313-mnc100-kk/strings.xml
new file mode 100644
index 0000000..0562a2f
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-kk/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Телефон пайдалануға болмайды MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-km/strings.xml b/core/res/res/values-mcc313-mnc100-km/strings.xml
new file mode 100644
index 0000000..74e607b
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-km/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"មិន​អនុញ្ញាត​ចំពោះ​ទូរសព្ទ​ទេ MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-kn/strings.xml b/core/res/res/values-mcc313-mnc100-kn/strings.xml
new file mode 100644
index 0000000..e287270
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-kn/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"ಫೋನ್ MM#6 ಅನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-ko/strings.xml b/core/res/res/values-mcc313-mnc100-ko/strings.xml
new file mode 100644
index 0000000..fbe222b
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-ko/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"전화가 허용되지 않음 MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-ky/strings.xml b/core/res/res/values-mcc313-mnc100-ky/strings.xml
new file mode 100644
index 0000000..8c08c4f
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-ky/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Телефонду колдонууга тыюу салынган MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-lo/strings.xml b/core/res/res/values-mcc313-mnc100-lo/strings.xml
new file mode 100644
index 0000000..793b87b
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-lo/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ໂທລະສັບ MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-lt/strings.xml b/core/res/res/values-mcc313-mnc100-lt/strings.xml
new file mode 100644
index 0000000..5edc6bf
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-lt/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Telefonas neleidžiamas (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-lv/strings.xml b/core/res/res/values-mcc313-mnc100-lv/strings.xml
new file mode 100644
index 0000000..de1ad9c
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-lv/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Tālruni nav atļauts izmantot: MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-mk/strings.xml b/core/res/res/values-mcc313-mnc100-mk/strings.xml
new file mode 100644
index 0000000..0b403e9
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-mk/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Телефонот не е дозволен MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-ml/strings.xml b/core/res/res/values-mcc313-mnc100-ml/strings.xml
new file mode 100644
index 0000000..1adc455
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-ml/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"ഫോൺ അനുവദനീയമല്ല MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-mn/strings.xml b/core/res/res/values-mcc313-mnc100-mn/strings.xml
new file mode 100644
index 0000000..5d5fbff
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-mn/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Утсыг зөвшөөрөөгүй MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-mr/strings.xml b/core/res/res/values-mcc313-mnc100-mr/strings.xml
new file mode 100644
index 0000000..32c6946
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-mr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"फोन MM#6 ला अनुमती देत नाही"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-ms/strings.xml b/core/res/res/values-mcc313-mnc100-ms/strings.xml
new file mode 100644
index 0000000..ebd1724
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-ms/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Telefon tidak dibenarkan MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-my/strings.xml b/core/res/res/values-mcc313-mnc100-my/strings.xml
new file mode 100644
index 0000000..7de66f7
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-my/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"ဖုန်းကို ခွင့်မပြုပါ MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-nb/strings.xml b/core/res/res/values-mcc313-mnc100-nb/strings.xml
new file mode 100644
index 0000000..84a7582
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-nb/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Telefonen er ikke tillatt, MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-ne/strings.xml b/core/res/res/values-mcc313-mnc100-ne/strings.xml
new file mode 100644
index 0000000..0fb9d64
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-ne/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"फोनलाई अनुमति छैन MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-nl/strings.xml b/core/res/res/values-mcc313-mnc100-nl/strings.xml
new file mode 100644
index 0000000..14e940d
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-nl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Telefoon niet toegestaan MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-pa/strings.xml b/core/res/res/values-mcc313-mnc100-pa/strings.xml
new file mode 100644
index 0000000..87b2e47
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-pa/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"ਫ਼ੋਨ ਨੂੰ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-pl/strings.xml b/core/res/res/values-mcc313-mnc100-pl/strings.xml
new file mode 100644
index 0000000..7df915c
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-pl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"MM#6 – telefon niedozwolony"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-pt-rBR/strings.xml b/core/res/res/values-mcc313-mnc100-pt-rBR/strings.xml
new file mode 100644
index 0000000..f80f618
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-pt-rBR/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Smartphone não permitido MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-pt-rPT/strings.xml b/core/res/res/values-mcc313-mnc100-pt-rPT/strings.xml
new file mode 100644
index 0000000..35d4f58
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-pt-rPT/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Telemóvel não permitido MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-pt/strings.xml b/core/res/res/values-mcc313-mnc100-pt/strings.xml
new file mode 100644
index 0000000..f80f618
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-pt/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Smartphone não permitido MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-ro/strings.xml b/core/res/res/values-mcc313-mnc100-ro/strings.xml
new file mode 100644
index 0000000..57a455d
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-ro/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Telefonul nu este permis MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-ru/strings.xml b/core/res/res/values-mcc313-mnc100-ru/strings.xml
new file mode 100644
index 0000000..8edec35
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-ru/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Звонки запрещены (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-si/strings.xml b/core/res/res/values-mcc313-mnc100-si/strings.xml
new file mode 100644
index 0000000..9493af0b
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-si/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"දුරකථනය MM#6 ඉඩ නොදේ"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-sk/strings.xml b/core/res/res/values-mcc313-mnc100-sk/strings.xml
new file mode 100644
index 0000000..04a1a08
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-sk/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Telefón nie je povolený (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-sl/strings.xml b/core/res/res/values-mcc313-mnc100-sl/strings.xml
new file mode 100644
index 0000000..e59c833
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-sl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Telefon ni dovoljen MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-sq/strings.xml b/core/res/res/values-mcc313-mnc100-sq/strings.xml
new file mode 100644
index 0000000..237a4a4
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-sq/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Telefoni nuk lejohet MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-sr/strings.xml b/core/res/res/values-mcc313-mnc100-sr/strings.xml
new file mode 100644
index 0000000..6d6c310
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-sr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Телефон није дозвољен MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-sv/strings.xml b/core/res/res/values-mcc313-mnc100-sv/strings.xml
new file mode 100644
index 0000000..145a960
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-sv/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Mobil tillåts inte MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-sw/strings.xml b/core/res/res/values-mcc313-mnc100-sw/strings.xml
new file mode 100644
index 0000000..a7574fb
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-sw/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Simu hairuhusiwi MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-ta/strings.xml b/core/res/res/values-mcc313-mnc100-ta/strings.xml
new file mode 100644
index 0000000..7ef5ea9
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-ta/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"ஃபோன் அனுமதிக்கப்படவில்லை MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-te/strings.xml b/core/res/res/values-mcc313-mnc100-te/strings.xml
new file mode 100644
index 0000000..8908fb7
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-te/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"ఫోన్ అనుమతించబడదు MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-th/strings.xml b/core/res/res/values-mcc313-mnc100-th/strings.xml
new file mode 100644
index 0000000..e562744
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-th/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"ไม่อนุญาตให้ใช้โทรศัพท์ MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-tl/strings.xml b/core/res/res/values-mcc313-mnc100-tl/strings.xml
new file mode 100644
index 0000000..6da1dbd
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-tl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Hindi pinapahintulutan ang telepono MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-tr/strings.xml b/core/res/res/values-mcc313-mnc100-tr/strings.xml
new file mode 100644
index 0000000..7200666
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-tr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Telefona izin verilmiyor MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-uk/strings.xml b/core/res/res/values-mcc313-mnc100-uk/strings.xml
new file mode 100644
index 0000000..833f9b1
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-uk/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Телефон заборонено (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-ur/strings.xml b/core/res/res/values-mcc313-mnc100-ur/strings.xml
new file mode 100644
index 0000000..d670d0e
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-ur/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"‏فون کی اجازت نہیں ہے MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-uz/strings.xml b/core/res/res/values-mcc313-mnc100-uz/strings.xml
new file mode 100644
index 0000000..202a30c
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-uz/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Chaqiruvlar taqiqlangan (MM#6)"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-vi/strings.xml b/core/res/res/values-mcc313-mnc100-vi/strings.xml
new file mode 100644
index 0000000..6a8c752
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-vi/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Không cho phép điện thoại MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-zh-rCN/strings.xml b/core/res/res/values-mcc313-mnc100-zh-rCN/strings.xml
new file mode 100644
index 0000000..056a75a
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-zh-rCN/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"不受允许的手机 MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-zh-rHK/strings.xml b/core/res/res/values-mcc313-mnc100-zh-rHK/strings.xml
new file mode 100644
index 0000000..db85730
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-zh-rHK/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"不允許手機 MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-zh-rTW/strings.xml b/core/res/res/values-mcc313-mnc100-zh-rTW/strings.xml
new file mode 100644
index 0000000..c907e39
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-zh-rTW/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"不支援的手機 MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-zu/strings.xml b/core/res/res/values-mcc313-mnc100-zu/strings.xml
new file mode 100644
index 0000000..1794f82
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-zu/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_illegal_me" msgid="7320955531336937252">"Ifoni ayivunyelwe MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index aef21c3..1deac5d 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Предупредувања"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Демонстрација за малопродажба"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-врска"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Апликацијата работи"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Апликации што ја трошат батеријата"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> користи батерија"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> апликации користат батерија"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Метод на внес"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Дејства со текст"</string>
     <string name="email" msgid="4560673117055050403">"E-пошта"</string>
-    <string name="dial" msgid="4204975095406423102">"Телефон"</string>
-    <string name="map" msgid="6068210738233985748">"„Карти“"</string>
-    <string name="browse" msgid="6993590095938149861">"Прелистувач"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Контакт"</string>
+    <string name="dial" msgid="1253998302767701559">"Повикај"</string>
+    <string name="map" msgid="6521159124535543457">"Лоцирај"</string>
+    <string name="browse" msgid="1245903488306147205">"Отвори"</string>
+    <string name="sms" msgid="4560537514610063430">"Порака"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Додај"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Меморијата е речиси полна"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Некои системски функции може да не работат"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Нема доволно меморија во системот. Проверете дали има слободен простор од 250 МБ и рестартирајте."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Откажи"</string>
     <string name="yes" msgid="5362982303337969312">"Во ред"</string>
     <string name="no" msgid="5141531044935541497">"Откажи"</string>
-    <string name="close" msgid="2318214661230355730">"ЗАТВОРИ"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Внимание"</string>
     <string name="loading" msgid="7933681260296021180">"Се вчитува..."</string>
     <string name="capital_on" msgid="1544682755514494298">"ВКЛУЧЕНО"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Размер"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Покажи секогаш"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Повторно овозможете го ова во Системски поставки &gt; Апликации &gt; Преземено."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Апликацијата не реагира"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> може да користи премногу меморија."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> не ја поддржува тековната поставка за големина на екранот и може да се однесува непредвидено."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Секогаш прикажувај"</string>
     <string name="smv_application" msgid="3307209192155442829">"Апликацијата <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) ја прекрши политиката StrictMode што си ја наметна врз себеси."</string>
@@ -1786,11 +1784,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Тестирање пораки за итни случаи"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Одговори"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"Не е дозволена SIM-картичка"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Не е обезбедена SIM-картичка"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"Не е дозволена SIM-картичка"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Не е дозволен телефон"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Појавен прозорец"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Појавен прозорец"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"За кратенкава е потребна најновата апликација"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Не можеше да се врати кратенката бидејќи апликацијата не поддржува бекап и враќање"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Не можеше да се врати кратенката бидејќи потписот на апликацијата не се совпаѓа"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Не можеше да се врати кратенката"</string>
 </resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 89333cc..ae897b3 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"അലേർട്ടുകൾ"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"റീട്ടെയിൽ ഡെമോ"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB കണക്ഷൻ"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"ആപ്പ് പ്രവർത്തിക്കുന്നു"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"ആപ്പുകൾ ബാറ്ററി ഉപയോഗിക്കുന്നു"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> ബാറ്ററി ഉപയോഗിക്കുന്നു"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> ആപ്പുകൾ ബാറ്ററി ഉപയോഗിക്കുന്നു"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"ടൈപ്പുചെയ്യൽ രീതി"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"ടെക്‌സ്‌റ്റ് പ്രവർത്തനങ്ങൾ"</string>
     <string name="email" msgid="4560673117055050403">"ഇമെയിൽ"</string>
-    <string name="dial" msgid="4204975095406423102">"ഫോണ്‍"</string>
-    <string name="map" msgid="6068210738233985748">"മാപ്‌സ്"</string>
-    <string name="browse" msgid="6993590095938149861">"ബ്രൗസർ"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"കോണ്‍‌ടാക്റ്റ്"</string>
+    <string name="dial" msgid="1253998302767701559">"വിളിക്കുക"</string>
+    <string name="map" msgid="6521159124535543457">"കണ്ടെത്തുക"</string>
+    <string name="browse" msgid="1245903488306147205">"തുറക്കുക"</string>
+    <string name="sms" msgid="4560537514610063430">"സന്ദേശം"</string>
+    <string name="add_contact" msgid="7867066569670597203">"ചേർക്കുക"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"സംഭരണയിടം കഴിഞ്ഞു"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"ചില സിസ്റ്റം പ്രവർത്തനങ്ങൾ പ്രവർത്തിക്കണമെന്നില്ല."</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"സിസ്‌റ്റത്തിനായി മതിയായ സംഭരണമില്ല. 250MB സൗജന്യ സംഭരണമുണ്ടെന്ന് ഉറപ്പുവരുത്തി പുനരാരംഭിക്കുക."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"റദ്ദാക്കുക"</string>
     <string name="yes" msgid="5362982303337969312">"ശരി"</string>
     <string name="no" msgid="5141531044935541497">"റദ്ദാക്കുക"</string>
-    <string name="close" msgid="2318214661230355730">"അടയ്‌ക്കുക"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"ശ്രദ്ധിക്കുക"</string>
     <string name="loading" msgid="7933681260296021180">"ലോഡുചെയ്യുന്നു..."</string>
     <string name="capital_on" msgid="1544682755514494298">"ഓൺ"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"സ്കെയിൽ"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"എപ്പോഴും പ്രദര്‍ശിപ്പിക്കുക"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"സിസ്‌റ്റം ക്രമീകരണങ്ങൾ &gt; അപ്ലിക്കേഷനുകൾ &gt; ഡൗൺലോഡുചെയ്‌തവ എന്നതിൽ ഇത് വീണ്ടും പ്രവർത്തനക്ഷമമാക്കുക."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"ആപ്പ് പ്രതികരിക്കുന്നില്ല"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> വളരെയധികം മെമ്മറി ഉപയോഗിക്കുന്നുണ്ടാകാം."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"നിലവിലെ ഡിസ്പ്ലേ വലുപ്പ ക്രമീകരണത്തെ <xliff:g id="APP_NAME">%1$s</xliff:g> പിന്തുണയ്ക്കുന്നില്ല, അതിനാൽ പ്രതീക്ഷിക്കാത്ത തരത്തിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കാം."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"എല്ലായ്‌പ്പോഴും ദൃശ്യമാക്കുക"</string>
     <string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> എന്ന അപ്ലിക്കേഷൻ (<xliff:g id="PROCESS">%2$s</xliff:g> പ്രോസസ്സ്) അതിന്റെ സ്വയം നിർബന്ധിത StrictMode നയം ലംഘിച്ചു."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"അടിയന്തര സന്ദേശ ടെസ്റ്റ്"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"മറുപടി നൽകുക"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM അനുവദനീയമല്ല"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM പ്രൊവിഷൻ ചെയ്തിട്ടില്ല"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM അനുവദനീയമല്ല"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"ഫോൺ അനുവദനീയമല്ല"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"പോപ്പ് അപ്പ് വിൻഡോ"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"പോപ്പ് അപ്പ് വിൻഡോ"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"ഈ കുറുക്കുവഴിക്ക് ഏറ്റവും പുതിയ ആപ്പ് ആവശ്യമാണ്"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"ആപ്പ് \'ബാക്കപ്പും പുനഃസ്ഥാപിക്കലും\' പിന്തുണയ്ക്കാത്തതിനാൽ കുറുക്കുവഴി പുനഃസ്ഥാപിക്കാനായില്ല"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"ആപ്പ് സിഗ്നേച്ചർ പൊരുത്തപ്പെടാത്തതിനാൽ കുറുക്കുവഴി പുനഃസ്ഥാപിക്കാനായില്ല"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"കുറുക്കുവഴി പുനഃസ്ഥാപിക്കാനായില്ല"</string>
 </resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 9173f2c..3e1992b 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Сануулга"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Жижиглэнгийн жишээ"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB холболт"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Апп ажиллаж байна"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Апп батерей ашиглаж байна"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> батерей ашиглаж байна"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> апп батерей ашиглаж байна"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Оруулах арга"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Текст үйлдэл"</string>
     <string name="email" msgid="4560673117055050403">"Имэйл"</string>
-    <string name="dial" msgid="4204975095406423102">"Утас"</string>
-    <string name="map" msgid="6068210738233985748">"Газрын зураг"</string>
-    <string name="browse" msgid="6993590095938149861">"Хөтөч"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Харилцагч"</string>
+    <string name="dial" msgid="1253998302767701559">"Залгах"</string>
+    <string name="map" msgid="6521159124535543457">"Байрших"</string>
+    <string name="browse" msgid="1245903488306147205">"Нээх"</string>
+    <string name="sms" msgid="4560537514610063430">"Зурвас"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Нэмэх"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Сангийн хэмжээ дутагдаж байна"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Зарим систем функц ажиллахгүй байна"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Системд хангалттай сан байхгүй байна. 250MБ чөлөөтэй зай байгаа эсэхийг шалгаад дахин эхлүүлнэ үү."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Цуцлах"</string>
     <string name="yes" msgid="5362982303337969312">"ОК"</string>
     <string name="no" msgid="5141531044935541497">"Цуцлах"</string>
-    <string name="close" msgid="2318214661230355730">"ХААХ"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Анхаар"</string>
     <string name="loading" msgid="7933681260296021180">"Ачааллаж байна..."</string>
     <string name="capital_on" msgid="1544682755514494298">"Идэвхтэй"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Цар хэмжээ"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Байнга харуулах"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Энийг Системийн тохиргоо &gt; Апп &gt; Татаж авсан дотроос дахин идэвхтэй болгох боломжтой."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Апп хариу өгөхгүй байна"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> хэт их санах ой ашиглаж байж болзошгүй."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь Дэлгэцийн хэмжээний одоогийн тохиргоог дэмждэггүй учир буруу ажиллаж болзошгүй."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Байнга харуулах"</string>
     <string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> апп (<xliff:g id="PROCESS">%2$s</xliff:g> процесс) өөрийнхөө StrictMode бодлогыг зөрчив."</string>
@@ -1782,11 +1780,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Онцгой байдлын зурвасын тест"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Хариу бичих"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM боломжгүй"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM-г хийгээгүй"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM боломжгүй"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Утас боломжгүй"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"гэнэт гарч ирэх цонх"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"гэнэт гарч ирэх цонх"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Энэ товчлолд саяхны апп шаардлагатай"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Апп нөөцлөлт, сэргээлтийг дэмждэггүй тул товчлолыг сэргээж чадсангүй"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Аппын гарын үсэг таарахгүй байгаа тул товчлолыг сэргээж чадсангүй"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Товчлолыг сэргээж чадсангүй"</string>
 </resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index eac23b9..96a9eda7 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"सूचना"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"रीटेल डेमो"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB कनेक्‍शन"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"APP चालत आहे"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"अॅप्‍समुळे बॅटरी संपत आहे"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> बॅटरी वापरत आहे"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> अॅप्‍स बॅटरी वापरत आहेत"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"इनपुट पद्धत"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"मजकूर क्रिया"</string>
     <string name="email" msgid="4560673117055050403">"ईमेल"</string>
-    <string name="dial" msgid="4204975095406423102">"फोन"</string>
-    <string name="map" msgid="6068210738233985748">"नकाशे"</string>
-    <string name="browse" msgid="6993590095938149861">"ब्राउझर"</string>
-    <string name="sms" msgid="8250353543787396737">"एसएमएस"</string>
-    <string name="add_contact" msgid="7990645816259405444">"संपर्क"</string>
+    <string name="dial" msgid="1253998302767701559">"कॉल करा"</string>
+    <string name="map" msgid="6521159124535543457">"शोधा"</string>
+    <string name="browse" msgid="1245903488306147205">"उघडा"</string>
+    <string name="sms" msgid="4560537514610063430">"संदेश"</string>
+    <string name="add_contact" msgid="7867066569670597203">"जोडा"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"संचयन स्थान संपत आहे"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"काही सिस्टम कार्ये कार्य करू शकत नाहीत"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"सिस्टीमसाठी पुरेसे संचयन नाही. आपल्याकडे 250MB मोकळे स्थान असल्याचे सुनिश्चित करा आणि रीस्टार्ट करा."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"रद्द करा"</string>
     <string name="yes" msgid="5362982303337969312">"ठीक"</string>
     <string name="no" msgid="5141531044935541497">"रद्द करा"</string>
-    <string name="close" msgid="2318214661230355730">"बंद करा"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"लक्ष द्या"</string>
     <string name="loading" msgid="7933681260296021180">"लोड करीत आहे..."</string>
     <string name="capital_on" msgid="1544682755514494298">"चालू"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"स्केल"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"नेहमी दर्शवा"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"सिस्टम सेटिंग्ज &gt; Apps &gt; डाउनलोड केलेले मध्ये हे पुन्हा-सक्षम करा."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"अॅप प्रतिसाद देत नाही"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> कदाचित बरीच मेमरी वापरत आहे."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> वर्तमान डिस्प्ले आकार सेटिंगला समर्थन देत नाही आणि अनपेक्षित वर्तन करू शकते."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"नेहमी दर्शवा"</string>
     <string name="smv_application" msgid="3307209192155442829">"अॅप <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ने तिच्या स्वयं-लागू केलेल्या StrictMode धोरणाचे उल्लंघन केले आहे."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"आणीबाणी संदेश चाचणी"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"प्रत्युत्तर द्या"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"सिमला अनुमती नाही"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"सिमसाठी तरतूद नाही"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"सिमला अनुमती नाही"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"फोनला अनुमती नाही"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"पॉपअप विंडो"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"पॉपअप विंडो"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"या शॉर्टकटला नवीनतम अॅपची आवश्यकता आहे"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"अॅप बॅकअप आणि रिस्‍टोअर करण्यास सपोर्ट देत नसल्यामुळे शॉर्टकट रिस्‍टोअर करू शकलो नाही"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"अॅप स्वाक्षरी न जुळल्यामुळे शॉर्टकट रिस्‍टोअर करू शकलो नाही"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"शॉर्टकट रिस्‍टोअर करू शकलो नाही"</string>
 </resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index a627a05..3753fb2 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Makluman"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Tunjuk cara runcit"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Sambungan USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Apl berjalan"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Apl yang menggunakan bateri"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang menggunakan bateri"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> apl sedang menggunakan bateri"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Kaedah input"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Tindakan teks"</string>
     <string name="email" msgid="4560673117055050403">"E-mel"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefon"</string>
-    <string name="map" msgid="6068210738233985748">"Peta"</string>
-    <string name="browse" msgid="6993590095938149861">"Penyemak imbas"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Kenalan"</string>
+    <string name="dial" msgid="1253998302767701559">"Panggil"</string>
+    <string name="map" msgid="6521159124535543457">"Cari"</string>
+    <string name="browse" msgid="1245903488306147205">"Buka"</string>
+    <string name="sms" msgid="4560537514610063430">"Mesej"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Tambah"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ruang storan semakin berkurangan"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Beberapa fungsi sistem mungkin tidak berfungsi"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Tidak cukup storan untuk sistem. Pastikan anda mempunyai 250MB ruang kosong dan mulakan semula."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Batal"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Batal"</string>
-    <string name="close" msgid="2318214661230355730">"TUTUP"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Perhatian"</string>
     <string name="loading" msgid="7933681260296021180">"Memuatkan…"</string>
     <string name="capital_on" msgid="1544682755514494298">"HIDUP"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skala"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Sentiasa tunjukkan"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Dayakan semula kod kompak ini tetapan Sistem &gt; Apl &gt; Dimuat turun."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Apl tidak bertindak balas"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> mungkin menggunakan terlalu banyak memori."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak menyokong tetapan saiz Paparan semasa dan mungkin menunjukkan gelagat yang tidak dijangka."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Sentiasa tunjukkan"</string>
     <string name="smv_application" msgid="3307209192155442829">"Apl <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) telah melanggar dasar Mod Tegasnya sendiri."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Ujian mesej kecemasan"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Balas"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM tidak dibenarkan"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM tidak diperuntukkan"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM tidak dibenarkan"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Telefon tidak dibenarkan"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Tetingkap Timbul"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Tetingkap Timbul"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Pintasan ini memerlukan apl yang terbaharu"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Tidak dapat memulihkan pintasan kerana apl tidak menyokong sandaran dan segerakan"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Tidak dapat memulihkan pintasan kerana ketakpadanan tandatangan apl"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Tidak dapat memulihkan pintasan"</string>
 </resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 01f7b76..0f0ae23 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"သတိပေးချက်များ"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"လက်လီအရောင်းဆိုင် သရုပ်ပြမှု"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB ချိတ်ဆက်မှု"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"APP လုပ်ဆောင်နေသည်"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"အက်ပ်များက ဘက်ထရီကုန်စေသည်"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> က ဘက်ထရီကို အသုံးပြုနေသည်"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"အက်ပ် <xliff:g id="NUMBER">%1$d</xliff:g> ခုက ဘက်ထရီကို အသုံးပြုနေသည်"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"ထည့်သွင်းရန်နည်းလမ်း"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"စာတို လုပ်ဆောင်ချက်"</string>
     <string name="email" msgid="4560673117055050403">"အီးမေးလ်"</string>
-    <string name="dial" msgid="4204975095406423102">"ဖုန်း"</string>
-    <string name="map" msgid="6068210738233985748">"Maps"</string>
-    <string name="browse" msgid="6993590095938149861">"ဘရောင်ဇာ"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS စာတိုစနစ်"</string>
-    <string name="add_contact" msgid="7990645816259405444">"အဆက်အသွယ်"</string>
+    <string name="dial" msgid="1253998302767701559">"ခေါ်ဆိုရန်"</string>
+    <string name="map" msgid="6521159124535543457">"တည်နေရာ"</string>
+    <string name="browse" msgid="1245903488306147205">"ဖွင့်ရန်"</string>
+    <string name="sms" msgid="4560537514610063430">"စာပို့ရန်"</string>
+    <string name="add_contact" msgid="7867066569670597203">"ထည့်ရန်"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"သိမ်းဆည်သော နေရာ နည်းနေပါသည်"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"တချို့ စနစ်လုပ်ငန်းများ အလုပ် မလုပ်ခြင်း ဖြစ်နိုင်ပါသည်"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"စနစ်အတွက် သိုလှောင်ခန်း မလုံလောက်ပါ။ သင့်ဆီမှာ နေရာလွတ် ၂၅၀ MB ရှိတာ စစ်ကြည့်ပြီး စတင်ပါ။"</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"မလုပ်တော့"</string>
     <string name="yes" msgid="5362982303337969312">"အိုကေ"</string>
     <string name="no" msgid="5141531044935541497">"မလုပ်တော့"</string>
-    <string name="close" msgid="2318214661230355730">"ပိတ်ရန်"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"သတိပြုရန်"</string>
     <string name="loading" msgid="7933681260296021180">"တင်နေ…"</string>
     <string name="capital_on" msgid="1544682755514494298">"ဖွင့်ရန်"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"စကေး"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"အမြဲပြသရန်"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"ဒါကို စနစ် ဆက်တင်များထဲ ပြန်ဖွင့်ပေးရန် &gt; Apps &gt; ဒေါင်းလုဒ် လုပ်ပြီး။"</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"အက်ပ်က တုံ့ပြန်မှုမရှိပါ"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> က နေရာအလွန်အကျွံ ယူထားပုံရပါသည်။"</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် လက်ရှိ မျက်နှာပြင်အရွယ်အစားကို ပံ့ပိုးထားခြင်း မရှိပါ။ မမျှော်လင့်နိုင်သည့် ချွတ်ယွင်းချက်များ ဖြစ်ပေါ်နိုင်ပါသည်။"</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"အမြဲပြပါ"</string>
     <string name="smv_application" msgid="3307209192155442829">"app <xliff:g id="APPLICATION">%1$s</xliff:g> (လုပ်ငန်းစဉ် <xliff:g id="PROCESS">%2$s</xliff:g>) က ကိုယ်တိုင် ပြဌာန်းခဲ့သည့် StrictMode မူဝါဒကို ချိုးဖောက်ခဲ့သည်။"</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"အရေးပေါ် မက်ဆေ့ဂျ် စမ်းသပ်မှု"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"စာပြန်ရန်"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"ဆင်းမ်ကို ခွင့်မပြုပါ"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"ဆင်းမ်ကို ထောက်ပံ့မထားပါ"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"ဆင်းမ်ကို ခွင့်မပြုပါ"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"ဖုန်းကို ခွင့်မပြုပါ"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"ပေါ့ပ်အပ် ဝင်းဒိုး"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"ပေါ့ပ်အပ် ဝင်းဒိုး"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"ဤဖြတ်လမ်းလင့်ခ်ကို အသုံးပြုနိုင်ရန် နောက်ဆုံးထွက်အက်ပ် လိုအပ်ပါသည်"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"အက်ပ်သည် မိတ္တူကူးခြင်းနှင့် ပြန်ယူခြင်းကို ပံ့ပိုးခြင်းမရှိသည့်အတွက် ဖြတ်လမ်းလင့်ခ်ကို ပြန်ယူ၍မရပါ"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"အက်ပ်လက်မှတ် မတူညီသည့်အတွက် ဖြတ်လမ်းလင့်ခ်များကို ပြန်ယူ၍မရပါ"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"ဖြတ်လမ်းလင့်ခ်ကို ပြန်ယူ၍မရပါ"</string>
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 8e7b683..93e978c 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Varsler"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Butikkdemo"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-tilkobling"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"App kjører"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Apper bruker batteri"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> bruker batteri"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> apper bruker batteri"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Inndatametode"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Teksthandlinger"</string>
     <string name="email" msgid="4560673117055050403">"E-post"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefon"</string>
-    <string name="map" msgid="6068210738233985748">"Kart"</string>
-    <string name="browse" msgid="6993590095938149861">"Nettleser"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Kontakt"</string>
+    <string name="dial" msgid="1253998302767701559">"Ring"</string>
+    <string name="map" msgid="6521159124535543457">"Finn"</string>
+    <string name="browse" msgid="1245903488306147205">"Åpne"</string>
+    <string name="sms" msgid="4560537514610063430">"Melding"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Legg til"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Lite ledig lagringsplass"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Enkelte systemfunksjoner fungerer muligens ikke slik de skal"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Det er ikke nok lagringsplass for systemet. Kontrollér at du har 250 MB ledig plass, og start på nytt."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Avbryt"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Avbryt"</string>
-    <string name="close" msgid="2318214661230355730">"LUKK"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Merk"</string>
     <string name="loading" msgid="7933681260296021180">"Laster inn …"</string>
     <string name="capital_on" msgid="1544682755514494298">"På"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skala"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Vis alltid"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reaktiver dette i systeminnstillingene  &gt; Apper &gt; Nedlastet."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Appen svarer ikke"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> bruker muligens for mye minne."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> støtter ikke den nåværende innstillingen for skjermstørrelse og fungerer kanskje ikke som den skal."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Vis alltid"</string>
     <string name="smv_application" msgid="3307209192155442829">"Appen <xliff:g id="APPLICATION">%1$s</xliff:g> (prosessen <xliff:g id="PROCESS">%2$s</xliff:g>) har brutt de selvpålagte StrictMode-retningslinjene."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test av nødmeldinger"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Svar"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM-kortet er ikke tillatt"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM-kortet er ikke klargjort"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM-kortet er ikke tillatt"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Telefonen er ikke tillatt"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Forgrunnsvindu"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Forgrunnsvindu"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Denne snarveien krever den nyeste appen"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Kunne ikke gjenopprette snarveien fordi appen ikke støtter sikkerhetskopiering og gjenoppretting"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Kunne ikke gjenopprette snarveien på grunn av manglende samsvar for appsignaturen"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Kunne ikke gjenopprette snarveien"</string>
 </resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 41bb71b..8300237 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"अलर्टहरू"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"खुद्रा बिक्री सम्बन्धी डेमो"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB जडान"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"अनुप्रयोग चलिरहेको छ"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"अनुप्रयोगहरूले ब्याट्री खपत गर्दै छन्"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले ब्याट्री प्रयोग गर्दै छ"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> अनुप्रयोगहरूले ब्याट्री प्रयोग गर्दै छन्"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"निवेश विधि"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"पाठ कार्यहरू"</string>
     <string name="email" msgid="4560673117055050403">"इमेल"</string>
-    <string name="dial" msgid="4204975095406423102">"फोन गर्नुहोस्"</string>
-    <string name="map" msgid="6068210738233985748">"नक्सा"</string>
-    <string name="browse" msgid="6993590095938149861">"ब्राउजर"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"सम्पर्क"</string>
+    <string name="dial" msgid="1253998302767701559">"कल"</string>
+    <string name="map" msgid="6521159124535543457">"पत्ता लगाउनुहोस्"</string>
+    <string name="browse" msgid="1245903488306147205">"खोल्नुहोस्"</string>
+    <string name="sms" msgid="4560537514610063430">"सन्देश"</string>
+    <string name="add_contact" msgid="7867066569670597203">"थप्नुहोस्"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"भण्डारण ठाउँ सकिँदै छ"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"सायद केही प्रणाली कार्यक्रमहरूले काम गर्दैनन्"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"प्रणालीको लागि पर्याप्त भण्डारण छैन। तपाईँसँग २५० मेगा बाइट ठाउँ खाली भएको निश्चित गर्नुहोस् र फेरि सुरु गर्नुहोस्।"</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"रद्द गर्नुहोस्"</string>
     <string name="yes" msgid="5362982303337969312">"ठीक छ"</string>
     <string name="no" msgid="5141531044935541497">"रद्द गर्नुहोस्"</string>
-    <string name="close" msgid="2318214661230355730">"बन्द गर्नुहोस्"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"सावधानी"</string>
     <string name="loading" msgid="7933681260296021180">"लोड हुँदै..."</string>
     <string name="capital_on" msgid="1544682755514494298">"चालु"</string>
@@ -1055,8 +1055,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"स्केल"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"सधैँ देखाउनुहोस्"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"प्रणाली सेटिङहरूमा यसलाई पुनःसक्षम गराउनुहोस् &gt; अनुप्रयोगहरू &gt; डाउनलोड गरेको।"</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"अनुप्रयोग चलिरहेको छैन"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले अत्यधिक मेमोरी प्रयोग गरिरहेको हुनसक्छ।"</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले हालको प्रदर्शनको आकार सम्बन्धी सेटिङलाई समर्थन गर्दैन र अप्रत्याशित तरिकाले व्यवहार गर्न सक्छ।"</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"सधैँ देखाउनुहोस्"</string>
     <string name="smv_application" msgid="3307209192155442829">"अनुप्रयोग <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ले यसको स्वयं-लागु गरिएको स्ट्रिटमोड नीति उलङ्घन गरेको छ।"</string>
@@ -1790,11 +1788,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"आपतकालीन सन्देशहरूको परीक्षण"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"जवाफ दिनुहोस्"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM लाई अनुमति छैन"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM को प्रावधान छैन"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM लाई अनुमति छैन"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"फोनलाई अनुमति छैन"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"पपअप विन्डो"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"पपअप विन्डो"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"यो सर्टकटलाई पछिल्लो अनुप्रयोग आवश्यक हुन्छ"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"अनुप्रयोगले ब्याकअप तथा पुनर्स्थापनालाई समर्थन नगर्ने हुँदा सर्टकट पुनर्स्थापित गर्न सकिएन"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"अनुप्रयोगमा प्रयोग गरिने हस्ताक्षर नमिल्ने हुँदा सर्टकट पुनर्स्थापित गर्न सकिएन"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"सर्टकट पुनर्स्थापित गर्न सकिएन"</string>
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 1355ed3..44215c3 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Meldingen"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demo voor de detailhandel"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-verbinding"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"App actief"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Apps die de batterij gebruiken"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> gebruikt de batterij"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> apps gebruiken de batterij"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Invoermethode"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Tekstacties"</string>
     <string name="email" msgid="4560673117055050403">"E-mail"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefoon"</string>
-    <string name="map" msgid="6068210738233985748">"Kaarten"</string>
-    <string name="browse" msgid="6993590095938149861">"Browser"</string>
-    <string name="sms" msgid="8250353543787396737">"Sms"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Contact"</string>
+    <string name="dial" msgid="1253998302767701559">"Bellen"</string>
+    <string name="map" msgid="6521159124535543457">"Zoeken"</string>
+    <string name="browse" msgid="1245903488306147205">"Openen"</string>
+    <string name="sms" msgid="4560537514610063430">"Bericht"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Toevoegen"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Opslagruimte is bijna vol"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Bepaalde systeemfuncties werken mogelijk niet"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Onvoldoende opslagruimte voor het systeem. Zorg ervoor dat je 250 MB vrije ruimte hebt en start opnieuw."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Annuleren"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Annuleren"</string>
-    <string name="close" msgid="2318214661230355730">"SLUITEN"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Let op"</string>
     <string name="loading" msgid="7933681260296021180">"Laden..."</string>
     <string name="capital_on" msgid="1544682755514494298">"AAN"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Schaal"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Altijd weergeven"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"U kunt dit opnieuw inschakelen via Systeeminstellingen &gt; Apps &gt; Gedownload."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"App reageert niet"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> gebruikt mogelijk te veel geheugen"</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> biedt geen ondersteuning voor de huidige instelling voor weergavegrootte en kan onverwacht gedrag vertonen."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Altijd weergeven"</string>
     <string name="smv_application" msgid="3307209192155442829">"De app <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) heeft het zelf afgedwongen StrictMode-beleid geschonden."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test voor noodberichten"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Beantwoorden"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"Simkaart niet toegestaan"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Simkaart niet geregistreerd"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"Simkaart niet toegestaan"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Telefoon niet toegestaan"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Pop-upvenster"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Pop-upvenster"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Voor deze snelkoppeling is de nieuwste app vereist"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Kan snelkoppeling niet herstellen omdat de app geen ondersteuning biedt voor \'Back-up maken en terugzetten\'"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Kan snelkoppeling niet herstellen vanwege een niet-overeenkomende app-ondertekening"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Kan snelkoppeling niet herstellen"</string>
 </resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index d6ecf91..d6233fb 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"ਸੁਚੇਤਨਾਵਾਂ"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"ਪ੍ਰਚੂਨ ਸਟੋਰਾਂ ਲਈ ਡੈਮੋ"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB ਕਨੈਕਸ਼ਨ"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"ਐਪ ਚੱਲ ਰਹੀ ਹੈ"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"ਬੈਟਰੀ ਦੀ ਖਪਤ ਕਰਨ ਵਾਲੀਆਂ ਐਪਾਂ"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਵੱਲੋਂ ਬੈਟਰੀ ਦੀ ਵਰਤੋਂ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> ਐਪਾਂ ਬੈਟਰੀ ਦੀ ਵਰਤੋਂ ਕਰ ਰਹੀਆਂ ਹਨ"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"ਇਨਪੁੱਟ ਵਿਧੀ"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"ਟੈਕਸਟ ਕਿਰਿਆਵਾਂ"</string>
     <string name="email" msgid="4560673117055050403">"ਈਮੇਲ ਕਰੋ"</string>
-    <string name="dial" msgid="4204975095406423102">"ਫ਼ੋਨ ਕਰੋ"</string>
-    <string name="map" msgid="6068210738233985748">"ਨਕਸ਼ੇ"</string>
-    <string name="browse" msgid="6993590095938149861">"ਬ੍ਰਾਊਜ਼ਰ"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"ਸੰਪਰਕ"</string>
+    <string name="dial" msgid="1253998302767701559">"ਕਾਲ ਕਰੋ"</string>
+    <string name="map" msgid="6521159124535543457">"ਟਿਕਾਣਾ ਦੇਖੋ"</string>
+    <string name="browse" msgid="1245903488306147205">"ਖੋਲ੍ਹੋ"</string>
+    <string name="sms" msgid="4560537514610063430">"ਸੁਨੇਹਾ ਭੇਜੋ"</string>
+    <string name="add_contact" msgid="7867066569670597203">"ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"ਸਟੋਰੇਜ ਦੀ ਜਗ੍ਹਾ ਖਤਮ ਹੋ ਰਹੀ ਹੈ"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"ਕੁਝ ਸਿਸਟਮ ਫੰਕਸ਼ਨ ਕੰਮ ਨਹੀਂ ਵੀ ਕਰ ਸਕਦੇ"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ਸਿਸਟਮ ਲਈ ਲੋੜੀਂਦੀ ਸਟੋਰੇਜ ਨਹੀਂ ਹੈ। ਯਕੀਨੀ ਬਣਾਓ ਕਿ ਤੁਹਾਡੇ ਕੋਲ 250MB ਖਾਲੀ ਜਗ੍ਹਾ ਹੈ ਅਤੇ ਮੁੜ-ਚਾਲੂ ਕਰੋ।"</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"ਰੱਦ ਕਰੋ"</string>
     <string name="yes" msgid="5362982303337969312">"ਠੀਕ"</string>
     <string name="no" msgid="5141531044935541497">"ਰੱਦ ਕਰੋ"</string>
-    <string name="close" msgid="2318214661230355730">"ਬੰਦ ਕਰੋ"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"ਧਿਆਨ ਦਿਓ"</string>
     <string name="loading" msgid="7933681260296021180">"ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ..."</string>
     <string name="capital_on" msgid="1544682755514494298">"ਚਾਲੂ"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"ਸਕੇਲ"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"ਹਮੇਸ਼ਾਂ ਦਿਖਾਓ"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"ਸਿਸਟਮ ਸੈਟਿੰਗਾਂ &gt; ਐਪਾਂ &gt; ਡਾਊਨਲੋਡ ਕੀਤਿਆਂ ਵਿੱਚ ਇਸਨੂੰ ਮੁੜ-ਸਮਰੱਥ ਬਣਾਓ।"</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"ਐਪ ਪ੍ਰਤਿਕਿਰਿਆ ਨਹੀਂ ਦੇ ਰਹੀ ਹੈ"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"ਸ਼ਾਇਦ <xliff:g id="APP_NAME">%1$s</xliff:g> ਵੱਲੋਂ ਬਹੁਤ ਜ਼ਿਆਦਾ ਮੈਮੋਰੀ ਦੀ ਵਰਤੋਂ ਕੀਤੀ ਜਾ ਰਹੀ ਹੋਵੇ।"</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਵਰਤਮਾਨ ਡਿਸਪਲੇ ਆਕਾਰ ਸੈਟਿੰਗ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ ਹੈ ਅਤੇ ਅਣਕਿਆਸੇ ਤੌਰ \'ਤੇ ਵਿਹਾਰ ਕਰ ਸਕਦੀ ਹੈ।"</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"ਹਮੇਸ਼ਾ  ਦਿਖਾਓ"</string>
     <string name="smv_application" msgid="3307209192155442829">"ਐਪ <xliff:g id="APPLICATION">%1$s</xliff:g> (ਪ੍ਰਕਿਰਿਆ <xliff:g id="PROCESS">%2$s</xliff:g>) ਨੇ ਆਪਣੀ ਖੁਦ-ਲਾਗੂ ਕੀਤੀ ਸਟ੍ਰਿਕਟਮੋਡ ਨੀਤੀ ਦੀ ਉਲੰਘਣਾ ਕੀਤੀ ਹੈ।"</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"ਸੰਕਟਕਾਲੀਨ ਸੰਦੇਸ਼ ਟੈਸਟ"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"ਜਵਾਬ ਦਿਓ"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM ਦੀ ਵਿਵਸਥਾ ਨਹੀਂ ਹੈ"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"ਫ਼ੋਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"ਪੌਪਅੱਪ ਵਿੰਡੋ"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"ਪੌਪਅੱਪ ਵਿੰਡੋ"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"ਇਸ ਸ਼ਾਰਟਕੱਟ ਨੂੰ ਨਵੀਨਤਮ ਐਪ ਦੀ ਲੋੜ ਹੈ"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"ਸ਼ਾਰਟਕੱਟ ਮੁੜ-ਬਹਾਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ ਕਿਉਂਕਿ ਐਪ \'ਬੈਕਅੱਪ ਅਤੇ ਮੁੜ-ਬਹਾਲੀ\' ਨਾਲ ਕੰਮ ਨਹੀਂ ਕਰਦੀ"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"ਐਪ ਹਸਤਾਖਰ ਦਾ ਮੇਲ ਨਾ ਹੋਣ ਕਾਰਨ ਸ਼ਾਰਟਕੱਟ ਮੁੜ-ਬਹਾਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"ਸ਼ਾਰਟਕੱਟ ਮੁੜ-ਬਹਾਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"</string>
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 5904abd..cc6cdc9 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -255,6 +255,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alerty"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Tryb demo dla sklepów"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Połączenie USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Działa aplikacja"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Aplikacje zużywające baterię"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> zużywa baterię"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"Liczba aplikacji zużywających baterię: <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
@@ -1018,11 +1019,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Sposób wprowadzania tekstu"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Działania na tekście"</string>
     <string name="email" msgid="4560673117055050403">"E-mail"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefon"</string>
-    <string name="map" msgid="6068210738233985748">"Mapy"</string>
-    <string name="browse" msgid="6993590095938149861">"Internet"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Kontakt"</string>
+    <string name="dial" msgid="1253998302767701559">"Zadzwoń"</string>
+    <string name="map" msgid="6521159124535543457">"Zlokalizuj"</string>
+    <string name="browse" msgid="1245903488306147205">"Otwórz"</string>
+    <string name="sms" msgid="4560537514610063430">"Wyślij SMS-a"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Dodaj"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Kończy się miejsce"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Niektóre funkcje systemu mogą nie działać"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Za mało pamięci w systemie. Upewnij się, że masz 250 MB wolnego miejsca i uruchom urządzenie ponownie."</string>
@@ -1032,7 +1033,6 @@
     <string name="cancel" msgid="6442560571259935130">"Anuluj"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Anuluj"</string>
-    <string name="close" msgid="2318214661230355730">"ZAMKNIJ"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Uwaga"</string>
     <string name="loading" msgid="7933681260296021180">"Wczytuję…"</string>
     <string name="capital_on" msgid="1544682755514494298">"Wł."</string>
@@ -1089,8 +1089,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skala"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Zawsze pokazuj"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Włącz ponownie, wybierając Ustawienia systemowe &gt; Aplikacje &gt; Pobrane."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikacja nie reaguje"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> może wykorzystywać za dużo pamięci"</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> nie obsługuje obecnie ustawionego rozmiaru wyświetlacza i może działać niestabilnie."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Zawsze pokazuj"</string>
     <string name="smv_application" msgid="3307209192155442829">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) naruszyła wymuszone przez siebie zasady StrictMode."</string>
@@ -1854,11 +1852,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test komunikatów alarmowych"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Odpowiedz"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"Niedozwolona karta SIM"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Nieobsługiwana karta SIM"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"Niedozwolona karta SIM"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Niedozwolony telefon"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Wyskakujące okienko"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Wyskakujące okienko"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Ten skrót wymaga zainstalowania najnowszej wersji aplikacji"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Nie można przywrócić skrótu, bo aplikacja nie obsługuje tworzenia i przywracania kopii zapasowej"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Nie można przywrócić skrótu z powodu niezgodności podpisu aplikacji"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Nie można przywrócić skrótu"</string>
 </resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 23b0eef..d088cdd 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demonstração na loja"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Conexão USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"App em execução"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Apps que estão consumindo a bateria"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está consumindo a bateria"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> apps estão consumindo a bateria"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Método de entrada"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Ações de texto"</string>
     <string name="email" msgid="4560673117055050403">"E-mail"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefone"</string>
-    <string name="map" msgid="6068210738233985748">"Mapas"</string>
-    <string name="browse" msgid="6993590095938149861">"Navegador"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Contato"</string>
+    <string name="dial" msgid="1253998302767701559">"Ligar"</string>
+    <string name="map" msgid="6521159124535543457">"Localizar"</string>
+    <string name="browse" msgid="1245903488306147205">"Abrir"</string>
+    <string name="sms" msgid="4560537514610063430">"Mensagem"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Adicionar"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Pouco espaço de armazenamento"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Algumas funções do sistema podem não funcionar"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Não há armazenamento suficiente para o sistema. Certifique-se de ter 250 MB de espaço livre e reinicie."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Cancelar"</string>
-    <string name="close" msgid="2318214661230355730">"FECHAR"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Atenção"</string>
     <string name="loading" msgid="7933681260296021180">"Carregando…"</string>
     <string name="capital_on" msgid="1544682755514494298">"LIG"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar sempre"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reativar isso em Configurações do sistema &gt; Apps &gt; Transferidos."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"O app não está respondendo"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> pode estar usando muita memória."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com a configuração atual de tamanho de exibição e pode se comportar de forma inesperada."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar sempre"</string>
     <string name="smv_application" msgid="3307209192155442829">"O app <xliff:g id="APPLICATION">%1$s</xliff:g>, processo <xliff:g id="PROCESS">%2$s</xliff:g>, violou a política StrictMode imposta automaticamente."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Teste de mensagens de emergência"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Responder"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM não permitido"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM não aprovisionado"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM não permitido"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Smartphone não permitido"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Janela pop-up"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Janela pop-up"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"Mais <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Esse atalho requer o app mais recente"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Não foi possível restaurar o atalho porque o app não é compatível com backup e restauração"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Não foi possível restaurar o atalho devido à incompatibilidade de assinatura de apps"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Não foi possível restaurar o atalho"</string>
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 141c8f090..afa28dd 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demonstração para retalho"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Ligação USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Aplicação em execução"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Aplicações que estão a consumir bateria"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"A aplicação <xliff:g id="APP_NAME">%1$s</xliff:g> está a consumir bateria."</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> aplicações estão a consumir bateria."</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Método de entrada"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Acções de texto"</string>
     <string name="email" msgid="4560673117055050403">"Email"</string>
-    <string name="dial" msgid="4204975095406423102">"Telemóvel"</string>
-    <string name="map" msgid="6068210738233985748">"Mapas"</string>
-    <string name="browse" msgid="6993590095938149861">"Navegador"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Contacto"</string>
+    <string name="dial" msgid="1253998302767701559">"Telefonar"</string>
+    <string name="map" msgid="6521159124535543457">"Localizar"</string>
+    <string name="browse" msgid="1245903488306147205">"Abrir"</string>
+    <string name="sms" msgid="4560537514610063430">"Mensagem"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Adicionar"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Está quase sem espaço de armazenamento"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Algumas funções do sistema poderão não funcionar"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Não existe armazenamento suficiente para o sistema. Certifique-se de que tem 250 MB de espaço livre e reinicie."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Cancelar"</string>
-    <string name="close" msgid="2318214661230355730">"FECHAR"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Atenção"</string>
     <string name="loading" msgid="7933681260296021180">"A carregar…"</string>
     <string name="capital_on" msgid="1544682755514494298">"Ativado"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar sempre"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reative este modo nas Definições do Sistema &gt; Aplicações &gt; Transferidas."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"A aplicação não está a responder"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"A aplicação <xliff:g id="APP_NAME">%1$s</xliff:g> pode estar a utilizar demasiada memória."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> não suporta a definição de Tamanho do ecrã atual e pode ter um comportamento inesperado."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar sempre"</string>
     <string name="smv_application" msgid="3307209192155442829">"A aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) violou a política StrictMode auto-imposta."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Teste de mensagens de emergência"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Responder"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM não permitido"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM não ativado"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM não permitido"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Telemóvel não permitido"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Janela pop-up"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Janela pop-up"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Este atalho requer a aplicação mais recente."</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Não foi possível restaurar o atalho porque a aplicação não é compatível com a funcionalidade de cópia de segurança e restauro."</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Não foi possível restaurar o atalho devido a uma falha de correspondência entre as assinaturas das aplicações."</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Não foi possível restaurar o atalho."</string>
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 23b0eef..d088cdd 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demonstração na loja"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Conexão USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"App em execução"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Apps que estão consumindo a bateria"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está consumindo a bateria"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> apps estão consumindo a bateria"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Método de entrada"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Ações de texto"</string>
     <string name="email" msgid="4560673117055050403">"E-mail"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefone"</string>
-    <string name="map" msgid="6068210738233985748">"Mapas"</string>
-    <string name="browse" msgid="6993590095938149861">"Navegador"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Contato"</string>
+    <string name="dial" msgid="1253998302767701559">"Ligar"</string>
+    <string name="map" msgid="6521159124535543457">"Localizar"</string>
+    <string name="browse" msgid="1245903488306147205">"Abrir"</string>
+    <string name="sms" msgid="4560537514610063430">"Mensagem"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Adicionar"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Pouco espaço de armazenamento"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Algumas funções do sistema podem não funcionar"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Não há armazenamento suficiente para o sistema. Certifique-se de ter 250 MB de espaço livre e reinicie."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Cancelar"</string>
-    <string name="close" msgid="2318214661230355730">"FECHAR"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Atenção"</string>
     <string name="loading" msgid="7933681260296021180">"Carregando…"</string>
     <string name="capital_on" msgid="1544682755514494298">"LIG"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar sempre"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reativar isso em Configurações do sistema &gt; Apps &gt; Transferidos."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"O app não está respondendo"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> pode estar usando muita memória."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com a configuração atual de tamanho de exibição e pode se comportar de forma inesperada."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Mostrar sempre"</string>
     <string name="smv_application" msgid="3307209192155442829">"O app <xliff:g id="APPLICATION">%1$s</xliff:g>, processo <xliff:g id="PROCESS">%2$s</xliff:g>, violou a política StrictMode imposta automaticamente."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Teste de mensagens de emergência"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Responder"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM não permitido"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM não aprovisionado"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM não permitido"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Smartphone não permitido"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Janela pop-up"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Janela pop-up"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"Mais <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Esse atalho requer o app mais recente"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Não foi possível restaurar o atalho porque o app não é compatível com backup e restauração"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Não foi possível restaurar o atalho devido à incompatibilidade de assinatura de apps"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Não foi possível restaurar o atalho"</string>
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 7cf8b1a..0afa413 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -252,6 +252,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alerte"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demonstrație comercială"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Conexiune USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Aplicația rulează"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Aplicațiile consumă bateria"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> folosește bateria"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> aplicații folosesc bateria"</string>
@@ -998,11 +999,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Metodă de intrare"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Acțiuni pentru text"</string>
     <string name="email" msgid="4560673117055050403">"E-mail"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefon"</string>
-    <string name="map" msgid="6068210738233985748">"Hărți"</string>
-    <string name="browse" msgid="6993590095938149861">"Browser"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Persoană de contact"</string>
+    <string name="dial" msgid="1253998302767701559">"Apelați"</string>
+    <string name="map" msgid="6521159124535543457">"Localizați"</string>
+    <string name="browse" msgid="1245903488306147205">"Deschideți"</string>
+    <string name="sms" msgid="4560537514610063430">"Mesaj"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Adăugați"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Spațiul de stocare aproape ocupat"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Este posibil ca unele funcții de sistem să nu funcționeze"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Spațiu de stocare insuficient pentru sistem. Asigurați-vă că aveți 250 MB de spațiu liber și reporniți."</string>
@@ -1012,7 +1013,6 @@
     <string name="cancel" msgid="6442560571259935130">"Anulați"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Anulați"</string>
-    <string name="close" msgid="2318214661230355730">"ÎNCHIDEȚI"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Atenție"</string>
     <string name="loading" msgid="7933681260296021180">"Se încarcă…"</string>
     <string name="capital_on" msgid="1544682755514494298">"DA"</string>
@@ -1069,8 +1069,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scară"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Afișați întotdeauna"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reactivați acest mod din Setări de sistem &gt; Aplicații &gt; Descărcate."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Aplicația nu răspunde"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"Este posibil ca <xliff:g id="APP_NAME">%1$s</xliff:g> să utilizeze prea multă memorie."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu acceptă setarea actuală pentru Dimensiunea afișării și este posibil să aibă un comportament neașteptat."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Afișează întotdeauna"</string>
     <string name="smv_application" msgid="3307209192155442829">"Aplicația <xliff:g id="APPLICATION">%1$s</xliff:g> (procesul <xliff:g id="PROCESS">%2$s</xliff:g>) a încălcat propria politică StrictMode."</string>
@@ -1819,11 +1817,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Testarea mesajelor de urgență"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Răspundeți"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"Cardul SIM nu este permis"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Cardul SIM nu este activat"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"Cardul SIM nu este permis"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Telefonul nu este permis"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Fereastră pop-up"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Fereastră pop-up"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Această comandă rapidă necesită cea mai recentă aplicație"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Nu s-a putut restabili comanda rapidă deoarece aplicația nu acceptă backupul și restabilirea"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Nu s-a putut restabili comanda rapidă din cauza nepotrivirii semnăturii aplicației"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Nu s-a putut restabili comanda rapidă"</string>
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index b8267c3..fc9298c 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -255,6 +255,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Уведомления"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Деморежим для магазина"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-подключение"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Приложение активно"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Приложения, расходующие заряд"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" расходует заряд"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"Несколько приложений (<xliff:g id="NUMBER">%1$d</xliff:g>) расходуют заряд"</string>
@@ -1018,11 +1019,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Способ ввода"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Операции с текстом"</string>
     <string name="email" msgid="4560673117055050403">"Письмо"</string>
-    <string name="dial" msgid="4204975095406423102">"Телефон"</string>
-    <string name="map" msgid="6068210738233985748">"Карты"</string>
-    <string name="browse" msgid="6993590095938149861">"Браузер"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Контакт"</string>
+    <string name="dial" msgid="1253998302767701559">"Позвонить"</string>
+    <string name="map" msgid="6521159124535543457">"Найти на карте"</string>
+    <string name="browse" msgid="1245903488306147205">"Открыть"</string>
+    <string name="sms" msgid="4560537514610063430">"Написать SMS"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Добавить"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Недостаточно памяти"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Некоторые функции могут не работать"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Недостаточно свободного места для системы. Освободите не менее 250 МБ дискового пространства и перезапустите устройство."</string>
@@ -1032,7 +1033,6 @@
     <string name="cancel" msgid="6442560571259935130">"Отмена"</string>
     <string name="yes" msgid="5362982303337969312">"ОК"</string>
     <string name="no" msgid="5141531044935541497">"Отмена"</string>
-    <string name="close" msgid="2318214661230355730">"ЗАКРЫТЬ"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Внимание"</string>
     <string name="loading" msgid="7933681260296021180">"Загрузка…"</string>
     <string name="capital_on" msgid="1544682755514494298">"I"</string>
@@ -1089,8 +1089,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Масштаб"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Всегда показывать"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Включить эту функцию можно в меню \"Настройки &gt; Приложения &gt; Загруженные\"."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Приложение не отвечает"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"Возможно, приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" использует слишком много памяти."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" не поддерживает выбранный масштаб изображения на экране и может работать некорректно."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Всегда показывать"</string>
     <string name="smv_application" msgid="3307209192155442829">"Приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" (процесс: <xliff:g id="PROCESS">%2$s</xliff:g>) нарушило собственную политику StrictMode."</string>
@@ -1854,11 +1852,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Тестовое экстренное сообщение"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Ответить"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"Использование SIM-карты запрещено"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM-карта не активирована"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"Использование SIM-карты запрещено"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Звонки запрещены"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Всплывающее окно"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Всплывающее окно"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Требуется последняя версия приложения"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Не удалось восстановить ярлык: приложение не поддерживает резервное копирование"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Не удалось восстановить ярлык: некорректная подпись приложения"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Не удалось восстановить ярлык"</string>
 </resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index bb9e6ec..9eff25e 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"ඇඟවීම්"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"සිල්ලර ආදර්ශනය"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB සම්බන්ධතාවය"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"යෙදුම ධාවනය කරමින්"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"බැටරිය භාවිත කරන යෙදුම්"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> බැටරිය භාවිත කරයි"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"යෙදුම් <xliff:g id="NUMBER">%1$d</xliff:g>ක් බැටරිය භාවිත කරයි"</string>
@@ -980,11 +981,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"ආදාන ක්‍රමය"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"පෙළ ක්‍රියාවන්"</string>
     <string name="email" msgid="4560673117055050403">"ඊ-තැපෑල"</string>
-    <string name="dial" msgid="4204975095406423102">"දුරකථනය"</string>
-    <string name="map" msgid="6068210738233985748">"සිතියම්"</string>
-    <string name="browse" msgid="6993590095938149861">"බ්‍රවුසරය"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"සම්බන්ධතා"</string>
+    <string name="dial" msgid="1253998302767701559">"අමතන්න"</string>
+    <string name="map" msgid="6521159124535543457">"ස්ථානගත කරන්න"</string>
+    <string name="browse" msgid="1245903488306147205">"විවෘත කරන්න"</string>
+    <string name="sms" msgid="4560537514610063430">"පණිවිඩය"</string>
+    <string name="add_contact" msgid="7867066569670597203">"එක් කරන්න"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"ආචයනය ඉඩ ප්‍රමාණය අඩු වී ඇත"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"සමහර පද්ධති කාර්යයන් ක්‍රියා නොකරනු ඇත"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"පද්ධතිය සඳහා ප්‍රමාණවත් ඉඩ නොමැත. ඔබට 250MB නිදහස් ඉඩක් තිබෙන ඔබට තිබෙන බව සහතික කරගෙන නැවත උත්සාහ කරන්න."</string>
@@ -994,7 +995,6 @@
     <string name="cancel" msgid="6442560571259935130">"අවලංගු කරන්න"</string>
     <string name="yes" msgid="5362982303337969312">"හරි"</string>
     <string name="no" msgid="5141531044935541497">"අවලංගු කරන්න"</string>
-    <string name="close" msgid="2318214661230355730">"වසන්න"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"අවධානය"</string>
     <string name="loading" msgid="7933681260296021180">"පූරණය වෙමින්..."</string>
     <string name="capital_on" msgid="1544682755514494298">"සක්‍රීයයි"</string>
@@ -1051,8 +1051,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"පරිමාණය"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"සැමවිටම පෙන්වන්න"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"පද්ධති සැකසීම් තුළ මෙය නැවත ක්‍රියාත්මක කරන්න &gt; යෙදුම් &gt; බාගන්නා ලදි."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"යෙදුම ප්‍රතිචාර නොදක්වයි"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> මතකය ඉතා වැඩියෙන් භාවිත කරනවා විය හැකිය."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> වත්මන් සංදර්ශක තරම සඳහා සහාය නොදක්වන අතර අනපේක්ෂිත ලෙස හැසිරීමට හැකිය."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"සැම විටම පෙන්වන්න"</string>
     <string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> යෙදුම (<xliff:g id="PROCESS">%2$s</xliff:g> ක්‍රියාවලිය) එහි StrictMode කොන්දේසිය උල්ලංඝනය කර ඇත."</string>
@@ -1786,11 +1784,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"හදිසි පණිවිඩ පරීක්ෂණය"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"පිළිතුරු දෙන්න"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM එක සඳහා ඉඩ නොදේ"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM එක සක්‍රීය කර නොමැත"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM එක සඳහා ඉඩ නොදේ"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"දුරකථනය සඳහා ඉඩ නොදේ"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"උත්පතන කවුළුව"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"උත්පතන කවුළුව"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"මෙම කෙටි මගට නවතම යෙදුම අවශ්‍යයි"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"යෙදුම උපස්ථ සහ ප්‍රතිසාධනය සඳහා සහාය නොදක්වන බැවින් කෙටි මග ප්‍රතිසාධනය කළ නොහැකි විය"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"යෙදුම් අත්සන නොගැළපෙන බැවින් කෙටි මග ප්‍රතිසාධනය කළ නොහැකි විය"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"කෙටි මග ප්‍රතිසාධනය කළ නොහැකි විය"</string>
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 8646e95..9dacc7b 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -255,6 +255,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Upozornenia"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Predajná ukážka"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Pripojenie USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Aplikácia je spustená"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Aplikácie spotrebúvajú batériu"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> používa batériu"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"Aplikácie (<xliff:g id="NUMBER">%1$d</xliff:g>) používajú batériu"</string>
@@ -1018,11 +1019,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Metóda vstupu"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Operácie s textom"</string>
     <string name="email" msgid="4560673117055050403">"E-mail"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefón"</string>
-    <string name="map" msgid="6068210738233985748">"Mapy"</string>
-    <string name="browse" msgid="6993590095938149861">"Prehliadač"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Kontakt"</string>
+    <string name="dial" msgid="1253998302767701559">"Volať"</string>
+    <string name="map" msgid="6521159124535543457">"Nájsť"</string>
+    <string name="browse" msgid="1245903488306147205">"Otvoriť"</string>
+    <string name="sms" msgid="4560537514610063430">"Správa"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Pridať"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nedostatok ukladacieho priestoru"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Niektoré systémové funkcie nemusia fungovať"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"V úložisku nie je dostatok voľného miesta pre systém. Zaistite, aby ste mali 250 MB voľného miesta a zariadenie reštartujte."</string>
@@ -1032,7 +1033,6 @@
     <string name="cancel" msgid="6442560571259935130">"Zrušiť"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Zrušiť"</string>
-    <string name="close" msgid="2318214661230355730">"ZAVRIEŤ"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Upozornenie"</string>
     <string name="loading" msgid="7933681260296021180">"Načítava sa…"</string>
     <string name="capital_on" msgid="1544682755514494298">"I"</string>
@@ -1089,8 +1089,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Prispôsobiť veľkosť"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Vždy zobraziť"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Povoľte to znova v sekcii Nastavenia systému &gt; Aplikácie &gt; Stiahnuté súbory."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikácia nereaguje"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> pravdepodobne používa príliš veľa pamäte."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> aktuálne nastavenie veľkosti zobrazenia nepodporuje a môže sa správať neočakávane."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Vždy zobrazovať"</string>
     <string name="smv_application" msgid="3307209192155442829">"Aplikácia <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) porušila svoje vlastné vynútené pravidlá StrictMode."</string>
@@ -1854,11 +1852,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test tiesňových správ"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Odpovedať"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM karta je zakázaná"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM karta nie je k dispozícii"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM karta je zakázaná"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Telefón je zakázaný"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Automaticky otvárané okno"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Automaticky otvárané okno"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Tento odkaz vyžaduje najnovšiu aplikáciu"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Odkaz sa nepodarilo obnoviť, pretože aplikácia nepodporuje zálohovanie a obnovu"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Odkaz sa nepodarilo obnoviť pre nesúlad podpisov aplikácie"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Odkaz sa nepodarilo obnoviť"</string>
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index da2a261..722e88e 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -255,6 +255,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Opozorila"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Predstavitev za maloprodajo"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Povezava USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Aplikacija se izvaja"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Aplikacije, ki porabljajo energijo akumulatorja"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> porablja energijo akumulatorja"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"Toliko aplikacij porablja energijo akumulatorja: <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
@@ -1018,11 +1019,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Način vnosa"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Besedilna dejanja"</string>
     <string name="email" msgid="4560673117055050403">"E-pošta"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefon"</string>
-    <string name="map" msgid="6068210738233985748">"Zemljevidi"</string>
-    <string name="browse" msgid="6993590095938149861">"Brskalnik"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Stik"</string>
+    <string name="dial" msgid="1253998302767701559">"Pokliči"</string>
+    <string name="map" msgid="6521159124535543457">"Poišči na zemljevidu"</string>
+    <string name="browse" msgid="1245903488306147205">"Odpri"</string>
+    <string name="sms" msgid="4560537514610063430">"Sporočilo"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Dodaj"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Prostor za shranjevanje bo pošel"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Nekatere sistemske funkcije morda ne delujejo"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"V shrambi ni dovolj prostora za sistem. Sprostite 250 MB prostora in znova zaženite napravo."</string>
@@ -1032,7 +1033,6 @@
     <string name="cancel" msgid="6442560571259935130">"Prekliči"</string>
     <string name="yes" msgid="5362982303337969312">"V redu"</string>
     <string name="no" msgid="5141531044935541497">"Prekliči"</string>
-    <string name="close" msgid="2318214661230355730">"ZAPRI"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Pozor"</string>
     <string name="loading" msgid="7933681260296021180">"Nalaganje …"</string>
     <string name="capital_on" msgid="1544682755514494298">"VKLOPLJENO"</string>
@@ -1089,8 +1089,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Lestvica"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Vedno pokaži"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Znova omogočite to v sistemskih nastavitvah &gt; Aplikacije &gt; Preneseno."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikacija se ne odziva"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> morda uporablja preveč pomnilnika."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podpira trenutne nastavitve velikosti zaslona, kar lahko vodi v nepričakovano delovanje."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Vedno pokaži"</string>
     <string name="smv_application" msgid="3307209192155442829">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) krši svoj samouveljavljiv pravilnik o strogem načinu."</string>
@@ -1854,11 +1852,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Preskus sporočil v sili"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Odgovor"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"Kartica SIM ni dovoljena"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Kartica SIM ni omogočena za uporabo"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"Kartica SIM ni dovoljena"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Telefon ni dovoljen"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Pojavno okno"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Pojavno okno"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"in še <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Za to bližnjico potrebujete najnovejšo aplikacijo"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Bližnjice ni bilo mogoče obnoviti, ker aplikacija ne podpira varnostnega kopiranja in obnavljanja"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Bližnjice ni bilo mogoče obnoviti zaradi neujemanja podpisa aplikacije"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Bližnjice ni bilo mogoče obnoviti"</string>
 </resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 0669d4c..1682557 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Sinjalizimet"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demonstrimi i shitjes me pakicë"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Lidhja USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Aplikacioni është në ekzekutim"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Aplikacionet që konsumojnë baterinë"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> po përdor baterinë"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> aplikacione po përdorin baterinë"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Metoda e hyrjes"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Veprimet e tekstit"</string>
     <string name="email" msgid="4560673117055050403">"Dërgo mail"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefoni"</string>
-    <string name="map" msgid="6068210738233985748">"Hartat"</string>
-    <string name="browse" msgid="6993590095938149861">"Shfletuesi"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Kontakti"</string>
+    <string name="dial" msgid="1253998302767701559">"Telefono"</string>
+    <string name="map" msgid="6521159124535543457">"Gjej vendndodhjen"</string>
+    <string name="browse" msgid="1245903488306147205">"Hap"</string>
+    <string name="sms" msgid="4560537514610063430">"Mesazh"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Shto"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Hapësira ruajtëse po mbaron"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Disa funksione të sistemit mund të mos punojnë"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nuk ka hapësirë të mjaftueshme ruajtjeje për sistemin. Sigurohu që të kesh 250 MB hapësirë të lirë dhe pastaj të rifillosh."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Anulo"</string>
     <string name="yes" msgid="5362982303337969312">"Në rregull"</string>
     <string name="no" msgid="5141531044935541497">"Anulo"</string>
-    <string name="close" msgid="2318214661230355730">"MBYLL"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Kujdes!"</string>
     <string name="loading" msgid="7933681260296021180">"Po ngarkohet..."</string>
     <string name="capital_on" msgid="1544682755514494298">"Aktivizuar"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Shkalla"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Shfaq gjithnjë"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktivizoje sërish këtë te \"Cilësimet e sistemit\" &gt; \"Aplikacionet\" &gt; \"Të shkarkuara\"."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Aplikacioni nuk po përgjigjet"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> mund të jetë duke përdorur shumë memorie."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk mbështet cilësimin aktual të madhësisë së ekranit dhe mund të shfaqë sjellje të papritura."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Shfaq gjithmonë"</string>
     <string name="smv_application" msgid="3307209192155442829">"Aplikacioni <xliff:g id="APPLICATION">%1$s</xliff:g> (procesi <xliff:g id="PROCESS">%2$s</xliff:g>) ka shkelur politikën e tij të vetë-imponuar \"Modaliteti i ashpër\" (StrictMode)."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Testim për mesazhet e urgjencës"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Përgjigju"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"Karta SIM nuk lejohet"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Karta SIM nuk është dhënë"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"Karta SIM nuk lejohet"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Telefoni nuk lejohet"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Dritare kërcyese"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Dritare kërcyese"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Kjo shkurtore kërkon aplikacionin më të fundit"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Nuk mund të restaurohej shkurtorja sepse aplikacioni nuk mbështet rezervimin dhe restaurimin"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Nuk mund të restaurohej shkurtorja për shkak të mospërputhjes së nënshkrimit të aplikacionit"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Nuk mund të restaurohej shkurtorja"</string>
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 26d7a298..2dd1d1a 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -252,6 +252,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Обавештења"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Режим демонстрације за малопродајне објекте"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB веза"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Апликација је покренута"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Апликације које троше батерију"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> користи батерију"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"Апликације (<xliff:g id="NUMBER">%1$d</xliff:g>) користе батерију"</string>
@@ -998,11 +999,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Метод уноса"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Радње у вези са текстом"</string>
     <string name="email" msgid="4560673117055050403">"Пошаљи имејл"</string>
-    <string name="dial" msgid="4204975095406423102">"Позови"</string>
-    <string name="map" msgid="6068210738233985748">"Мапе"</string>
-    <string name="browse" msgid="6993590095938149861">"Прегледач"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Контакт"</string>
+    <string name="dial" msgid="1253998302767701559">"Позови"</string>
+    <string name="map" msgid="6521159124535543457">"Пронађи"</string>
+    <string name="browse" msgid="1245903488306147205">"Отвори"</string>
+    <string name="sms" msgid="4560537514610063430">"Пошаљи SMS"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Додај"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Меморијски простор је на измаку"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Неке системске функције можда не функционишу"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Нема довољно меморијског простора за систем. Уверите се да имате 250 MB слободног простора и поново покрените."</string>
@@ -1012,7 +1013,6 @@
     <string name="cancel" msgid="6442560571259935130">"Откажи"</string>
     <string name="yes" msgid="5362982303337969312">"Потврди"</string>
     <string name="no" msgid="5141531044935541497">"Откажи"</string>
-    <string name="close" msgid="2318214661230355730">"ЗАТВОРИ"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Пажња"</string>
     <string name="loading" msgid="7933681260296021180">"Учитава се…"</string>
     <string name="capital_on" msgid="1544682755514494298">"ДА"</string>
@@ -1069,8 +1069,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Размера"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Увек приказуј"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Поново омогућите у менију Системска подешавања &gt; Апликације &gt; Преузето."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Апликација не реагује"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> можда користи превише меморије."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> не подржава тренутно подешавање величине приказа и може да се понаша неочекивано."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Увек приказуј"</string>
     <string name="smv_application" msgid="3307209192155442829">"Апликација <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) је прекршила самонаметнуте StrictMode смернице."</string>
@@ -1819,11 +1817,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Тестирање порука у хитним случајевима"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Одговори"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM картица није дозвољена"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM картица није подешена"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM картица није дозвољена"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Телефон није дозвољен"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Искачући прозор"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Искачући прозор"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"и још <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Ова пречица захтева најновију апликацију"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Враћање пречице није успело јер апликација не подржава прављење резервне копије и враћање"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Враћање пречице није успело јер се потписи апликација не подударају"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Враћање пречице није успело"</string>
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 5b3fdf6..cd5ec95 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Varningar"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demo för återförsäljare"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-anslutning"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"App körs"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Appar som drar batteri"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> drar batteri"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> appar drar batteri"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Indatametod"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Textåtgärder"</string>
     <string name="email" msgid="4560673117055050403">"Skicka e-post"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefon"</string>
-    <string name="map" msgid="6068210738233985748">"Kartor"</string>
-    <string name="browse" msgid="6993590095938149861">"Webbläsare"</string>
-    <string name="sms" msgid="8250353543787396737">"Sms"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Kontakt"</string>
+    <string name="dial" msgid="1253998302767701559">"Ring"</string>
+    <string name="map" msgid="6521159124535543457">"Hitta"</string>
+    <string name="browse" msgid="1245903488306147205">"Öppna"</string>
+    <string name="sms" msgid="4560537514610063430">"Sms:a"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Lägg till"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Lagringsutrymmet börjar ta slut"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Det kan hända att vissa systemfunktioner inte fungerar"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Det finns inte tillräckligt med utrymme för systemet. Kontrollera att du har ett lagringsutrymme på minst 250 MB och starta om."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Avbryt"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Avbryt"</string>
-    <string name="close" msgid="2318214661230355730">"STÄNG"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Obs!"</string>
     <string name="loading" msgid="7933681260296021180">"Läser in …"</string>
     <string name="capital_on" msgid="1544682755514494298">"PÅ"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Anpassning"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Visa alltid"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Aktivera detta igen i Systeminställningar &gt; Appar &gt; Hämtat."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Appen svarar inte"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> kanske använder för mycket minne."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> har inte stöd för den nuvarande inställningen för skärmstorlek och kanske inte fungerar som förväntat."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Visa alltid"</string>
     <string name="smv_application" msgid="3307209192155442829">"Appen <xliff:g id="APPLICATION">%1$s</xliff:g> (processen <xliff:g id="PROCESS">%2$s</xliff:g>) har brutit mot sin egen StrictMode-policy."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test för nödmeddelanden"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Svara"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM-kort tillåts inte"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM-kort tillhandahålls inte"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM-kort tillåts inte"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Mobil tillåts inte"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"popup-fönster"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"popup-fönster"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"<xliff:g id="NUMBER">%1$d</xliff:g> till"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Den här genvägen kräver den senaste versionen av appen"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Det gick inte att återställa genvägen eftersom appen inte har stöd för säkerhetskopiering och återställning"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Det gick inte att återställa genvägen eftersom appens signatur inte stämmer"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Det gick inte att återställa genvägen"</string>
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 78fc186..0eaaf91 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -247,6 +247,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Arifa"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Onyesho la duka la rejareja"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Muunganisho wa USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Programu inaendelea kutekelezwa"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Programu zinazotumia betri"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> inatumia betri"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"Programu <xliff:g id="NUMBER">%1$d</xliff:g> zinatumia betri"</string>
@@ -296,7 +297,7 @@
     <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Ishara za alama ya kidole"</string>
     <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Inaweza kurekodi ishara zinazotekelezwa kwenye kitambua alama ya kidole."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"zima au rekebisha mwambaa hali"</string>
-    <string name="permdesc_statusBar" msgid="8434669549504290975">"Inaruhusu programu kulemaza upau wa hali au kuongeza na kutoa ikoni za mfumo."</string>
+    <string name="permdesc_statusBar" msgid="8434669549504290975">"Inaruhusu programu kulemaza upau wa hali au kuongeza na kutoa aikoni za mfumo."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"kuwa sehemu ya arifa"</string>
     <string name="permdesc_statusBarService" msgid="716113660795976060">"Inaruhusu programu kuwa upau wa hali."</string>
     <string name="permlab_expandStatusBar" msgid="1148198785937489264">"panua/kunja mwambaa hali"</string>
@@ -976,11 +977,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Mbinu ya uingizaji"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Vitendo vya maandishi"</string>
     <string name="email" msgid="4560673117055050403">"Barua pepe"</string>
-    <string name="dial" msgid="4204975095406423102">"Simu"</string>
-    <string name="map" msgid="6068210738233985748">"Ramani"</string>
-    <string name="browse" msgid="6993590095938149861">"Kivinjari"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Anwani"</string>
+    <string name="dial" msgid="1253998302767701559">"Simu"</string>
+    <string name="map" msgid="6521159124535543457">"Tafuta"</string>
+    <string name="browse" msgid="1245903488306147205">"Fungua"</string>
+    <string name="sms" msgid="4560537514610063430">"Ujumbe"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Ongeza"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nafasi ya kuhifadhi inakaribia kujaa"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Baadhi ya vipengee vya mfumo huenda visifanye kazi"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Hifadhi haitoshi kwa ajili ya mfumo. Hakikisha una MB 250 za nafasi ya hifadhi isiyotumika na uanzishe upya."</string>
@@ -990,7 +991,6 @@
     <string name="cancel" msgid="6442560571259935130">"Ghairi"</string>
     <string name="yes" msgid="5362982303337969312">"Sawa"</string>
     <string name="no" msgid="5141531044935541497">"Ghairi"</string>
-    <string name="close" msgid="2318214661230355730">"FUNGA"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Zingatia"</string>
     <string name="loading" msgid="7933681260296021180">"Inapakia…"</string>
     <string name="capital_on" msgid="1544682755514494298">"Washa"</string>
@@ -1047,8 +1047,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Kipimo"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Onyesha kila wakati"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Wezesha tena hii katika mipangilio ya Mfumo &gt; Programu &gt;  iliyopakuliwa."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Programu haifanyi kazi"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"Huenda <xliff:g id="APP_NAME">%1$s</xliff:g> inatumia hifadhi nyingi mno."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> haiwezi kutumia mipangilio ya sasa ya ukubwa wa Skrini na huenda isifanye kazi vizuri."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Onyesha kila wakati"</string>
     <string name="smv_application" msgid="3307209192155442829">"Programu <xliff:g id="APPLICATION">%1$s</xliff:g>  (utaratibu  <xliff:g id="PROCESS">%2$s</xliff:g>) imeenda kinyume na sera yake ya StrictMode."</string>
@@ -1072,7 +1070,7 @@
     <string name="new_app_action" msgid="5472756926945440706">"Anza <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Komesha programu ya zamani bila kuhifadhi."</string>
     <string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> imezidi kiwango cha hifadhi kinachotakikana"</string>
-    <string name="dump_heap_notification_detail" msgid="6901391084243999274">"Imezidi kikomo cha hifadhi; gonga ili uishiriki"</string>
+    <string name="dump_heap_notification_detail" msgid="6901391084243999274">"Imezidi kikomo cha hifadhi; gusa ili uishiriki"</string>
     <string name="dump_heap_title" msgid="5864292264307651673">"Ungependa kushiriki picha ya binafsi?"</string>
     <string name="dump_heap_text" msgid="4809417337240334941">"Mchakato wa <xliff:g id="PROC">%1$s</xliff:g> umezidi kiwango kinachotakikana cha hifadhi cha <xliff:g id="SIZE">%2$s</xliff:g>. Unaweza kupata picha ya hifadhi ili uishiriki na msadini programu wa picha. Tahadhari: picha hii ya hifadhi inaweza kuwa na maelezo yako ya binafsi ambayo yanaweza kufikiwa na programu."</string>
     <string name="sendText" msgid="5209874571959469142">"Chagua kitendo kwa ajili ya maandishi"</string>
@@ -1782,11 +1780,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Jaribio la ujumbe wa dharura"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Jibu"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM imekataliwa"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM haikubaliwi"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM imekataliwa"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Simu imekataliwa"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Dirisha Ibukizi"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Dirisha Ibukizi"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Njia hii ya mkato inahitaji toleo jipya la programu"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Imeshindwa kurejesha njia ya mkato kwa sababu programu haitumii kipengele cha hifadhi rudufu na kurejesha upya"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Imeshindwa kurejesha njia ya mkato kwa sababu ufunguo wako wa kuambatisha cheti kwenye programu haulingani"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Imeshindwa kurejesha njia ya mkato"</string>
 </resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 544d109..62b54d2 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"விழிப்பூட்டல்கள்"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"விற்பனையாளர் டெமோ"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB இணைப்பு"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"பயன்பாடு இயங்குகிறது"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"பேட்டரியைப் பயன்படுத்தும் பயன்பாடுகள்"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> பயன்பாடு பேட்டரியைப் பயன்படுத்துகிறது"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> பயன்பாடுகள் பேட்டரியைப் பயன்படுத்துகின்றன"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"உள்ளீட்டு முறை"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"உரை நடவடிக்கைகள்"</string>
     <string name="email" msgid="4560673117055050403">"மின்னஞ்சல்"</string>
-    <string name="dial" msgid="4204975095406423102">"ஃபோன்"</string>
-    <string name="map" msgid="6068210738233985748">"வரைபடம்"</string>
-    <string name="browse" msgid="6993590095938149861">"உலாவி"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"தொடர்பு"</string>
+    <string name="dial" msgid="1253998302767701559">"அழை"</string>
+    <string name="map" msgid="6521159124535543457">"கண்டுபிடி"</string>
+    <string name="browse" msgid="1245903488306147205">"திற"</string>
+    <string name="sms" msgid="4560537514610063430">"செய்தி"</string>
+    <string name="add_contact" msgid="7867066569670597203">"சேர்"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"சேமிப்பிடம் குறைகிறது"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"சில அமைப்பு செயல்பாடுகள் வேலை செய்யாமல் போகலாம்"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"முறைமையில் போதுமான சேமிப்பகம் இல்லை. 250மெ.பை. அளவு காலி இடவசதி இருப்பதை உறுதிசெய்து மீண்டும் தொடங்கவும்."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"ரத்துசெய்"</string>
     <string name="yes" msgid="5362982303337969312">"சரி"</string>
     <string name="no" msgid="5141531044935541497">"ரத்துசெய்"</string>
-    <string name="close" msgid="2318214661230355730">"மூடு"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"கவனத்திற்கு"</string>
     <string name="loading" msgid="7933681260296021180">"ஏற்றுகிறது..."</string>
     <string name="capital_on" msgid="1544682755514494298">"ஆன்"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"அளவு"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"எப்போதும் காட்டு"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"சிஸ்டம் அமைப்பு &gt; பயன்பாடுகள் &gt; பதிவிறக்கம் என்பதில் இதை மீண்டும் இயக்கவும்."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"பயன்பாடு செயல்படவில்லை"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> பயன்பாடு, அதிகளவு நினைவகத்தைப் பயன்படுத்தக்கூடும்."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"தற்போதைய திரை அளவு அமைப்பை <xliff:g id="APP_NAME">%1$s</xliff:g> ஆதரிக்காததால், அது வழக்கத்திற்கு மாறாகச் செயல்படக்கூடும்."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"எப்போதும் காட்டு"</string>
     <string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> பயன்பாடு (செயல்முறை <xliff:g id="PROCESS">%2$s</xliff:g>), தனது சுய-செயலாக்க StrictMode கொள்கையை மீறியது."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"அவசரக் காலச் செய்திகளுக்கான சோதனை"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"பதிலளிக்கும்"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"சிம் அனுமதிக்கப்படவில்லை"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"சிம் அமைக்கப்படவில்லை"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"சிம் அனுமதிக்கப்படவில்லை"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"ஃபோன் அனுமதிக்கப்படவில்லை"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"பாப்அப் சாளரம்"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"பாப்அப் சாளரம்"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"இந்த ஷார்ட்கட்டைப் பயன்படுத்த, சமீபத்திய பயன்பாடு வேண்டும்"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"காப்புப் பிரதி மற்றும் மீட்டமைவைப் பயன்பாடு ஆதரிக்காத காரணத்தால், ஷார்ட்கட்டை மீட்டமைக்க முடியவில்லை"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"பயன்பாட்டுச் சான்றுகள் பொருந்தாத காரணத்தினால், ஷார்ட்கட்டை மீட்டமைக்க முடியவில்லை"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"ஷார்ட்கட்டை மீட்டமைக்க முடியவில்லை"</string>
 </resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 75c37249..9b3b89b 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"హెచ్చరికలు"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"రిటైల్ డెమో"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB కనెక్షన్"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"యాప్ అమలవుతోంది"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"బ్యాటరీని ఉపయోగిస్తున్న యాప్‌లు"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> బ్యాటరీని ఉపయోగిస్తోంది"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> యాప్‌లు బ్యాటరీని ఉపయోగిస్తున్నాయి"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"ఇన్‌పుట్ పద్ధతి"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"వచనానికి సంబంధించిన చర్యలు"</string>
     <string name="email" msgid="4560673117055050403">"ఇమెయిల్"</string>
-    <string name="dial" msgid="4204975095406423102">"ఫోన్"</string>
-    <string name="map" msgid="6068210738233985748">"మ్యాప్స్"</string>
-    <string name="browse" msgid="6993590095938149861">"బ్రౌజర్"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"పరిచయం"</string>
+    <string name="dial" msgid="1253998302767701559">"కాల్ చేయండి"</string>
+    <string name="map" msgid="6521159124535543457">"గుర్తించండి"</string>
+    <string name="browse" msgid="1245903488306147205">"తెరవండి"</string>
+    <string name="sms" msgid="4560537514610063430">"సందేశం"</string>
+    <string name="add_contact" msgid="7867066569670597203">"జోడించండి"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"నిల్వ ఖాళీ అయిపోతోంది"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"కొన్ని సిస్టమ్ కార్యాచరణలు పని చేయకపోవచ్చు"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"సిస్టమ్ కోసం తగినంత నిల్వ లేదు. మీకు 250MB ఖాళీ స్థలం ఉందని నిర్ధారించుకుని, పునఃప్రారంభించండి."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"రద్దు చేయి"</string>
     <string name="yes" msgid="5362982303337969312">"సరే"</string>
     <string name="no" msgid="5141531044935541497">"రద్దు చేయి"</string>
-    <string name="close" msgid="2318214661230355730">"మూసివేయండి"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"గమనిక"</string>
     <string name="loading" msgid="7933681260296021180">"లోడ్ చేస్తోంది…"</string>
     <string name="capital_on" msgid="1544682755514494298">"ఆన్‌లో ఉంది"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"ప్రమాణం"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"ఎల్లప్పుడూ చూపు"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"సిస్టమ్ సెట్టింగ్‌లు &gt; అనువర్తనాలు &gt; డౌన్‌లోడ్ చేసినవిలో దీన్ని పునఃప్రారంభించండి."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"యాప్ ప్రతిస్పందించలేదు"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> చాలా ఎక్కువ మెమరీని ఉపయోగించుకోవచ్చు."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ప్రస్తుత ప్రదర్శన పరిమాణ సెట్టింగ్‌కు మద్దతు ఇవ్వదు, దీని వలన ఊహించని సమస్యలు తలెత్తవచ్చు."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"ఎల్లప్పుడూ చూపు"</string>
     <string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> యాప్ (<xliff:g id="PROCESS">%2$s</xliff:g> ప్రాసెస్) అది స్వయంగా అమలు చేసే ఖచ్చితమైన మోడ్ విధానాన్ని ఉల్లంఘించింది."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"అత్యవసర సందేశాల పరీక్ష"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"ప్రత్యుత్తరం పంపండి"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM అనుమతించబడదు"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM సక్రియం కాలేదు"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM అనుమతించబడదు"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"ఫోన్ అనుమతించబడదు"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"పాప్అప్ విండో"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"పాప్అప్ విండో"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"ఈ సత్వరమార్గానికి తాజా యాప్ అవసరం"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"బ్యాకప్ మరియు పునరుద్ధరణకు యాప్ మద్దతు ఇవ్వని కారణంగా సత్వరమార్గాన్ని పునరుద్ధరించడం సాధ్యపడలేదు"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"యాప్ సంతకం సరిపోలని కారణంగా సత్వరమార్గాన్ని పునరుద్ధరించడం సాధ్యపడలేదు"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"సత్వరమార్గాన్ని పునరుద్ధరించడం సాధ్యపడలేదు"</string>
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 66a7280..1ccb751 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"การแจ้งเตือน"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"การสาธิตสำหรับผู้ค้าปลีก"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"การเชื่อมต่อ USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"แอปที่ทำงานอยู่"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"แอปหลายแอปกำลังใช้แบตเตอรี่"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังใช้แบตเตอรี่"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"แอป <xliff:g id="NUMBER">%1$d</xliff:g> แอปกำลังใช้แบตเตอรี่"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"วิธีป้อนข้อมูล"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"การทำงานของข้อความ"</string>
     <string name="email" msgid="4560673117055050403">"อีเมล"</string>
-    <string name="dial" msgid="4204975095406423102">"โทรศัพท์"</string>
-    <string name="map" msgid="6068210738233985748">"Maps"</string>
-    <string name="browse" msgid="6993590095938149861">"เบราว์เซอร์"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"ติดต่อ"</string>
+    <string name="dial" msgid="1253998302767701559">"โทร"</string>
+    <string name="map" msgid="6521159124535543457">"ค้นหา"</string>
+    <string name="browse" msgid="1245903488306147205">"เปิด"</string>
+    <string name="sms" msgid="4560537514610063430">"ข้อความ"</string>
+    <string name="add_contact" msgid="7867066569670597203">"เพิ่ม"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"พื้นที่จัดเก็บเหลือน้อย"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"บางฟังก์ชันระบบอาจไม่ทำงาน"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"พื้นที่เก็บข้อมูลไม่เพียงพอสำหรับระบบ โปรดตรวจสอบว่าคุณมีพื้นที่ว่าง 250 MB แล้วรีสตาร์ท"</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"ยกเลิก"</string>
     <string name="yes" msgid="5362982303337969312">"ตกลง"</string>
     <string name="no" msgid="5141531044935541497">"ยกเลิก"</string>
-    <string name="close" msgid="2318214661230355730">"ปิด"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"โปรดทราบ"</string>
     <string name="loading" msgid="7933681260296021180">"กำลังโหลด..."</string>
     <string name="capital_on" msgid="1544682755514494298">"เปิด"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"สเกล"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"แสดงเสมอ"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"เปิดใช้งานอีกครั้งในการตั้งค่าระบบ &gt; แอปพลิเคชัน &gt; ดาวน์โหลด"</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"แอปไม่ตอบสนอง"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> อาจใช้หน่วยความจำมากเกินไป"</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ไม่สนับสนุนการตั้งค่าขนาดการแสดงผลปัจจุบันและอาจแสดงผลผิดปกติ"</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"แสดงเสมอ"</string>
     <string name="smv_application" msgid="3307209192155442829">"แอปพลิเคชัน <xliff:g id="APPLICATION">%1$s</xliff:g> (กระบวนการ <xliff:g id="PROCESS">%2$s</xliff:g>) ละเมิดนโยบาย StrictMode ที่บังคับใช้ด้วยตัวเอง"</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"การทดสอบข้อความกรณีฉุกเฉิน"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"ตอบ"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"ไม่อนุญาตให้ใช้ซิม"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"ไม่มีการจัดสรรซิม"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"ไม่อนุญาตให้ใช้ซิม"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"ไม่อนุญาตให้ใช้โทรศัพท์"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"หน้าต่างป๊อปอัป"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"หน้าต่างป๊อปอัป"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"ทางลัดนี้ต้องใช้แอปล่าสุด"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"คืนค่าทางลัดไม่ได้เนื่องจากแอปไม่รองรับการสำรองข้อมูลและคืนค่า"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"คืนค่าทางลัดไม่ได้เนื่องจากการลงนามแอปไม่ตรงกัน"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"คืนค่าทางลัดไม่ได้"</string>
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index bafcef3..5a9d118 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Mga Alerto"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Retail demo"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Koneksyon ng USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Tumatakbo ang app"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Mga app na kumokonsumo ng baterya"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"Gumagamit ng baterya ang <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"Gumagamit ng baterya ang <xliff:g id="NUMBER">%1$d</xliff:g> (na) app"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Pamamaraan ng pag-input"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Pagkilos ng teksto"</string>
     <string name="email" msgid="4560673117055050403">"Mag-email"</string>
-    <string name="dial" msgid="4204975095406423102">"Telepono"</string>
-    <string name="map" msgid="6068210738233985748">"Mga Mapa"</string>
-    <string name="browse" msgid="6993590095938149861">"Browser"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Contact"</string>
+    <string name="dial" msgid="1253998302767701559">"Tawagan"</string>
+    <string name="map" msgid="6521159124535543457">"Hanapin"</string>
+    <string name="browse" msgid="1245903488306147205">"Buksan"</string>
+    <string name="sms" msgid="4560537514610063430">"Padalhan ng Mensahe"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Magdagdag"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nauubusan na ang puwang ng storage"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Maaaring hindi gumana nang tama ang ilang paggana ng system"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Walang sapat na storage para sa system. Tiyaking mayroon kang 250MB na libreng espasyo at i-restart."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Kanselahin"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Kanselahin"</string>
-    <string name="close" msgid="2318214661230355730">"ISARA"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Bigyang pansin"</string>
     <string name="loading" msgid="7933681260296021180">"Naglo-load…"</string>
     <string name="capital_on" msgid="1544682755514494298">"I-ON"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Sukat"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Palaging ipakita"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Muling paganahin ito sa mga setting ng System &gt; Apps &gt; Na-download."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Hindi tumutugon ang app"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"Maaaring gumagamit ang <xliff:g id="APP_NAME">%1$s</xliff:g> ng masyadong maraming memory."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"Hindi sinusuportahan ng <xliff:g id="APP_NAME">%1$s</xliff:g> ang kasalukuyang setting ng laki ng Display at maaaring may mangyaring hindi inaasahan."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Palaging ipakita"</string>
     <string name="smv_application" msgid="3307209192155442829">"Ang app na <xliff:g id="APPLICATION">%1$s</xliff:g> (prosesong <xliff:g id="PROCESS">%2$s</xliff:g>) ay lumabag sa sarili nitong ipinapatupad na patakarang StrictMode."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Pagsubok sa mga mensaheng pang-emergency"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Tumugon"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"Hindi pinahihintulutan ang SIM"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Hindi naprobisyon ang SIM"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"Hindi pinahihintulutan ang SIM"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Hindi pinahihintulutan ang telepono"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Window ng Popup"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Window ng Popup"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Kinakailangan ng shortcut na ito ang pinakabagong app"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Hindi ma-restore ang shortcut dahil hindi sinusuportahan ng app ang pag-back up at pag-restore"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Hindi ma-restore ang shortcut dahil hindi magkatugma ang signature ng app"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Hindi ma-restore ang shortcut"</string>
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 7e2d2bfe..2460e65 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Uyarılar"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Mağaza demo"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB bağlantısı"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Uygulama çalışıyor"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Pil kullanan uygulamalar"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> pil kullanıyor"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> uygulama pil kullanıyor"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Giriş yöntemi"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Metin eylemleri"</string>
     <string name="email" msgid="4560673117055050403">"E-posta"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefon"</string>
-    <string name="map" msgid="6068210738233985748">"Haritalar"</string>
-    <string name="browse" msgid="6993590095938149861">"Tarayıcı"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Kişi"</string>
+    <string name="dial" msgid="1253998302767701559">"Telefon et"</string>
+    <string name="map" msgid="6521159124535543457">"Yerini bul"</string>
+    <string name="browse" msgid="1245903488306147205">"Aç"</string>
+    <string name="sms" msgid="4560537514610063430">"Mesaj"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Ekle"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Depolama alanı bitiyor"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Bazı sistem işlevleri çalışmayabilir"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sistem için yeterli depolama alanı yok. 250 MB boş alanınızın bulunduğundan emin olun ve yeniden başlatın."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"İptal"</string>
     <string name="yes" msgid="5362982303337969312">"Tamam"</string>
     <string name="no" msgid="5141531044935541497">"İptal"</string>
-    <string name="close" msgid="2318214661230355730">"KAPAT"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Dikkat"</string>
     <string name="loading" msgid="7933681260296021180">"Yükleniyor..."</string>
     <string name="capital_on" msgid="1544682755514494298">"AÇIK"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Ölçek"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Her zaman göster"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Bunu Sistem ayarları &gt; Uygulamalar &gt; İndirilenler bölümünden yeniden etkinleştirin."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Uygulama yanıt vermiyor"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> çok fazla bellek kullanıyor olabilir."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> geçerli Ekran boyutu ayarını desteklemiyor ve beklenmedik bir şekilde davranabilir."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Her zaman göster"</string>
     <string name="smv_application" msgid="3307209192155442829">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması (<xliff:g id="PROCESS">%2$s</xliff:g> işlemi) kendiliğinden uyguladığı StrictMode politikasını ihlal etti."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Acil durum mesajları testi"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Yanıtla"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM\'e izin verilmiyor"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM için temel hazırlık yapılmadı"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM\'e izin verilmiyor"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Telefona izin verilmiyor"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Pop-up Pencere"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Pop-up Pencere"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Bu kısayol, en son uygulamayı gerektiriyor"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Uygulama, yedekleme ve geri yüklemeyi desteklemediğinden kısayol geri yüklenemedi"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Uygulama imzası eşleşmediğinden kısayol geri yüklenemedi"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Kısayol geri yüklenemedi"</string>
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 050b26b..7d14e59 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -255,6 +255,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Сповіщення"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Демо-режим для роздрібної торгівлі"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"З’єднання USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Працює додаток"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Додатки, що використовують заряд акумулятора"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> використовує заряд акумулятора"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"Додатків, що використовують заряд акумулятора: <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
@@ -1018,11 +1019,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Метод введення"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Дії з текстом"</string>
     <string name="email" msgid="4560673117055050403">"Електронна пошта"</string>
-    <string name="dial" msgid="4204975095406423102">"Телефонувати"</string>
-    <string name="map" msgid="6068210738233985748">"Карти"</string>
-    <string name="browse" msgid="6993590095938149861">"Веб-переглядач"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Контакт"</string>
+    <string name="dial" msgid="1253998302767701559">"Зателефонувати"</string>
+    <string name="map" msgid="6521159124535543457">"Знайти"</string>
+    <string name="browse" msgid="1245903488306147205">"Відкрити"</string>
+    <string name="sms" msgid="4560537514610063430">"Повідомлення"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Додати"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Закінчується пам’ять"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Деякі системні функції можуть не працювати"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Недостатньо місця для системи. Переконайтесь, що на пристрої є 250 МБ вільного місця, і повторіть спробу."</string>
@@ -1032,7 +1033,6 @@
     <string name="cancel" msgid="6442560571259935130">"Скасувати"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Скасувати"</string>
-    <string name="close" msgid="2318214661230355730">"ЗАКРИТИ"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Увага"</string>
     <string name="loading" msgid="7933681260296021180">"Завантаження..."</string>
     <string name="capital_on" msgid="1544682755514494298">"УВІМК"</string>
@@ -1089,8 +1089,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Масштаб"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Завжди показувати"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Знову ввімкнути це в меню Налаштування системи &gt; Програми &gt; Завантажені."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Додаток не відповідає"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"Можливо, додаток <xliff:g id="APP_NAME">%1$s</xliff:g> використовує забагато пам’яті."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> не підтримує поточне налаштування розміру екрана та може працювати неналежним чином."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Завжди показувати"</string>
     <string name="smv_application" msgid="3307209192155442829">"Програма <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) порушила свою самозастосовну політику StrictMode."</string>
@@ -1854,11 +1852,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Перевірка екстрених повідомлень"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Відповісти"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM-карта заборонена"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM-карту не затверджено"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM-карта заборонена"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Телефон заборонено"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Спливаюче вікно"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Спливаюче вікно"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Для цього ярлика потрібна найновіша версія додатка"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Не вдалося відновити ярлик, оскільки додаток не підтримує резервне копіювання та відновлення"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Не вдалося відновити ярлик, оскільки підписи додатків не збігаються"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Не вдалося відновити ярлик"</string>
 </resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 44e7350..b89af42 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"الرٹس"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"ریٹیل ڈیمو"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"‏USB کنکشن"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"ایپ چل رہی ہے"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"ایپس بیٹری خرچ کر رہی ہیں"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> بیٹری کا استعمال کر رہی ہے"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> ایپس بیٹری کا استعمال کر رہی ہیں"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"اندراج کا طریقہ"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"متن کی کارروائیاں"</string>
     <string name="email" msgid="4560673117055050403">"ای میل"</string>
-    <string name="dial" msgid="4204975095406423102">"فون کریں"</string>
-    <string name="map" msgid="6068210738233985748">"Maps"</string>
-    <string name="browse" msgid="6993590095938149861">"براؤزر"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"رابطہ"</string>
+    <string name="dial" msgid="1253998302767701559">"کال کریں"</string>
+    <string name="map" msgid="6521159124535543457">"پتا لگائیں"</string>
+    <string name="browse" msgid="1245903488306147205">"کھولیں"</string>
+    <string name="sms" msgid="4560537514610063430">"پیغام"</string>
+    <string name="add_contact" msgid="7867066569670597203">"شامل کریں"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"اسٹوریج کی جگہ ختم ہو رہی ہے"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"ممکن ہے سسٹم کے کچھ فنکشنز کام نہ کریں"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"‏سسٹم کیلئے کافی اسٹوریج نہیں ہے۔ اس بات کو یقینی بنائیں کہ آپ کے پاس 250MB خالی جگہ ہے اور دوبارہ شروع کریں۔"</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"منسوخ کریں"</string>
     <string name="yes" msgid="5362982303337969312">"ٹھیک ہے"</string>
     <string name="no" msgid="5141531044935541497">"منسوخ کریں"</string>
-    <string name="close" msgid="2318214661230355730">"بند کریں"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"توجہ دیں"</string>
     <string name="loading" msgid="7933681260296021180">"لوڈ ہو رہا ہے…"</string>
     <string name="capital_on" msgid="1544682755514494298">"آن"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"پیمانہ"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"ہمیشہ دکھائیں"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"‏سسٹم ترتیبات &gt; ایپس &gt; ڈاؤن لوڈ کردہ میں اسے دوبارہ فعال کریں۔"</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"ایپ جواب نہیں دے رہی ہے"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> کافی زیادہ میموری استعمال کر سکتی ہے۔"</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> میں موجودہ ڈسپلے سائز ترتیبات کی معاونت نہیں ہے اور ہو سکتا ہے غیر متوقع طریقے سے کام کرے۔"</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"ہمیشہ دکھائیں"</string>
     <string name="smv_application" msgid="3307209192155442829">"‏ایپ <xliff:g id="APPLICATION">%1$s</xliff:g> (کارروائی <xliff:g id="PROCESS">%2$s</xliff:g>) نے خود نافذ کی گئی StrictMode پالیسی کی خلاف ورزی کی ہے۔"</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"ایمرجنسی پیغامات کی جانچ"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"جواب دیں"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"‏SIM کی اجازت نہیں ہے"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"‏SIM فراہم کردہ نہیں ہے"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"‏SIM کی اجازت نہیں ہے"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"فون کی اجازت نہیں ہے"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"پاپ اپ ونڈو"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"پاپ اپ ونڈو"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"‎‎‎‎‎+ <xliff:g id="NUMBER">%1$d</xliff:g>‎‎"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"اس شارٹ کٹ کیلئے جدید ترین ایپ درکار ہے"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"شارٹ کٹ کو بحال نہیں کیا جا سکا، کیونکہ ایپ بیک اپ اور بحالی کو سپورٹ نہیں کرتی ہے"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"ایپ کی دستخط کے غیر مماثل ہونے کی وجہ سے شارٹ کٹ کو بحال نہیں کیا جا سکا"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"شارٹ کٹ کو بحال نہیں کیا جا سکا"</string>
 </resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index b62d5b9..a99fc0f 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Ogohlantirishlar"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demo rejim"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB orqali ulanish"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Ilova ishlamoqda"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Batareya quvvatini sarflayotgan ilovalar"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi batareya quvvatini sarflamoqda"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> ta ilova batareya quvvatini sarflamoqda"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Kiritish uslubi"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Matn yozish"</string>
     <string name="email" msgid="4560673117055050403">"E-pochta"</string>
-    <string name="dial" msgid="4204975095406423102">"Telefon"</string>
-    <string name="map" msgid="6068210738233985748">"Xaritalar"</string>
-    <string name="browse" msgid="6993590095938149861">"Brauzer"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Kontakt"</string>
+    <string name="dial" msgid="1253998302767701559">"Chaqiruv"</string>
+    <string name="map" msgid="6521159124535543457">"Joylashuvni aniqlash"</string>
+    <string name="browse" msgid="1245903488306147205">"Ochish"</string>
+    <string name="sms" msgid="4560537514610063430">"Xabar"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Qo‘shish"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Xotirada bo‘sh joy tugamoqda"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Ba‘zi tizim funksiyalari ishlamasligi mumkin"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Tizim uchun xotirada joy yetarli emas. Avval 250 megabayt joy bo‘shatib, keyin qurilmani o‘chirib yoqing."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Bekor qilish"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Bekor qilish"</string>
-    <string name="close" msgid="2318214661230355730">"YOPISH"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Diqqat"</string>
     <string name="loading" msgid="7933681260296021180">"Yuklanmoqda…"</string>
     <string name="capital_on" msgid="1544682755514494298">"I"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Masshtab"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Doimo ko‘rsatish"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Uni Tizim sozlamalari &gt; Ilovalar &gt; Yuklab olingan menyusidan qayta yoqing."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Ilova javob bermayapti"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> ortiqcha xotira ishlatmoqda."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” ilovasi joriy ekran o‘lchami sozlamalariga mos kelmasligi va noto‘g‘ri ishlashi mumkin."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Har doim ko‘rsatilsin"</string>
     <string name="smv_application" msgid="3307209192155442829">"“<xliff:g id="APPLICATION">%1$s</xliff:g>” ilovasi (jarayaon: <xliff:g id="PROCESS">%2$s</xliff:g>) o‘zining StrictMode qoidasini buzdi."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Favqulodda holatlar uchun sinov xabarlari"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Javob berish"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM karta ishlatish taqiqlangan"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM karta yo‘q"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM karta ishlatish taqiqlangan"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Chaqiruvlar taqiqlangan"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Qalqib chiquvchi oyna"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Qalqib chiquvchi oyna"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Bu yorliq uchun eng oxirgi versiyadagi ilova zarur"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Ilovada zaxiralash va tiklash ishlamagani uchun yorliq tiklanmadi"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Ilova imzosi mos kelmagani uchun yorliq tiklanmadi"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Yorliq tiklanmadi"</string>
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 921f7c6..c3938aa 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Cảnh báo"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Giới thiệu bán lẻ"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Kết nối USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Ứng dụng đang chạy"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Các ứng dụng tiêu thụ pin"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang sử dụng pin"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> ứng dụng đang sử dụng pin"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Phương thức nhập"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Tác vụ văn bản"</string>
     <string name="email" msgid="4560673117055050403">"Email"</string>
-    <string name="dial" msgid="4204975095406423102">"Điện thoại"</string>
-    <string name="map" msgid="6068210738233985748">"Bản đồ"</string>
-    <string name="browse" msgid="6993590095938149861">"Trình duyệt"</string>
-    <string name="sms" msgid="8250353543787396737">"SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Liên hệ"</string>
+    <string name="dial" msgid="1253998302767701559">"Gọi"</string>
+    <string name="map" msgid="6521159124535543457">"Định vị"</string>
+    <string name="browse" msgid="1245903488306147205">"Mở"</string>
+    <string name="sms" msgid="4560537514610063430">"Gửi tin nhắn"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Thêm"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Sắp hết dung lượng lưu trữ"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Một số chức năng hệ thống có thể không hoạt động"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Không đủ bộ nhớ cho hệ thống. Đảm bảo bạn có 250 MB dung lượng trống và khởi động lại."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Hủy"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Hủy"</string>
-    <string name="close" msgid="2318214661230355730">"ĐÓNG"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Chú ý"</string>
     <string name="loading" msgid="7933681260296021180">"Đang tải…"</string>
     <string name="capital_on" msgid="1544682755514494298">"BẬT"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Tỷ lệ"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Luôn hiển thị"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Bật lại chế độ này trong cài đặt Hệ thống &gt; Ứng dụng &gt; Đã tải xuống."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"Ứng dụng không phản hồi"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> có thể đang sử dụng quá nhiều bộ nhớ."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> không hỗ trợ cài đặt kích thước Màn hình hiện tại và có thể hoạt động không như mong đợi."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Luôn hiển thị"</string>
     <string name="smv_application" msgid="3307209192155442829">"Ứng dụng <xliff:g id="APPLICATION">%1$s</xliff:g> (quá trình <xliff:g id="PROCESS">%2$s</xliff:g>) đã vi phạm chính sách StrictMode tự thi hành của mình."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Kiểm tra thông báo khẩn cấp"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Trả lời"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM không được cho phép"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM không được cấp phép"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM không được cho phép"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Điện thoại không được cho phép"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Cửa sổ bật lên"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Cửa sổ bật lên"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Lối tắt này yêu cầu ứng dụng mới nhất"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Không thể khôi phục lối tắt do ứng dụng không hỗ trợ sao lưu và khôi phục"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Không thể khôi phục lối tắt do không khớp chữ ký ứng dụng"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Không thể khôi phục lối tắt"</string>
 </resources>
diff --git a/core/res/res/values-xlarge/strings.xml b/core/res/res/values-xlarge/strings.xml
deleted file mode 100644
index fc20be6..0000000
--- a/core/res/res/values-xlarge/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/assets/res/any/strings.xml
-**
-** Copyright 2010, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- Do not translate.  WebView User Agent targeted content -->
-    <string name="web_user_agent_target_content" translatable="false"></string>
-
-</resources>
\ No newline at end of file
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 06b781d..5629df1 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"提醒"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"零售演示模式"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB 连接"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"应用正在运行中"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"消耗电量的应用"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g>正在消耗电量"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> 个应用正在消耗电量"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"输入法"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"文字操作"</string>
     <string name="email" msgid="4560673117055050403">"电子邮件"</string>
-    <string name="dial" msgid="4204975095406423102">"电话"</string>
-    <string name="map" msgid="6068210738233985748">"地图"</string>
-    <string name="browse" msgid="6993590095938149861">"浏览器"</string>
-    <string name="sms" msgid="8250353543787396737">"短信"</string>
-    <string name="add_contact" msgid="7990645816259405444">"联系人"</string>
+    <string name="dial" msgid="1253998302767701559">"通话"</string>
+    <string name="map" msgid="6521159124535543457">"定位"</string>
+    <string name="browse" msgid="1245903488306147205">"打开"</string>
+    <string name="sms" msgid="4560537514610063430">"短信"</string>
+    <string name="add_contact" msgid="7867066569670597203">"添加"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"存储空间不足"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"某些系统功能可能无法正常使用"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"系统存储空间不足。请确保您有250MB的可用空间,然后重新启动。"</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"取消"</string>
     <string name="yes" msgid="5362982303337969312">"确定"</string>
     <string name="no" msgid="5141531044935541497">"取消"</string>
-    <string name="close" msgid="2318214661230355730">"关闭"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"注意"</string>
     <string name="loading" msgid="7933681260296021180">"正在加载..."</string>
     <string name="capital_on" msgid="1544682755514494298">"开启"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"缩放"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"始终显示"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"在“系统设置”&gt;“应用”&gt;“已下载”中重新启用此模式。"</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"应用没有响应"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g>可能占用了过多内存。"</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g>不支持当前的显示大小设置,因此可能无法正常显示。"</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"一律显示"</string>
     <string name="smv_application" msgid="3307209192155442829">"“<xliff:g id="APPLICATION">%1$s</xliff:g>”应用(<xliff:g id="PROCESS">%2$s</xliff:g> 进程)违反了自我强制执行的严格模式 (StrictMode) 政策。"</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"紧急消息测试"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"回复"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"不受允许的 SIM 卡"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"未配置的 SIM 卡"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"不受允许的 SIM 卡"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"不受允许的手机"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"弹出式窗口"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"弹出式窗口"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"您必须拥有最新版的应用才能使用此快捷方式"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"无法恢复快捷方式,因为应用不支持备份和恢复功能"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"无法恢复快捷方式,因为应用签名不相符"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"无法恢复快捷方式"</string>
 </resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index aac5fcc..b9c83b3 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"通知"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"零售示範"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB 連線"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"應用程式正在執行"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"耗用電量的應用程式"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在使用電量"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> 個應用程式正在使用電量"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"輸入法"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"文字操作"</string>
     <string name="email" msgid="4560673117055050403">"電郵"</string>
-    <string name="dial" msgid="4204975095406423102">"撥打電話"</string>
-    <string name="map" msgid="6068210738233985748">"地圖"</string>
-    <string name="browse" msgid="6993590095938149861">"瀏覽器"</string>
-    <string name="sms" msgid="8250353543787396737">"短訊"</string>
-    <string name="add_contact" msgid="7990645816259405444">"聯絡人"</string>
+    <string name="dial" msgid="1253998302767701559">"通話"</string>
+    <string name="map" msgid="6521159124535543457">"尋找"</string>
+    <string name="browse" msgid="1245903488306147205">"開啟"</string>
+    <string name="sms" msgid="4560537514610063430">"短訊"</string>
+    <string name="add_contact" msgid="7867066569670597203">"新增"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"儲存空間即將用盡"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"部分系統功能可能無法運作"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"系統儲存空間不足。請確認裝置有 250 MB 的可用空間,然後重新啟動。"</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"取消"</string>
     <string name="yes" msgid="5362982303337969312">"確定"</string>
     <string name="no" msgid="5141531044935541497">"取消"</string>
-    <string name="close" msgid="2318214661230355730">"關閉"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"注意"</string>
     <string name="loading" msgid="7933681260296021180">"正在載入..."</string>
     <string name="capital_on" msgid="1544682755514494298">"開啟"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"比例"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"永遠顯示"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"前往 [系統設定] &gt; [應用程式] &gt; [下載] 重新啟用這個模式。"</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"應用程式沒有回應"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」可能佔用大量記憶體。"</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援目前的「螢幕」尺寸設定,畫面可能無法如預期顯示。"</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"永遠顯示"</string>
     <string name="smv_application" msgid="3307209192155442829">"應用程式 <xliff:g id="APPLICATION">%1$s</xliff:g> (處理程序 <xliff:g id="PROCESS">%2$s</xliff:g>) 已違反其自行強制實施的嚴格模式 (StrictMode) 政策。"</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"緊急訊息測試"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"回覆"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"不允許使用 SIM 卡"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"無法識別 SIM 卡"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"不允許使用 SIM 卡"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"不允許使用手機"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"彈出式視窗"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"彈出式視窗"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"您需要最新的應用程式,才能使用這個捷徑"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"由於應用程式不支援備份和還原功能,因此無法還原捷徑"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"由於應用程式簽署不相符,因此無法還原捷徑"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"無法還原捷徑"</string>
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 6a35994..a5b91eb 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"快訊"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"零售商示範模式"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB 連線"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"應用程式執行中"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"正在耗用電量的應用程式"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在耗用電量"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> 個應用程式正在耗用電量"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"輸入法"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"文字動作"</string>
     <string name="email" msgid="4560673117055050403">"電子郵件"</string>
-    <string name="dial" msgid="4204975095406423102">"電話"</string>
-    <string name="map" msgid="6068210738233985748">"地圖"</string>
-    <string name="browse" msgid="6993590095938149861">"瀏覽器"</string>
-    <string name="sms" msgid="8250353543787396737">"簡訊"</string>
-    <string name="add_contact" msgid="7990645816259405444">"聯絡人"</string>
+    <string name="dial" msgid="1253998302767701559">"通話"</string>
+    <string name="map" msgid="6521159124535543457">"定位"</string>
+    <string name="browse" msgid="1245903488306147205">"開啟"</string>
+    <string name="sms" msgid="4560537514610063430">"訊息"</string>
+    <string name="add_contact" msgid="7867066569670597203">"新增"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"儲存空間即將用盡"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"部分系統功能可能無法運作"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"系統儲存空間不足。請確定你已釋出 250MB 的可用空間,然後重新啟動。"</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"取消"</string>
     <string name="yes" msgid="5362982303337969312">"確定"</string>
     <string name="no" msgid="5141531044935541497">"取消"</string>
-    <string name="close" msgid="2318214661230355730">"關閉"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"注意"</string>
     <string name="loading" msgid="7933681260296021180">"載入中…"</string>
     <string name="capital_on" msgid="1544682755514494298">"開啟"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"比例"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"一律顯示"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"前往 [系統設定] &gt; [應用程式] &gt; [下載] 重新啟用這個模式。"</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"應用程式沒有回應"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」可能使用了過多記憶體。"</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援目前的顯示大小設定,可能會發生非預期的行為。"</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"一律顯示"</string>
     <string name="smv_application" msgid="3307209192155442829">"應用程式 <xliff:g id="APPLICATION">%1$s</xliff:g> (處理程序 <xliff:g id="PROCESS">%2$s</xliff:g>) 已違反其自行強制實施的嚴格模式 (StrictMode) 政策。"</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"緊急訊息測試"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"回覆"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"不受允許的 SIM 卡"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"未佈建的 SIM 卡"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"不受允許的 SIM 卡"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"不受允許的手機"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"彈出式視窗"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"彈出式視窗"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"你必須擁有最新版的應用程式,才能使用這個捷徑"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"應用程式不支援備份與還原功能,因此無法還原捷徑"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"應用程式簽署不相符,因此無法還原捷徑"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"無法還原捷徑"</string>
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 6f5e4cb..4703e79 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -249,6 +249,7 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Izexwayiso"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Idemo yokuthenga"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Ukuxhumeka kwe-USB"</string>
+    <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Uhlelo loksuebenza olusebenzayo"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Izinhlelo zokusebenza ezidla ibhethri"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> isebenzisa ibhethri"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> izinhlelo zokusebenza zisebenzisa ibhethri"</string>
@@ -978,11 +979,11 @@
     <string name="inputMethod" msgid="1653630062304567879">"Indlela yokufakwayo"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Izenzo zombhalo"</string>
     <string name="email" msgid="4560673117055050403">"I-imeyili"</string>
-    <string name="dial" msgid="4204975095406423102">"Ifoni"</string>
-    <string name="map" msgid="6068210738233985748">"Amamephu"</string>
-    <string name="browse" msgid="6993590095938149861">"Isiphequluli"</string>
-    <string name="sms" msgid="8250353543787396737">"I-SMS"</string>
-    <string name="add_contact" msgid="7990645816259405444">"Oxhumana naye"</string>
+    <string name="dial" msgid="1253998302767701559">"Shaya"</string>
+    <string name="map" msgid="6521159124535543457">"Beka"</string>
+    <string name="browse" msgid="1245903488306147205">"Vula"</string>
+    <string name="sms" msgid="4560537514610063430">"Umlayezo"</string>
+    <string name="add_contact" msgid="7867066569670597203">"Engeza"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Isikhala sokulondoloza siyaphela"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Eminye imisebenzi yohlelo ingahle ingasebenzi"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Akusona isitoreji esanele sesistimu. Qiniseka ukuthi unesikhala esikhululekile esingu-250MB uphinde uqalise kabusha."</string>
@@ -992,7 +993,6 @@
     <string name="cancel" msgid="6442560571259935130">"Khansela"</string>
     <string name="yes" msgid="5362982303337969312">"KULUNGILE"</string>
     <string name="no" msgid="5141531044935541497">"Khansela"</string>
-    <string name="close" msgid="2318214661230355730">"VALA"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Qaphela"</string>
     <string name="loading" msgid="7933681260296021180">"Iyalayisha…"</string>
     <string name="capital_on" msgid="1544682755514494298">"VULIWE"</string>
@@ -1049,8 +1049,6 @@
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Isilinganisi"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Bonisa njalo"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Yenza kuphinde kusebenze kuzilungiselelo Zesistimue &gt; Izinhlelo zokusebenza &gt; Okulayishiwe."</string>
-    <string name="top_app_killed_title" msgid="6814231368167994497">"I-App ayiphenduli"</string>
-    <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> ingasebenzisa imemori eningi."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayisekeli isilungiselelo sosayizi sokubonisa samanje futhi ingasebenza ngokungalindelekile."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"Bonisa njalo"</string>
     <string name="smv_application" msgid="3307209192155442829">"Inqubo <xliff:g id="APPLICATION">%1$s</xliff:g> (yohlelo <xliff:g id="PROCESS">%2$s</xliff:g>) iphule inqubomgomo oziphoqelela yona Yemodi Ebukhali."</string>
@@ -1784,11 +1782,18 @@
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Ukuhlolwa kwemilayezo yesimo esiphuthumayo"</string>
     <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Phendula"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
-    <string name="mmcc_authentication_reject" msgid="7729819349669603406">"I-SIM ayivunyelwe"</string>
-    <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"I-SIM ayinikezelwe"</string>
-    <string name="mmcc_illegal_ms" msgid="2769452751852211112">"I-SIM ayivunyelwe"</string>
-    <string name="mmcc_illegal_me" msgid="4438696681169345015">"Ifoni ayivunyelwe"</string>
-    <string name="popup_window_default_title" msgid="4874318849712115433">"Iwindi lesigelekeqe"</string>
-    <!-- no translation found for slice_more_content (8504342889413274608) -->
+    <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
     <skip />
+    <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+    <skip />
+    <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+    <skip />
+    <string name="popup_window_default_title" msgid="4874318849712115433">"Iwindi lesigelekeqe"</string>
+    <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Lesi sinqamuleli sidinga uhlelo lokusebenza lwakamuva"</string>
+    <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Ayikwazanga ukubuyisa isinqamuleli ngoba uhlelo lokusebenza alusekeli isipele nokubuyisa"</string>
+    <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Ayikwazanga ukubuyisa isinqamuleli ngoba isignisha yohlelo lokusebenza ayifani"</string>
+    <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Ayikwazanga ukubuyisa isinqamuleli"</string>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 4b9839f..5a497ac 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8670,6 +8670,9 @@
          common values are 400 for regular weight and 700 for bold weight. If unspecified, the value
          in the font's header tables will be used. -->
         <attr name="fontWeight" format="integer" />
+        <!-- The index of the font in the tcc font file. If the font file referenced is not in the
+         tcc format, this attribute needs not be specified. -->
+        <attr name="ttcIndex" format="integer" />
     </declare-styleable>
 
     <!-- Attributes that are read when parsing a <fontfamily> tag. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index dcb56a2..dec5fd9 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1741,7 +1741,7 @@
          Build.MODEL. The format string shall not be escaped. -->
     <string name="config_useragentprofile_url" translatable="false"></string>
 
-    <!-- When a database query is executed, the results retuned are paginated
+    <!-- When a database query is executed, the results returned are paginated
          in pages of size (in KB) indicated by this value -->
     <integer name="config_cursorWindowSize">2048</integer>
 
@@ -2352,9 +2352,37 @@
     <!-- Package name for default network scorer app; overridden by product overlays. -->
     <string name="config_defaultNetworkScorerPackageName"></string>
 
-    <!-- default device has recents property -->
+    <!-- Determines whether recent tasks are provided to the user. Default device has recents
+         property. If this is false, then the following recents config flags are ignored. -->
     <bool name="config_hasRecents">true</bool>
 
+    <!-- The minimum number of visible recent tasks to be presented to the user through the
+         SystemUI. Can be -1 if there is no minimum limit. -->
+    <integer name="config_minNumVisibleRecentTasks_grid">-1</integer>
+
+    <!-- The maximum number of visible recent tasks to be presented to the user through the
+         SystemUI. Can be -1 if there is no maximum limit. -->
+    <integer name="config_maxNumVisibleRecentTasks_grid">9</integer>
+
+    <!-- The minimum number of visible recent tasks to be presented to the user through the
+         SystemUI. Can be -1 if there is no minimum limit. -->
+    <integer name="config_minNumVisibleRecentTasks_lowRam">-1</integer>
+
+    <!-- The maximum number of visible recent tasks to be presented to the user through the
+         SystemUI. Can be -1 if there is no maximum limit. -->
+    <integer name="config_maxNumVisibleRecentTasks_lowRam">9</integer>
+
+    <!-- The minimum number of visible recent tasks to be presented to the user through the
+         SystemUI. Can be -1 if there is no minimum limit. -->
+    <integer name="config_minNumVisibleRecentTasks">5</integer>
+
+    <!-- The maximum number of visible recent tasks to be presented to the user through the
+         SystemUI. Can be -1 if there is no maximum limit. -->
+    <integer name="config_maxNumVisibleRecentTasks">-1</integer>
+
+    <!-- The duration in which a recent task is considered in session and should be visible. -->
+    <integer name="config_activeTaskDurationHours">6</integer>
+
     <!-- default window ShowCircularMask property -->
     <bool name="config_windowShowCircularMask">false</bool>
 
@@ -3096,4 +3124,8 @@
     <!-- Decide whether to display 'No service' on status bar instead of 'Emergency calls only'
          when SIM is unready. -->
     <bool name="config_display_no_service_when_sim_unready">false</bool>
+
+    <!-- Class names of device specific services inheriting com.android.server.SystemService. The
+         classes are instantiated in the order of the array. -->
+    <string-array translatable="false" name="config_deviceSpecificSystemServices"></string-array>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 0364b81..b42fd82 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2845,6 +2845,7 @@
 
     <public-group type="attr" first-id="0x0101056e">
       <public name="cantSaveState" />
+      <public name="ttcIndex" />
     </public-group>
 
     <public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 085241a..78a8e2a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2106,12 +2106,6 @@
     <!-- Do not translate.  datepicker mode, overridden for watch -->
     <string name="date_picker_mode" translatable="false">"calendar"</string>
 
-    <!-- Do not translate.  WebView User Agent string -->
-    <string name="web_user_agent" translatable="false">Mozilla/5.0 (Linux; U; <xliff:g id="x">Android %s</xliff:g>)
-        AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 <xliff:g id="mobile">%s</xliff:g>Safari/534.30</string>
-    <!-- Do not translate.  WebView User Agent targeted content -->
-    <string name="web_user_agent_target_content" translatable="false">"Mobile "</string>
-
     <!-- Title for a JavaScript dialog. "The page at <url of current page> says:" -->
     <string name="js_dialog_title">The page at \"<xliff:g id="title">%s</xliff:g>\" says:</string>
     <!-- Default title for a javascript dialog -->
@@ -2683,19 +2677,19 @@
     <string name="email">Email</string>
 
     <!-- Label for item in the text selection menu to trigger a Dialer app [CHAR LIMIT=20] -->
-    <string name="dial">Phone</string>
+    <string name="dial">Call</string>
 
     <!-- Label for item in the text selection menu to trigger a Map app [CHAR LIMIT=20] -->
-    <string name="map">Maps</string>
+    <string name="map">Locate</string>
 
     <!-- Label for item in the text selection menu to trigger a Browser app [CHAR LIMIT=20] -->
-    <string name="browse">Browser</string>
+    <string name="browse">Open</string>
 
     <!-- Label for item in the text selection menu to trigger an SMS app [CHAR LIMIT=20] -->
-    <string name="sms">SMS</string>
+    <string name="sms">Message</string>
 
     <!-- Label for item in the text selection menu to trigger adding a contact [CHAR LIMIT=20] -->
-    <string name="add_contact">Contact</string>
+    <string name="add_contact">Add</string>
 
     <!-- If the device is getting low on internal storage, a notification is shown to the user.  This is the title of that notification. -->
     <string name="low_internal_storage_view_title">Storage space running out</string>
@@ -2721,8 +2715,6 @@
     <string name="yes">OK</string>
     <!-- Preference framework strings. -->
     <string name="no">Cancel</string>
-    <!-- Preference framework strings. -->
-    <string name="close">CLOSE</string>
     <!-- This is the generic "attention" string to be used in attention dialogs.  Typically
          combined with setIconAttribute(android.R.attr.alertDialogIcon)
          (or setIcon(android.R.drawable.ic_dialog_alert) on legacy versions of the platform) -->
@@ -2855,11 +2847,6 @@
     <!-- [CHAR LIMIT=200] Compat mode dialog: hint to re-enable compat mode dialog. -->
     <string name="screen_compat_mode_hint">Re-enable this in System settings &gt; Apps &gt; Downloaded.</string>
 
-    <!-- Text of the alert that is displayed when a top application is killed by lmk. -->
-    <string name="top_app_killed_title">App isn\'t responding</string>
-    <!-- Top app killed by lmk dialog message. -->
-    <string name="top_app_killed_message"><xliff:g id="app_name">%1$s</xliff:g> may be using too much memory.</string>
-
     <!-- [CHAR LIMIT=200] Unsupported display size dialog: message. Refers to "Display size" setting. -->
     <string name="unsupported_display_size_message"><xliff:g id="app_name">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly.</string>
     <!-- [CHAR LIMIT=50] Unsupported display size dialog: check box label. -->
@@ -4359,8 +4346,6 @@
     <string name="lock_to_app_toast">To unpin this screen, touch &amp; hold Back and Overview
         buttons</string>
 
-    <!-- Notify user that they are locked in lock-to-app mode -->
-    <string name="lock_to_app_toast_locked">This app can\'t be unpinned</string>
     <!-- Starting lock-to-app indication. -->
     <string name="lock_to_app_start">Screen pinned</string>
     <!-- Exting lock-to-app indication. -->
@@ -4724,15 +4709,39 @@
     <!-- Primary ETWS (Earthquake and Tsunami Warning System) default message for others -->
     <string name="etws_primary_default_message_others"></string>
 
-    <!-- Title of notification when UE fails to register network with MM reject cause code. -->
-    <string name="mmcc_authentication_reject">SIM not allowed</string>
-    <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned</string>
-    <string name="mmcc_illegal_ms">SIM not allowed</string>
-    <string name="mmcc_illegal_me">Phone not allowed</string>
+    <!-- Title of notification when UE fails CS registration with MM reject cause code from network. -->
+    <string name="mmcc_authentication_reject">SIM not allowed for voice</string>
+    <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned for voice</string>
+    <string name="mmcc_illegal_ms">SIM not allowed for voice</string>
+    <string name="mmcc_illegal_me">Phone not allowed for voice</string>
 
     <!-- Popup window default title to be read by a screen reader-->
     <string name="popup_window_default_title">Popup Window</string>
 
     <!-- Format string for indicating there is more content in a slice view -->
     <string name="slice_more_content">+ <xliff:g id="number" example="5">%1$d</xliff:g></string>
+
+    <!--
+    A toast message shown when an app shortcut that was restored from a previous device is clicked,
+    but it cannot be started because the shortcut was created by a newer version of the app.
+    -->
+    <string name="shortcut_restored_on_lower_version">This shortcut requires latest app</string>
+
+    <!--
+    A toast message shown when an app shortcut that was restored from a previous device is clicked,
+    but it cannot be started because the shortcut was created by an app that doesn't support backup
+    and restore.
+    -->
+    <string name="shortcut_restore_not_supported">Couldn\u2019t restore shortcut because app doesn\u2019t support backup and restore</string>
+
+    <!--
+    A toast message shown when an app shortcut that was restored from a previous device is clicked,
+    but it cannot be started because the shortcut was created by an app with a different signature.
+    -->
+    <string name="shortcut_restore_signature_mismatch">Couldn\u2019t restore shortcut because of app signature mismatch</string>
+
+    <!--
+    A toast message shown when an app shortcut that wasn't restored due to an unknown issue is clicked,
+    -->
+    <string name="shortcut_restore_unknown_issue">Couldn\u2019t restore shortcut</string>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 44a10e8..7bbd17e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -311,6 +311,13 @@
   <java-symbol type="bool" name="config_enableMultiUserUI"/>
   <java-symbol type="bool" name="config_disableUsbPermissionDialogs"/>
   <java-symbol type="bool" name="config_hasRecents" />
+  <java-symbol type="integer" name="config_minNumVisibleRecentTasks_lowRam" />
+  <java-symbol type="integer" name="config_maxNumVisibleRecentTasks_lowRam" />
+  <java-symbol type="integer" name="config_minNumVisibleRecentTasks_grid" />
+  <java-symbol type="integer" name="config_maxNumVisibleRecentTasks_grid" />
+  <java-symbol type="integer" name="config_minNumVisibleRecentTasks" />
+  <java-symbol type="integer" name="config_maxNumVisibleRecentTasks" />
+  <java-symbol type="integer" name="config_activeTaskDurationHours" />
   <java-symbol type="bool" name="config_windowShowCircularMask" />
   <java-symbol type="bool" name="config_windowEnableCircularEmulatorDisplayOverlay" />
   <java-symbol type="bool" name="config_wifi_framework_enable_associated_network_selection" />
@@ -447,6 +454,7 @@
   <java-symbol type="integer" name="config_keepPreloadsMinDays" />
   <java-symbol type="bool" name="config_hasPermanentDpad" />
   <java-symbol type="bool" name="config_useDefaultFocusHighlight" />
+  <java-symbol type="array" name="config_deviceSpecificSystemServices" />
 
   <java-symbol type="color" name="tab_indicator_text_v4" />
 
@@ -746,7 +754,6 @@
   <java-symbol type="string" name="last_month" />
   <java-symbol type="string" name="launchBrowserDefault" />
   <java-symbol type="string" name="lock_to_app_toast" />
-  <java-symbol type="string" name="lock_to_app_toast_locked" />
   <java-symbol type="string" name="lock_to_app_start" />
   <java-symbol type="string" name="lock_to_app_exit" />
   <java-symbol type="string" name="lock_to_app_unlock_pin" />
@@ -987,8 +994,6 @@
   <java-symbol type="string" name="volume_icon_description_notification" />
   <java-symbol type="string" name="volume_icon_description_ringer" />
   <java-symbol type="string" name="wait" />
-  <java-symbol type="string" name="web_user_agent" />
-  <java-symbol type="string" name="web_user_agent_target_content" />
   <java-symbol type="string" name="webpage_unresponsive" />
   <java-symbol type="string" name="whichApplication" />
   <java-symbol type="string" name="whichHomeApplication" />
@@ -1896,9 +1901,6 @@
   <java-symbol type="string" name="anr_application_process" />
   <java-symbol type="string" name="anr_process" />
   <java-symbol type="string" name="anr_title" />
-  <java-symbol type="string" name="top_app_killed_title" />
-  <java-symbol type="string" name="top_app_killed_message" />
-  <java-symbol type="string" name="close" />
   <java-symbol type="string" name="car_mode_disable_notification_message" />
   <java-symbol type="string" name="car_mode_disable_notification_title" />
   <java-symbol type="string" name="chooser_wallpaper" />
@@ -3116,4 +3118,9 @@
   <java-symbol type="dimen" name="slice_icon_size" />
   <java-symbol type="dimen" name="slice_padding" />
   <java-symbol type="string" name="slice_more_content" />
+
+  <java-symbol type="string" name="shortcut_restored_on_lower_version" />
+  <java-symbol type="string" name="shortcut_restore_not_supported" />
+  <java-symbol type="string" name="shortcut_restore_signature_mismatch" />
+  <java-symbol type="string" name="shortcut_restore_unknown_issue" />
 </resources>
diff --git a/core/res/res/xml/default_zen_mode_config.xml b/core/res/res/xml/default_zen_mode_config.xml
index 5f4199a..1e4c03e 100644
--- a/core/res/res/xml/default_zen_mode_config.xml
+++ b/core/res/res/xml/default_zen_mode_config.xml
@@ -19,5 +19,5 @@
 
 <!-- Default configuration for zen mode.  See android.service.notification.ZenModeConfig. -->
 <zen version="2">
-    <allow calls="true" messages="false" reminders="true" events="true" />
+    <allow alarms="true" media_system_other="true" calls="false" messages="false" reminders="false" events="false" />
 </zen>
diff --git a/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttf b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttf
deleted file mode 100644
index 1bad6fe..0000000
--- a/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttf
+++ /dev/null
Binary files differ
diff --git a/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttx b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttx
deleted file mode 100644
index 0cf0f79..0000000
--- a/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttx
+++ /dev/null
@@ -1,207 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
-
-  <GlyphOrder>
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="0em"/>
-    <GlyphID id="2" name="1em"/>
-    <GlyphID id="3" name="3em"/>
-    <GlyphID id="4" name="5em"/>
-    <GlyphID id="5" name="7em"/>
-    <GlyphID id="6" name="10em"/>
-    <GlyphID id="7" name="50em"/>
-    <GlyphID id="8" name="100em"/>
-  </GlyphOrder>
-
-  <head>
-    <tableVersion value="1.0"/>
-    <fontRevision value="1.0"/>
-    <checkSumAdjustment value="0x640cdb2f"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00000011"/>
-    <unitsPerEm value="100"/>
-    <created value="Fri Mar 17 07:26:00 2017"/>
-    <macStyle value="00000000 00000000"/>
-    <lowestRecPPEM value="7"/>
-    <fontDirectionHint value="2"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="1000"/>
-    <descent value="-200"/>
-    <lineGap value="0"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-  </hhea>
-
-  <maxp>
-    <tableVersion value="0x10000"/>
-    <maxZones value="0"/>
-    <maxTwilightPoints value="0"/>
-    <maxStorage value="0"/>
-    <maxFunctionDefs value="0"/>
-    <maxInstructionDefs value="0"/>
-    <maxStackElements value="0"/>
-    <maxSizeOfInstructions value="0"/>
-    <maxComponentElements value="0"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="3"/>
-    <xAvgCharWidth value="594"/>
-    <usWeightClass value="400"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00001000"/>
-    <ySubscriptXSize value="650"/>
-    <ySubscriptYSize value="600"/>
-    <ySubscriptXOffset value="0"/>
-    <ySubscriptYOffset value="75"/>
-    <ySuperscriptXSize value="650"/>
-    <ySuperscriptYSize value="600"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="350"/>
-    <yStrikeoutSize value="50"/>
-    <yStrikeoutPosition value="300"/>
-    <sFamilyClass value="0"/>
-    <panose>
-      <bFamilyType value="0"/>
-      <bSerifStyle value="0"/>
-      <bWeight value="5"/>
-      <bProportion value="0"/>
-      <bContrast value="0"/>
-      <bStrokeVariation value="0"/>
-      <bArmStyle value="0"/>
-      <bLetterForm value="0"/>
-      <bMidline value="0"/>
-      <bXHeight value="0"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="UKWN"/>
-    <fsSelection value="00000000 01000000"/>
-    <usFirstCharIndex value="32"/>
-    <usLastCharIndex value="122"/>
-    <sTypoAscender value="800"/>
-    <sTypoDescender value="-200"/>
-    <sTypoLineGap value="200"/>
-    <usWinAscent value="1000"/>
-    <usWinDescent value="200"/>
-    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
-    <sxHeight value="500"/>
-    <sCapHeight value="700"/>
-    <usDefaultChar value="0"/>
-    <usBreakChar value="32"/>
-    <usMaxContext value="0"/>
-  </OS_2>
-
-  <hmtx>
-    <mtx name=".notdef" width="50" lsb="0"/>
-    <mtx name="0em" width="0" lsb="0"/>
-    <mtx name="1em" width="100" lsb="0"/>
-    <mtx name="3em" width="300" lsb="0"/>
-    <mtx name="5em" width="500" lsb="0"/>
-    <mtx name="7em" width="700" lsb="0"/>
-    <mtx name="10em" width="1000" lsb="0"/>
-    <mtx name="50em" width="5000" lsb="0"/>
-    <mtx name="100em" width="10000" lsb="0"/>
-  </hmtx>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_12 format="12" reserved="0" length="6" nGroups="1" platformID="3" platEncID="10" language="0">
-      <map code="0x0020" name="10em" />
-      <map code="0x002e" name="10em" />  <!-- . -->
-      <map code="0x0043" name="100em" />  <!-- C -->
-      <map code="0x0049" name="1em" />  <!-- I -->
-      <map code="0x004c" name="50em" />  <!-- L -->
-      <map code="0x0056" name="5em" />  <!-- V -->
-      <map code="0x0058" name="10em" />  <!-- X -->
-      <map code="0x005f" name="0em" /> <!-- _ -->
-      <map code="0xfffd" name="7em" /> <!-- REPLACEMENT CHAR -->
-      <map code="0x10331" name="10em" />
-    </cmap_format_12>
-  </cmap>
-
-  <loca>
-    <!-- The 'loca' table will be calculated by the compiler -->
-  </loca>
-
-  <glyf>
-    <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
-    <TTGlyph name="0em" xMin="0" yMin="0" xMax="0" yMax="0" />
-    <TTGlyph name="1em" xMin="0" yMin="0" xMax="0" yMax="0" />
-    <TTGlyph name="3em" xMin="0" yMin="0" xMax="0" yMax="0" />
-    <TTGlyph name="5em" xMin="0" yMin="0" xMax="0" yMax="0" />
-    <TTGlyph name="7em" xMin="0" yMin="0" xMax="0" yMax="0" />
-    <TTGlyph name="10em" xMin="0" yMin="0" xMax="0" yMax="0" />
-    <TTGlyph name="50em" xMin="0" yMin="0" xMax="0" yMax="0" />
-    <TTGlyph name="100em" xMin="0" yMin="0" xMax="0" yMax="0" />
-  </glyf>
-
-  <name>
-    <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Font for StaticLayoutLineBreakingTest
-    </namerecord>
-    <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Regular
-    </namerecord>
-    <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Font for StaticLayoutLineBreakingTest
-    </namerecord>
-    <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      SampleFont-Regular
-    </namerecord>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      Sample Font
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      Sample Font
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      SampleFont-Regular
-    </namerecord>
-  </name>
-
-  <post>
-    <formatType value="3.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-75"/>
-    <underlineThickness value="50"/>
-    <isFixedPitch value="0"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="0"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="0"/>
-  </post>
-
-</ttFont>
diff --git a/core/tests/coretests/res/font/samplexmlfont.xml b/core/tests/coretests/res/font/samplexmlfont.xml
index bb813e1..59d615f 100644
--- a/core/tests/coretests/res/font/samplexmlfont.xml
+++ b/core/tests/coretests/res/font/samplexmlfont.xml
@@ -1,7 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <font-family xmlns:android="http://schemas.android.com/apk/res/android">
-    <font android:fontStyle="normal" android:fontWeight="400" android:font="@font/samplefont" />
-    <font android:fontStyle="italic" android:fontWeight="400" android:font="@font/samplefont2" />
-    <font android:fontStyle="normal" android:fontWeight="800" android:font="@font/samplefont3" />
+    <font android:fontStyle="normal" android:fontWeight="400" android:font="@font/samplefont"
+          android:ttcIndex="0"/>
+    <font android:fontStyle="italic" android:fontWeight="400" android:font="@font/samplefont2"
+          android:ttcIndex="1"/>
+    <font android:fontStyle="normal" android:fontWeight="800" android:font="@font/samplefont3"
+          android:ttcIndex="2" />
     <font android:fontStyle="italic" android:fontWeight="800" android:font="@font/samplefont4" />
 </font-family>
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
index 9c904d1..4d1a9f4 100644
--- a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
+++ b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
@@ -69,18 +69,22 @@
         FontFileResourceEntry font1 = fileEntries[0];
         assertEquals(400, font1.getWeight());
         assertEquals(0, font1.getItalic());
+        assertEquals(0, font1.getTtcIndex());
         assertEquals("res/font/samplefont.ttf", font1.getFileName());
         FontFileResourceEntry font2 = fileEntries[1];
         assertEquals(400, font2.getWeight());
         assertEquals(1, font2.getItalic());
+        assertEquals(1, font2.getTtcIndex());
         assertEquals("res/font/samplefont2.ttf", font2.getFileName());
         FontFileResourceEntry font3 = fileEntries[2];
         assertEquals(800, font3.getWeight());
         assertEquals(0, font3.getItalic());
+        assertEquals(2, font3.getTtcIndex());
         assertEquals("res/font/samplefont3.ttf", font3.getFileName());
         FontFileResourceEntry font4 = fileEntries[3];
         assertEquals(800, font4.getWeight());
         assertEquals(1, font4.getItalic());
+        assertEquals(0, font4.getTtcIndex());
         assertEquals("res/font/samplefont4.ttf", font4.getFileName());
     }
 
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteCursorTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteCursorTest.java
index 9ccc6e8..c52cf6e 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteCursorTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteCursorTest.java
@@ -18,18 +18,25 @@
 
 import android.content.ContentValues;
 import android.content.Context;
+import android.database.AbstractWindowedCursor;
 import android.database.Cursor;
+import android.database.CursorWindow;
+import android.platform.test.annotations.Presubmit;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 
 import java.io.File;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Set;
 
+@Presubmit
+@LargeTest
 public class SQLiteCursorTest extends AndroidTestCase {
+    private static final String TABLE_NAME = "testCursor";
     private SQLiteDatabase mDatabase;
     private File mDatabaseFile;
-    private static final String TABLE_NAME = "testCursor";
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -55,7 +62,6 @@
     /**
      * this test could take a while to execute. so, designate it as LargeTest
      */
-    @LargeTest
     public void testFillWindow() {
         // create schema
         final String testTable = "testV";
@@ -138,7 +144,7 @@
             // nothing to do - just scrolling to about half-point in the resultset
         }
         mDatabase.beginTransaction();
-        mDatabase.delete(testTable, "col1 < ?", new String[]{ (3 * M / 4) + ""});
+        mDatabase.delete(testTable, "col1 < ?", new String[]{(3 * M / 4) + ""});
         mDatabase.setTransactionSuccessful();
         mDatabase.endTransaction();
         c.requery();
@@ -149,4 +155,35 @@
         }
         c.close();
     }
-}
+
+    public void testCustomWindowSize() {
+        mDatabase.execSQL("CREATE TABLE Tst (Txt BLOB NOT NULL);");
+        byte[] testArr = new byte[10000];
+        Arrays.fill(testArr, (byte) 1);
+        for (int i = 0; i < 10; i++) {
+            mDatabase.execSQL("INSERT INTO Tst VALUES (?)", new Object[]{testArr});
+        }
+        Cursor cursor = mDatabase.rawQuery("SELECT * FROM TST", null);
+        // With default window size, all rows should fit in RAM
+        AbstractWindowedCursor ac = (AbstractWindowedCursor) cursor;
+        int n = 0;
+        while (ac.moveToNext()) {
+            n++;
+            assertEquals(10, ac.getWindow().getNumRows());
+        }
+        assertEquals("All rows should be visited", 10, n);
+
+        // Now reduce window size, so that only 1 row can fit
+        cursor = mDatabase.rawQuery("SELECT * FROM TST", null);
+        CursorWindow cw = new CursorWindow("test", 11000);
+        ac = (AbstractWindowedCursor) cursor;
+        ac.setWindow(cw);
+        ac.move(-10);
+        n = 0;
+        while (ac.moveToNext()) {
+            n++;
+            assertEquals(1, cw.getNumRows());
+        }
+        assertEquals("All rows should be visited", 10, n);
+    }
+}
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
deleted file mode 100644
index 1cb0ecd..0000000
--- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java
+++ /dev/null
@@ -1,789 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.LinkProperties.CompareResult;
-import android.net.LinkProperties.ProvisioningChange;
-import android.net.RouteInfo;
-import android.system.OsConstants;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
-import android.util.ArraySet;
-
-import junit.framework.TestCase;
-
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-
-public class LinkPropertiesTest extends TestCase {
-    private static InetAddress ADDRV4 = NetworkUtils.numericToInetAddress("75.208.6.1");
-    private static InetAddress ADDRV6 = NetworkUtils.numericToInetAddress(
-            "2001:0db8:85a3:0000:0000:8a2e:0370:7334");
-    private static InetAddress DNS1 = NetworkUtils.numericToInetAddress("75.208.7.1");
-    private static InetAddress DNS2 = NetworkUtils.numericToInetAddress("69.78.7.1");
-    private static InetAddress DNS6 = NetworkUtils.numericToInetAddress("2001:4860:4860::8888");
-    private static InetAddress GATEWAY1 = NetworkUtils.numericToInetAddress("75.208.8.1");
-    private static InetAddress GATEWAY2 = NetworkUtils.numericToInetAddress("69.78.8.1");
-    private static InetAddress GATEWAY61 = NetworkUtils.numericToInetAddress("fe80::6:0000:613");
-    private static InetAddress GATEWAY62 = NetworkUtils.numericToInetAddress("fe80::6:2222");
-    private static String NAME = "qmi0";
-    private static int MTU = 1500;
-
-    private static LinkAddress LINKADDRV4 = new LinkAddress(ADDRV4, 32);
-    private static LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128);
-    private static LinkAddress LINKADDRV6LINKLOCAL = new LinkAddress("fe80::1/64");
-
-    // TODO: replace all calls to NetworkUtils.numericToInetAddress with calls to this method.
-    private InetAddress Address(String addrString) {
-        return NetworkUtils.numericToInetAddress(addrString);
-    }
-
-    public void assertLinkPropertiesEqual(LinkProperties source, LinkProperties target) {
-        // Check implementation of equals(), element by element.
-        assertTrue(source.isIdenticalInterfaceName(target));
-        assertTrue(target.isIdenticalInterfaceName(source));
-
-        assertTrue(source.isIdenticalAddresses(target));
-        assertTrue(target.isIdenticalAddresses(source));
-
-        assertTrue(source.isIdenticalDnses(target));
-        assertTrue(target.isIdenticalDnses(source));
-
-        assertTrue(source.isIdenticalRoutes(target));
-        assertTrue(target.isIdenticalRoutes(source));
-
-        assertTrue(source.isIdenticalHttpProxy(target));
-        assertTrue(target.isIdenticalHttpProxy(source));
-
-        assertTrue(source.isIdenticalStackedLinks(target));
-        assertTrue(target.isIdenticalStackedLinks(source));
-
-        assertTrue(source.isIdenticalMtu(target));
-        assertTrue(target.isIdenticalMtu(source));
-
-        // Check result of equals().
-        assertTrue(source.equals(target));
-        assertTrue(target.equals(source));
-
-        // Check hashCode.
-        assertEquals(source.hashCode(), target.hashCode());
-    }
-
-    @SmallTest
-    public void testEqualsNull() {
-        LinkProperties source = new LinkProperties();
-        LinkProperties target = new LinkProperties();
-
-        assertFalse(source == target);
-        assertLinkPropertiesEqual(source, target);
-    }
-
-    @SmallTest
-    public void testEqualsSameOrder() {
-        try {
-            LinkProperties source = new LinkProperties();
-            source.setInterfaceName(NAME);
-            // set 2 link addresses
-            source.addLinkAddress(LINKADDRV4);
-            source.addLinkAddress(LINKADDRV6);
-            // set 2 dnses
-            source.addDnsServer(DNS1);
-            source.addDnsServer(DNS2);
-            // set 2 gateways
-            source.addRoute(new RouteInfo(GATEWAY1));
-            source.addRoute(new RouteInfo(GATEWAY2));
-            source.setMtu(MTU);
-
-            LinkProperties target = new LinkProperties();
-
-            // All fields are same
-            target.setInterfaceName(NAME);
-            target.addLinkAddress(LINKADDRV4);
-            target.addLinkAddress(LINKADDRV6);
-            target.addDnsServer(DNS1);
-            target.addDnsServer(DNS2);
-            target.addRoute(new RouteInfo(GATEWAY1));
-            target.addRoute(new RouteInfo(GATEWAY2));
-            target.setMtu(MTU);
-
-            assertLinkPropertiesEqual(source, target);
-
-            target.clear();
-            // change Interface Name
-            target.setInterfaceName("qmi1");
-            target.addLinkAddress(LINKADDRV4);
-            target.addLinkAddress(LINKADDRV6);
-            target.addDnsServer(DNS1);
-            target.addDnsServer(DNS2);
-            target.addRoute(new RouteInfo(GATEWAY1));
-            target.addRoute(new RouteInfo(GATEWAY2));
-            target.setMtu(MTU);
-            assertFalse(source.equals(target));
-
-            target.clear();
-            target.setInterfaceName(NAME);
-            // change link addresses
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress("75.208.6.2"), 32));
-            target.addLinkAddress(LINKADDRV6);
-            target.addDnsServer(DNS1);
-            target.addDnsServer(DNS2);
-            target.addRoute(new RouteInfo(GATEWAY1));
-            target.addRoute(new RouteInfo(GATEWAY2));
-            target.setMtu(MTU);
-            assertFalse(source.equals(target));
-
-            target.clear();
-            target.setInterfaceName(NAME);
-            target.addLinkAddress(LINKADDRV4);
-            target.addLinkAddress(LINKADDRV6);
-            // change dnses
-            target.addDnsServer(NetworkUtils.numericToInetAddress("75.208.7.2"));
-            target.addDnsServer(DNS2);
-            target.addRoute(new RouteInfo(GATEWAY1));
-            target.addRoute(new RouteInfo(GATEWAY2));
-            target.setMtu(MTU);
-            assertFalse(source.equals(target));
-
-            target.clear();
-            target.setInterfaceName(NAME);
-            target.addLinkAddress(LINKADDRV4);
-            target.addLinkAddress(LINKADDRV6);
-            target.addDnsServer(DNS1);
-            target.addDnsServer(DNS2);
-            // change gateway
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2")));
-            target.addRoute(new RouteInfo(GATEWAY2));
-            target.setMtu(MTU);
-            assertFalse(source.equals(target));
-
-            target.clear();
-            target.setInterfaceName(NAME);
-            target.addLinkAddress(LINKADDRV4);
-            target.addLinkAddress(LINKADDRV6);
-            target.addDnsServer(DNS1);
-            target.addDnsServer(DNS2);
-            target.addRoute(new RouteInfo(GATEWAY1));
-            target.addRoute(new RouteInfo(GATEWAY2));
-            // change mtu
-            target.setMtu(1440);
-            assertFalse(source.equals(target));
-
-        } catch (Exception e) {
-            throw new RuntimeException(e.toString());
-            //fail();
-        }
-    }
-
-    @SmallTest
-    public void testEqualsDifferentOrder() {
-        try {
-            LinkProperties source = new LinkProperties();
-            source.setInterfaceName(NAME);
-            // set 2 link addresses
-            source.addLinkAddress(LINKADDRV4);
-            source.addLinkAddress(LINKADDRV6);
-            // set 2 dnses
-            source.addDnsServer(DNS1);
-            source.addDnsServer(DNS2);
-            // set 2 gateways
-            source.addRoute(new RouteInfo(GATEWAY1));
-            source.addRoute(new RouteInfo(GATEWAY2));
-            source.setMtu(MTU);
-
-            LinkProperties target = new LinkProperties();
-            // Exchange order
-            target.setInterfaceName(NAME);
-            target.addLinkAddress(LINKADDRV6);
-            target.addLinkAddress(LINKADDRV4);
-            target.addDnsServer(DNS2);
-            target.addDnsServer(DNS1);
-            target.addRoute(new RouteInfo(GATEWAY2));
-            target.addRoute(new RouteInfo(GATEWAY1));
-            target.setMtu(MTU);
-
-            assertLinkPropertiesEqual(source, target);
-        } catch (Exception e) {
-            fail();
-        }
-    }
-
-    @SmallTest
-    public void testEqualsDuplicated() {
-        try {
-            LinkProperties source = new LinkProperties();
-            // set 3 link addresses, eg, [A, A, B]
-            source.addLinkAddress(LINKADDRV4);
-            source.addLinkAddress(LINKADDRV4);
-            source.addLinkAddress(LINKADDRV6);
-
-            LinkProperties target = new LinkProperties();
-            // set 3 link addresses, eg, [A, B, B]
-            target.addLinkAddress(LINKADDRV4);
-            target.addLinkAddress(LINKADDRV6);
-            target.addLinkAddress(LINKADDRV6);
-
-            assertLinkPropertiesEqual(source, target);
-        } catch (Exception e) {
-            fail();
-        }
-    }
-
-    private void assertAllRoutesHaveInterface(String iface, LinkProperties lp) {
-        for (RouteInfo r : lp.getRoutes()) {
-            assertEquals(iface, r.getInterface());
-        }
-    }
-
-    @SmallTest
-    public void testRouteInterfaces() {
-        LinkAddress prefix = new LinkAddress(
-            NetworkUtils.numericToInetAddress("2001:db8::"), 32);
-        InetAddress address = ADDRV6;
-
-        // Add a route with no interface to a LinkProperties with no interface. No errors.
-        LinkProperties lp = new LinkProperties();
-        RouteInfo r = new RouteInfo(prefix, address, null);
-        assertTrue(lp.addRoute(r));
-        assertEquals(1, lp.getRoutes().size());
-        assertAllRoutesHaveInterface(null, lp);
-
-        // Adding the same route twice has no effect.
-        assertFalse(lp.addRoute(r));
-        assertEquals(1, lp.getRoutes().size());
-
-        // Add a route with an interface. Expect an exception.
-        r = new RouteInfo(prefix, address, "wlan0");
-        try {
-          lp.addRoute(r);
-          fail("Adding wlan0 route to LP with no interface, expect exception");
-        } catch (IllegalArgumentException expected) {}
-
-        // Change the interface name. All the routes should change their interface name too.
-        lp.setInterfaceName("rmnet0");
-        assertAllRoutesHaveInterface("rmnet0", lp);
-
-        // Now add a route with the wrong interface. This causes an exception too.
-        try {
-          lp.addRoute(r);
-          fail("Adding wlan0 route to rmnet0 LP, expect exception");
-        } catch (IllegalArgumentException expected) {}
-
-        // If the interface name matches, the route is added.
-        r = new RouteInfo(prefix, null, "wlan0");
-        lp.setInterfaceName("wlan0");
-        lp.addRoute(r);
-        assertEquals(2, lp.getRoutes().size());
-        assertAllRoutesHaveInterface("wlan0", lp);
-
-        // Routes with null interfaces are converted to wlan0.
-        r = RouteInfo.makeHostRoute(ADDRV6, null);
-        lp.addRoute(r);
-        assertEquals(3, lp.getRoutes().size());
-        assertAllRoutesHaveInterface("wlan0", lp);
-
-        // Check comparisons work.
-        LinkProperties lp2 = new LinkProperties(lp);
-        assertAllRoutesHaveInterface("wlan0", lp);
-        assertEquals(0, lp.compareAllRoutes(lp2).added.size());
-        assertEquals(0, lp.compareAllRoutes(lp2).removed.size());
-
-        lp2.setInterfaceName("p2p0");
-        assertAllRoutesHaveInterface("p2p0", lp2);
-        assertEquals(3, lp.compareAllRoutes(lp2).added.size());
-        assertEquals(3, lp.compareAllRoutes(lp2).removed.size());
-    }
-
-    @SmallTest
-    public void testStackedInterfaces() {
-        LinkProperties rmnet0 = new LinkProperties();
-        rmnet0.setInterfaceName("rmnet0");
-        rmnet0.addLinkAddress(LINKADDRV6);
-
-        LinkProperties clat4 = new LinkProperties();
-        clat4.setInterfaceName("clat4");
-        clat4.addLinkAddress(LINKADDRV4);
-
-        assertEquals(0, rmnet0.getStackedLinks().size());
-        assertEquals(1, rmnet0.getAddresses().size());
-        assertEquals(1, rmnet0.getLinkAddresses().size());
-        assertEquals(1, rmnet0.getAllAddresses().size());
-        assertEquals(1, rmnet0.getAllLinkAddresses().size());
-
-        rmnet0.addStackedLink(clat4);
-        assertEquals(1, rmnet0.getStackedLinks().size());
-        assertEquals(1, rmnet0.getAddresses().size());
-        assertEquals(1, rmnet0.getLinkAddresses().size());
-        assertEquals(2, rmnet0.getAllAddresses().size());
-        assertEquals(2, rmnet0.getAllLinkAddresses().size());
-
-        rmnet0.addStackedLink(clat4);
-        assertEquals(1, rmnet0.getStackedLinks().size());
-        assertEquals(1, rmnet0.getAddresses().size());
-        assertEquals(1, rmnet0.getLinkAddresses().size());
-        assertEquals(2, rmnet0.getAllAddresses().size());
-        assertEquals(2, rmnet0.getAllLinkAddresses().size());
-
-        assertEquals(0, clat4.getStackedLinks().size());
-
-        // Modify an item in the returned collection to see what happens.
-        for (LinkProperties link : rmnet0.getStackedLinks()) {
-            if (link.getInterfaceName().equals("clat4")) {
-               link.setInterfaceName("newname");
-            }
-        }
-        for (LinkProperties link : rmnet0.getStackedLinks()) {
-            assertFalse("newname".equals(link.getInterfaceName()));
-        }
-
-        assertTrue(rmnet0.removeStackedLink("clat4"));
-        assertEquals(0, rmnet0.getStackedLinks().size());
-        assertEquals(1, rmnet0.getAddresses().size());
-        assertEquals(1, rmnet0.getLinkAddresses().size());
-        assertEquals(1, rmnet0.getAllAddresses().size());
-        assertEquals(1, rmnet0.getAllLinkAddresses().size());
-
-        assertFalse(rmnet0.removeStackedLink("clat4"));
-    }
-
-    private LinkAddress getFirstLinkAddress(LinkProperties lp) {
-        return lp.getLinkAddresses().iterator().next();
-    }
-
-    @SmallTest
-    public void testAddressMethods() {
-        LinkProperties lp = new LinkProperties();
-
-        // No addresses.
-        assertFalse(lp.hasIPv4Address());
-        assertFalse(lp.hasGlobalIPv6Address());
-
-        // Addresses on stacked links don't count.
-        LinkProperties stacked = new LinkProperties();
-        stacked.setInterfaceName("stacked");
-        lp.addStackedLink(stacked);
-        stacked.addLinkAddress(LINKADDRV4);
-        stacked.addLinkAddress(LINKADDRV6);
-        assertTrue(stacked.hasIPv4Address());
-        assertTrue(stacked.hasGlobalIPv6Address());
-        assertFalse(lp.hasIPv4Address());
-        assertFalse(lp.hasGlobalIPv6Address());
-        lp.removeStackedLink("stacked");
-        assertFalse(lp.hasIPv4Address());
-        assertFalse(lp.hasGlobalIPv6Address());
-
-        // Addresses on the base link.
-        // Check the return values of hasIPvXAddress and ensure the add/remove methods return true
-        // iff something changes.
-        assertEquals(0, lp.getLinkAddresses().size());
-        assertTrue(lp.addLinkAddress(LINKADDRV6));
-        assertEquals(1, lp.getLinkAddresses().size());
-        assertFalse(lp.hasIPv4Address());
-        assertTrue(lp.hasGlobalIPv6Address());
-
-        assertTrue(lp.removeLinkAddress(LINKADDRV6));
-        assertEquals(0, lp.getLinkAddresses().size());
-
-        assertTrue(lp.addLinkAddress(LINKADDRV6LINKLOCAL));
-        assertEquals(1, lp.getLinkAddresses().size());
-        assertFalse(lp.hasGlobalIPv6Address());
-
-        assertTrue(lp.addLinkAddress(LINKADDRV4));
-        assertEquals(2, lp.getLinkAddresses().size());
-        assertTrue(lp.hasIPv4Address());
-        assertFalse(lp.hasGlobalIPv6Address());
-
-        assertTrue(lp.addLinkAddress(LINKADDRV6));
-        assertEquals(3, lp.getLinkAddresses().size());
-        assertTrue(lp.hasIPv4Address());
-        assertTrue(lp.hasGlobalIPv6Address());
-
-        assertTrue(lp.removeLinkAddress(LINKADDRV6LINKLOCAL));
-        assertEquals(2, lp.getLinkAddresses().size());
-        assertTrue(lp.hasIPv4Address());
-        assertTrue(lp.hasGlobalIPv6Address());
-
-        // Adding an address twice has no effect.
-        // Removing an address that's not present has no effect.
-        assertFalse(lp.addLinkAddress(LINKADDRV4));
-        assertEquals(2, lp.getLinkAddresses().size());
-        assertTrue(lp.hasIPv4Address());
-        assertTrue(lp.removeLinkAddress(LINKADDRV4));
-        assertEquals(1, lp.getLinkAddresses().size());
-        assertFalse(lp.hasIPv4Address());
-        assertFalse(lp.removeLinkAddress(LINKADDRV4));
-        assertEquals(1, lp.getLinkAddresses().size());
-
-        // Adding an address that's already present but with different properties causes the
-        // existing address to be updated and returns true.
-        // Start with only LINKADDRV6.
-        assertEquals(1, lp.getLinkAddresses().size());
-        assertEquals(LINKADDRV6, getFirstLinkAddress(lp));
-
-        // Create a LinkAddress object for the same address, but with different flags.
-        LinkAddress deprecated = new LinkAddress(ADDRV6, 128,
-                OsConstants.IFA_F_DEPRECATED, OsConstants.RT_SCOPE_UNIVERSE);
-        assertTrue(deprecated.isSameAddressAs(LINKADDRV6));
-        assertFalse(deprecated.equals(LINKADDRV6));
-
-        // Check that adding it updates the existing address instead of adding a new one.
-        assertTrue(lp.addLinkAddress(deprecated));
-        assertEquals(1, lp.getLinkAddresses().size());
-        assertEquals(deprecated, getFirstLinkAddress(lp));
-        assertFalse(LINKADDRV6.equals(getFirstLinkAddress(lp)));
-
-        // Removing LINKADDRV6 removes deprecated, because removing addresses ignores properties.
-        assertTrue(lp.removeLinkAddress(LINKADDRV6));
-        assertEquals(0, lp.getLinkAddresses().size());
-    }
-
-    @SmallTest
-    public void testSetLinkAddresses() {
-        LinkProperties lp = new LinkProperties();
-        lp.addLinkAddress(LINKADDRV4);
-        lp.addLinkAddress(LINKADDRV6);
-
-        LinkProperties lp2 = new LinkProperties();
-        lp2.addLinkAddress(LINKADDRV6);
-
-        assertFalse(lp.equals(lp2));
-
-        lp2.setLinkAddresses(lp.getLinkAddresses());
-        assertTrue(lp.equals(lp));
-    }
-
-    @SmallTest
-    public void testIsProvisioned() {
-        LinkProperties lp4 = new LinkProperties();
-        assertFalse("v4only:empty", lp4.isProvisioned());
-        lp4.addLinkAddress(LINKADDRV4);
-        assertFalse("v4only:addr-only", lp4.isProvisioned());
-        lp4.addDnsServer(DNS1);
-        assertFalse("v4only:addr+dns", lp4.isProvisioned());
-        lp4.addRoute(new RouteInfo(GATEWAY1));
-        assertTrue("v4only:addr+dns+route", lp4.isProvisioned());
-        assertTrue("v4only:addr+dns+route", lp4.isIPv4Provisioned());
-        assertFalse("v4only:addr+dns+route", lp4.isIPv6Provisioned());
-
-        LinkProperties lp6 = new LinkProperties();
-        assertFalse("v6only:empty", lp6.isProvisioned());
-        lp6.addLinkAddress(LINKADDRV6LINKLOCAL);
-        assertFalse("v6only:fe80-only", lp6.isProvisioned());
-        lp6.addDnsServer(DNS6);
-        assertFalse("v6only:fe80+dns", lp6.isProvisioned());
-        lp6.addRoute(new RouteInfo(GATEWAY61));
-        assertFalse("v6only:fe80+dns+route", lp6.isProvisioned());
-        lp6.addLinkAddress(LINKADDRV6);
-        assertTrue("v6only:fe80+global+dns+route", lp6.isIPv6Provisioned());
-        assertTrue("v6only:fe80+global+dns+route", lp6.isProvisioned());
-        lp6.removeLinkAddress(LINKADDRV6LINKLOCAL);
-        assertFalse("v6only:global+dns+route", lp6.isIPv4Provisioned());
-        assertTrue("v6only:global+dns+route", lp6.isIPv6Provisioned());
-        assertTrue("v6only:global+dns+route", lp6.isProvisioned());
-
-        LinkProperties lp46 = new LinkProperties();
-        lp46.addLinkAddress(LINKADDRV4);
-        lp46.addLinkAddress(LINKADDRV6);
-        lp46.addDnsServer(DNS1);
-        lp46.addDnsServer(DNS6);
-        assertFalse("dualstack:missing-routes", lp46.isProvisioned());
-        lp46.addRoute(new RouteInfo(GATEWAY1));
-        assertTrue("dualstack:v4-provisioned", lp46.isIPv4Provisioned());
-        assertFalse("dualstack:v4-provisioned", lp46.isIPv6Provisioned());
-        assertTrue("dualstack:v4-provisioned", lp46.isProvisioned());
-        lp46.addRoute(new RouteInfo(GATEWAY61));
-        assertTrue("dualstack:both-provisioned", lp46.isIPv4Provisioned());
-        assertTrue("dualstack:both-provisioned", lp46.isIPv6Provisioned());
-        assertTrue("dualstack:both-provisioned", lp46.isProvisioned());
-
-        // A link with an IPv6 address and default route, but IPv4 DNS server.
-        LinkProperties mixed = new LinkProperties();
-        mixed.addLinkAddress(LINKADDRV6);
-        mixed.addDnsServer(DNS1);
-        mixed.addRoute(new RouteInfo(GATEWAY61));
-        assertFalse("mixed:addr6+route6+dns4", mixed.isIPv4Provisioned());
-        assertFalse("mixed:addr6+route6+dns4", mixed.isIPv6Provisioned());
-        assertFalse("mixed:addr6+route6+dns4", mixed.isProvisioned());
-    }
-
-    @SmallTest
-    public void testCompareProvisioning() {
-        LinkProperties v4lp = new LinkProperties();
-        v4lp.addLinkAddress(LINKADDRV4);
-        v4lp.addRoute(new RouteInfo(GATEWAY1));
-        v4lp.addDnsServer(DNS1);
-        assertTrue(v4lp.isProvisioned());
-
-        LinkProperties v4r = new LinkProperties(v4lp);
-        v4r.removeDnsServer(DNS1);
-        assertFalse(v4r.isProvisioned());
-
-        assertEquals(ProvisioningChange.STILL_NOT_PROVISIONED,
-                LinkProperties.compareProvisioning(v4r, v4r));
-        assertEquals(ProvisioningChange.LOST_PROVISIONING,
-                LinkProperties.compareProvisioning(v4lp, v4r));
-        assertEquals(ProvisioningChange.GAINED_PROVISIONING,
-                LinkProperties.compareProvisioning(v4r, v4lp));
-        assertEquals(ProvisioningChange.STILL_PROVISIONED,
-                LinkProperties.compareProvisioning(v4lp, v4lp));
-
-        // Check that losing IPv4 provisioning on a dualstack network is
-        // seen as a total loss of provisioning.
-        LinkProperties v6lp = new LinkProperties();
-        v6lp.addLinkAddress(LINKADDRV6);
-        v6lp.addRoute(new RouteInfo(GATEWAY61));
-        v6lp.addDnsServer(DNS6);
-        assertFalse(v6lp.isIPv4Provisioned());
-        assertTrue(v6lp.isIPv6Provisioned());
-        assertTrue(v6lp.isProvisioned());
-
-        LinkProperties v46lp = new LinkProperties(v6lp);
-        v46lp.addLinkAddress(LINKADDRV4);
-        v46lp.addRoute(new RouteInfo(GATEWAY1));
-        v46lp.addDnsServer(DNS1);
-        assertTrue(v46lp.isIPv4Provisioned());
-        assertTrue(v46lp.isIPv6Provisioned());
-        assertTrue(v46lp.isProvisioned());
-
-        assertEquals(ProvisioningChange.STILL_PROVISIONED,
-                LinkProperties.compareProvisioning(v4lp, v46lp));
-        assertEquals(ProvisioningChange.STILL_PROVISIONED,
-                LinkProperties.compareProvisioning(v6lp, v46lp));
-        assertEquals(ProvisioningChange.LOST_PROVISIONING,
-                LinkProperties.compareProvisioning(v46lp, v6lp));
-        assertEquals(ProvisioningChange.LOST_PROVISIONING,
-                LinkProperties.compareProvisioning(v46lp, v4lp));
-
-        // Check that losing and gaining a secondary router does not change
-        // the provisioning status.
-        LinkProperties v6lp2 = new LinkProperties(v6lp);
-        v6lp2.addRoute(new RouteInfo(GATEWAY62));
-        assertTrue(v6lp2.isProvisioned());
-
-        assertEquals(ProvisioningChange.STILL_PROVISIONED,
-                LinkProperties.compareProvisioning(v6lp2, v6lp));
-        assertEquals(ProvisioningChange.STILL_PROVISIONED,
-                LinkProperties.compareProvisioning(v6lp, v6lp2));
-    }
-
-    @SmallTest
-    @Suppress  // Failing.
-    public void testIsReachable() {
-        final LinkProperties v4lp = new LinkProperties();
-        assertFalse(v4lp.isReachable(DNS1));
-        assertFalse(v4lp.isReachable(DNS2));
-
-        // Add an on-link route, making the on-link DNS server reachable,
-        // but there is still no IPv4 address.
-        assertTrue(v4lp.addRoute(new RouteInfo(
-                new IpPrefix(NetworkUtils.numericToInetAddress("75.208.0.0"), 16))));
-        assertFalse(v4lp.isReachable(DNS1));
-        assertFalse(v4lp.isReachable(DNS2));
-
-        // Adding an IPv4 address (right now, any IPv4 address) means we use
-        // the routes to compute likely reachability.
-        assertTrue(v4lp.addLinkAddress(new LinkAddress(ADDRV4, 16)));
-        assertTrue(v4lp.isReachable(DNS1));
-        assertFalse(v4lp.isReachable(DNS2));
-
-        // Adding a default route makes the off-link DNS server reachable.
-        assertTrue(v4lp.addRoute(new RouteInfo(GATEWAY1)));
-        assertTrue(v4lp.isReachable(DNS1));
-        assertTrue(v4lp.isReachable(DNS2));
-
-        final LinkProperties v6lp = new LinkProperties();
-        final InetAddress kLinkLocalDns = NetworkUtils.numericToInetAddress("fe80::6:1");
-        final InetAddress kLinkLocalDnsWithScope = NetworkUtils.numericToInetAddress("fe80::6:2%43");
-        final InetAddress kOnLinkDns = NetworkUtils.numericToInetAddress("2001:db8:85a3::53");
-        assertFalse(v6lp.isReachable(kLinkLocalDns));
-        assertFalse(v6lp.isReachable(kLinkLocalDnsWithScope));
-        assertFalse(v6lp.isReachable(kOnLinkDns));
-        assertFalse(v6lp.isReachable(DNS6));
-
-        // Add a link-local route, making the link-local DNS servers reachable. Because
-        // we assume the presence of an IPv6 link-local address, link-local DNS servers
-        // are considered reachable, but only those with a non-zero scope identifier.
-        assertTrue(v6lp.addRoute(new RouteInfo(
-                new IpPrefix(NetworkUtils.numericToInetAddress("fe80::"), 64))));
-        assertFalse(v6lp.isReachable(kLinkLocalDns));
-        assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
-        assertFalse(v6lp.isReachable(kOnLinkDns));
-        assertFalse(v6lp.isReachable(DNS6));
-
-        // Add a link-local address--nothing changes.
-        assertTrue(v6lp.addLinkAddress(LINKADDRV6LINKLOCAL));
-        assertFalse(v6lp.isReachable(kLinkLocalDns));
-        assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
-        assertFalse(v6lp.isReachable(kOnLinkDns));
-        assertFalse(v6lp.isReachable(DNS6));
-
-        // Add a global route on link, but no global address yet. DNS servers reachable
-        // via a route that doesn't require a gateway: give them the benefit of the
-        // doubt and hope the link-local source address suffices for communication.
-        assertTrue(v6lp.addRoute(new RouteInfo(
-                new IpPrefix(NetworkUtils.numericToInetAddress("2001:db8:85a3::"), 64))));
-        assertFalse(v6lp.isReachable(kLinkLocalDns));
-        assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
-        assertTrue(v6lp.isReachable(kOnLinkDns));
-        assertFalse(v6lp.isReachable(DNS6));
-
-        // Add a global address; the on-link global address DNS server is (still)
-        // presumed reachable.
-        assertTrue(v6lp.addLinkAddress(new LinkAddress(ADDRV6, 64)));
-        assertFalse(v6lp.isReachable(kLinkLocalDns));
-        assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
-        assertTrue(v6lp.isReachable(kOnLinkDns));
-        assertFalse(v6lp.isReachable(DNS6));
-
-        // Adding a default route makes the off-link DNS server reachable.
-        assertTrue(v6lp.addRoute(new RouteInfo(GATEWAY62)));
-        assertFalse(v6lp.isReachable(kLinkLocalDns));
-        assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
-        assertTrue(v6lp.isReachable(kOnLinkDns));
-        assertTrue(v6lp.isReachable(DNS6));
-
-        // Check isReachable on stacked links. This requires that the source IP address be assigned
-        // on the interface returned by the route lookup.
-        LinkProperties stacked = new LinkProperties();
-
-        // Can't add a stacked link without an interface name.
-        stacked.setInterfaceName("v4-test0");
-        v6lp.addStackedLink(stacked);
-
-        InetAddress stackedAddress = Address("192.0.0.4");
-        LinkAddress stackedLinkAddress = new LinkAddress(stackedAddress, 32);
-        assertFalse(v6lp.isReachable(stackedAddress));
-        stacked.addLinkAddress(stackedLinkAddress);
-        assertFalse(v6lp.isReachable(stackedAddress));
-        stacked.addRoute(new RouteInfo(stackedLinkAddress));
-        assertTrue(stacked.isReachable(stackedAddress));
-        assertTrue(v6lp.isReachable(stackedAddress));
-
-        assertFalse(v6lp.isReachable(DNS1));
-        stacked.addRoute(new RouteInfo((IpPrefix) null, stackedAddress));
-        assertTrue(v6lp.isReachable(DNS1));
-    }
-
-    @SmallTest
-    public void testLinkPropertiesEnsureDirectlyConnectedRoutes() {
-        // IPv4 case: no route added initially
-        LinkProperties rmnet0 = new LinkProperties();
-        rmnet0.setInterfaceName("rmnet0");
-        rmnet0.addLinkAddress(new LinkAddress("10.0.0.2/8"));
-        RouteInfo directRoute0 = new RouteInfo(new IpPrefix("10.0.0.0/8"), null,
-                rmnet0.getInterfaceName());
-
-        // Since no routes is added explicitly, getAllRoutes() should return empty.
-        assertTrue(rmnet0.getAllRoutes().isEmpty());
-        rmnet0.ensureDirectlyConnectedRoutes();
-        // ensureDirectlyConnectedRoutes() should have added the missing local route.
-        assertEqualRoutes(Collections.singletonList(directRoute0), rmnet0.getAllRoutes());
-
-        // IPv4 case: both direct and default routes added initially
-        LinkProperties rmnet1 = new LinkProperties();
-        rmnet1.setInterfaceName("rmnet1");
-        rmnet1.addLinkAddress(new LinkAddress("10.0.0.3/8"));
-        RouteInfo defaultRoute1 = new RouteInfo((IpPrefix) null,
-                NetworkUtils.numericToInetAddress("10.0.0.1"), rmnet1.getInterfaceName());
-        RouteInfo directRoute1 = new RouteInfo(new IpPrefix("10.0.0.0/8"), null,
-                rmnet1.getInterfaceName());
-        rmnet1.addRoute(defaultRoute1);
-        rmnet1.addRoute(directRoute1);
-
-        // Check added routes
-        assertEqualRoutes(Arrays.asList(defaultRoute1, directRoute1), rmnet1.getAllRoutes());
-        // ensureDirectlyConnectedRoutes() shouldn't change the routes since direct connected
-        // route is already part of the configuration.
-        rmnet1.ensureDirectlyConnectedRoutes();
-        assertEqualRoutes(Arrays.asList(defaultRoute1, directRoute1), rmnet1.getAllRoutes());
-
-        // IPv6 case: only default routes added initially
-        LinkProperties rmnet2 = new LinkProperties();
-        rmnet2.setInterfaceName("rmnet2");
-        rmnet2.addLinkAddress(new LinkAddress("fe80::cafe/64"));
-        rmnet2.addLinkAddress(new LinkAddress("2001:db8::2/64"));
-        RouteInfo defaultRoute2 = new RouteInfo((IpPrefix) null,
-                NetworkUtils.numericToInetAddress("2001:db8::1"), rmnet2.getInterfaceName());
-        RouteInfo directRoute2 = new RouteInfo(new IpPrefix("2001:db8::/64"), null,
-                rmnet2.getInterfaceName());
-        RouteInfo linkLocalRoute2 = new RouteInfo(new IpPrefix("fe80::/64"), null,
-                rmnet2.getInterfaceName());
-        rmnet2.addRoute(defaultRoute2);
-
-        assertEqualRoutes(Arrays.asList(defaultRoute2), rmnet2.getAllRoutes());
-        rmnet2.ensureDirectlyConnectedRoutes();
-        assertEqualRoutes(Arrays.asList(defaultRoute2, directRoute2, linkLocalRoute2),
-                rmnet2.getAllRoutes());
-
-        // Corner case: no interface name
-        LinkProperties rmnet3 = new LinkProperties();
-        rmnet3.addLinkAddress(new LinkAddress("192.168.0.2/24"));
-        RouteInfo directRoute3 = new RouteInfo(new IpPrefix("192.168.0.0/24"), null,
-                rmnet3.getInterfaceName());
-
-        assertTrue(rmnet3.getAllRoutes().isEmpty());
-        rmnet3.ensureDirectlyConnectedRoutes();
-        assertEqualRoutes(Collections.singletonList(directRoute3), rmnet3.getAllRoutes());
-
-    }
-
-    @SmallTest
-    public void testCompareResult() {
-        // Either adding or removing items
-        testCompareResult(Arrays.asList(1, 2, 3, 4), Arrays.asList(1),
-                Arrays.asList(2, 3, 4), new ArrayList<>());
-        testCompareResult(Arrays.asList(1, 2), Arrays.asList(3, 2, 1, 4),
-                new ArrayList<>(), Arrays.asList(3, 4));
-
-
-        // adding and removing items at the same time
-        testCompareResult(Arrays.asList(1, 2, 3, 4), Arrays.asList(2, 3, 4, 5),
-                Arrays.asList(1), Arrays.asList(5));
-        testCompareResult(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6),
-                Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6));
-
-        // null cases
-        testCompareResult(Arrays.asList(1, 2, 3), null, Arrays.asList(1, 2, 3), new ArrayList<>());
-        testCompareResult(null, Arrays.asList(3, 2, 1), new ArrayList<>(), Arrays.asList(1, 2, 3));
-        testCompareResult(null, null, new ArrayList<>(), new ArrayList<>());
-    }
-
-    private void assertEqualRoutes(Collection<RouteInfo> expected, Collection<RouteInfo> actual) {
-        Set<RouteInfo> expectedSet = new ArraySet<>(expected);
-        Set<RouteInfo> actualSet = new ArraySet<>(actual);
-        // Duplicated entries in actual routes are considered failures
-        assertEquals(actual.size(), actualSet.size());
-
-        assertEquals(expectedSet, actualSet);
-    }
-
-    private <T> void testCompareResult(List<T> oldItems, List<T> newItems, List<T> expectRemoved,
-            List<T> expectAdded) {
-        CompareResult<T> result = new CompareResult<>(oldItems, newItems);
-        assertEquals(new ArraySet<>(expectAdded), new ArraySet<>(result.added));
-        assertEquals(new ArraySet<>(expectRemoved), (new ArraySet<>(result.removed)));
-    }
-}
diff --git a/core/tests/coretests/src/android/net/NetworkTest.java b/core/tests/coretests/src/android/net/NetworkTest.java
deleted file mode 100644
index 74b6d98..0000000
--- a/core/tests/coretests/src/android/net/NetworkTest.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 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 android.net;
-
-import static android.test.MoreAsserts.assertNotEqual;
-
-import android.net.LocalServerSocket;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
-import android.net.Network;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.net.Inet6Address;
-import java.net.SocketException;
-
-import junit.framework.TestCase;
-
-public class NetworkTest extends TestCase {
-    final Network mNetwork = new Network(99);
-
-    @SmallTest
-    public void testBindSocketOfInvalidFdThrows() throws Exception {
-
-        final FileDescriptor fd = new FileDescriptor();
-        assertFalse(fd.valid());
-
-        try {
-            mNetwork.bindSocket(fd);
-            fail("SocketException not thrown");
-        } catch (SocketException expected) {}
-    }
-
-    @SmallTest
-    public void testBindSocketOfNonSocketFdThrows() throws Exception {
-        final File devNull = new File("/dev/null");
-        assertTrue(devNull.canRead());
-
-        final FileInputStream fis = new FileInputStream(devNull);
-        assertTrue(null != fis.getFD());
-        assertTrue(fis.getFD().valid());
-
-        try {
-            mNetwork.bindSocket(fis.getFD());
-            fail("SocketException not thrown");
-        } catch (SocketException expected) {}
-    }
-
-    @SmallTest
-    public void testBindSocketOfConnectedDatagramSocketThrows() throws Exception {
-        final DatagramSocket mDgramSocket = new DatagramSocket(0, (InetAddress) Inet6Address.ANY);
-        mDgramSocket.connect((InetAddress) Inet6Address.LOOPBACK, 53);
-        assertTrue(mDgramSocket.isConnected());
-
-        try {
-            mNetwork.bindSocket(mDgramSocket);
-            fail("SocketException not thrown");
-        } catch (SocketException expected) {}
-    }
-
-    @SmallTest
-    public void testBindSocketOfLocalSocketThrows() throws Exception {
-        final LocalSocket mLocalClient = new LocalSocket();
-        mLocalClient.bind(new LocalSocketAddress("testClient"));
-        assertTrue(mLocalClient.getFileDescriptor().valid());
-
-        try {
-            mNetwork.bindSocket(mLocalClient.getFileDescriptor());
-            fail("SocketException not thrown");
-        } catch (SocketException expected) {}
-
-        final LocalServerSocket mLocalServer = new LocalServerSocket("testServer");
-        mLocalClient.connect(mLocalServer.getLocalSocketAddress());
-        assertTrue(mLocalClient.isConnected());
-
-        try {
-            mNetwork.bindSocket(mLocalClient.getFileDescriptor());
-            fail("SocketException not thrown");
-        } catch (SocketException expected) {}
-    }
-
-    @SmallTest
-    public void testZeroIsObviousForDebugging() {
-        Network zero = new Network(0);
-        assertEquals(0, zero.hashCode());
-        assertEquals(0, zero.getNetworkHandle());
-        assertEquals("0", zero.toString());
-    }
-
-    @SmallTest
-    public void testGetNetworkHandle() {
-        Network one = new Network(1);
-        Network two = new Network(2);
-        Network three = new Network(3);
-
-        // None of the hashcodes are zero.
-        assertNotEqual(0, one.hashCode());
-        assertNotEqual(0, two.hashCode());
-        assertNotEqual(0, three.hashCode());
-
-        // All the hashcodes are distinct.
-        assertNotEqual(one.hashCode(), two.hashCode());
-        assertNotEqual(one.hashCode(), three.hashCode());
-        assertNotEqual(two.hashCode(), three.hashCode());
-
-        // None of the handles are zero.
-        assertNotEqual(0, one.getNetworkHandle());
-        assertNotEqual(0, two.getNetworkHandle());
-        assertNotEqual(0, three.getNetworkHandle());
-
-        // All the handles are distinct.
-        assertNotEqual(one.getNetworkHandle(), two.getNetworkHandle());
-        assertNotEqual(one.getNetworkHandle(), three.getNetworkHandle());
-        assertNotEqual(two.getNetworkHandle(), three.getNetworkHandle());
-
-        // The handles are not equal to the hashcodes.
-        assertNotEqual(one.hashCode(), one.getNetworkHandle());
-        assertNotEqual(two.hashCode(), two.getNetworkHandle());
-        assertNotEqual(three.hashCode(), three.getNetworkHandle());
-
-        // Adjust as necessary to test an implementation's specific constants.
-        // When running with runtest, "adb logcat -s TestRunner" can be useful.
-        assertEquals(4311403230L, one.getNetworkHandle());
-        assertEquals(8606370526L, two.getNetworkHandle());
-        assertEquals(12901337822L, three.getNetworkHandle());
-    }
-}
diff --git a/core/tests/coretests/src/android/net/StaticIpConfigurationTest.java b/core/tests/coretests/src/android/net/StaticIpConfigurationTest.java
deleted file mode 100644
index 59f780f..0000000
--- a/core/tests/coretests/src/android/net/StaticIpConfigurationTest.java
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.RouteInfo;
-import android.net.StaticIpConfiguration;
-import android.os.Parcel;
-
-import java.net.InetAddress;
-import java.util.HashSet;
-
-import junit.framework.TestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import static org.junit.Assert.*;
-
-
-public class StaticIpConfigurationTest extends TestCase {
-
-    private static final String ADDRSTR = "192.0.2.2/25";
-    private static final LinkAddress ADDR = new LinkAddress(ADDRSTR);
-    private static final InetAddress GATEWAY = IpAddress("192.0.2.1");
-    private static final InetAddress OFFLINKGATEWAY = IpAddress("192.0.2.129");
-    private static final InetAddress DNS1 = IpAddress("8.8.8.8");
-    private static final InetAddress DNS2 = IpAddress("8.8.4.4");
-    private static final InetAddress DNS3 = IpAddress("4.2.2.2");
-    private static final String IFACE = "eth0";
-
-    private static InetAddress IpAddress(String addr) {
-        return InetAddress.parseNumericAddress(addr);
-    }
-
-    private void checkEmpty(StaticIpConfiguration s) {
-        assertNull(s.ipAddress);
-        assertNull(s.gateway);
-        assertNull(s.domains);
-        assertEquals(0, s.dnsServers.size());
-    }
-
-    private boolean isEqual(StaticIpConfiguration s1, StaticIpConfiguration s2) {
-        return s1.equals(s2);
-    }
-
-    private void assertEquals(StaticIpConfiguration s1, StaticIpConfiguration s2) {
-        assertTrue(isEqual(s1, s2));
-    }
-
-    private void assertNotEquals(StaticIpConfiguration s1, StaticIpConfiguration s2) {
-        assertFalse(isEqual(s1, s2));
-    }
-
-    private StaticIpConfiguration makeTestObject() {
-        StaticIpConfiguration s = new StaticIpConfiguration();
-        s.ipAddress = ADDR;
-        s.gateway = GATEWAY;
-        s.dnsServers.add(DNS1);
-        s.dnsServers.add(DNS2);
-        s.dnsServers.add(DNS3);
-        s.domains = "google.com";
-        return s;
-    }
-
-    @SmallTest
-    public void testConstructor() {
-        StaticIpConfiguration s = new StaticIpConfiguration();
-        checkEmpty(s);
-    }
-
-    @SmallTest
-    public void testCopyAndClear() {
-        StaticIpConfiguration empty = new StaticIpConfiguration((StaticIpConfiguration) null);
-        checkEmpty(empty);
-
-        StaticIpConfiguration s1 = makeTestObject();
-        StaticIpConfiguration s2 = new StaticIpConfiguration(s1);
-        assertEquals(s1, s2);
-        s2.clear();
-        assertEquals(empty, s2);
-    }
-
-    @SmallTest
-    public void testHashCodeAndEquals() {
-        HashSet<Integer> hashCodes = new HashSet();
-        hashCodes.add(0);
-
-        StaticIpConfiguration s = new StaticIpConfiguration();
-        // Check that this hash code is nonzero and different from all the ones seen so far.
-        assertTrue(hashCodes.add(s.hashCode()));
-
-        s.ipAddress = ADDR;
-        assertTrue(hashCodes.add(s.hashCode()));
-
-        s.gateway = GATEWAY;
-        assertTrue(hashCodes.add(s.hashCode()));
-
-        s.dnsServers.add(DNS1);
-        assertTrue(hashCodes.add(s.hashCode()));
-
-        s.dnsServers.add(DNS2);
-        assertTrue(hashCodes.add(s.hashCode()));
-
-        s.dnsServers.add(DNS3);
-        assertTrue(hashCodes.add(s.hashCode()));
-
-        s.domains = "example.com";
-        assertTrue(hashCodes.add(s.hashCode()));
-
-        assertFalse(s.equals(null));
-        assertEquals(s, s);
-
-        StaticIpConfiguration s2 = new StaticIpConfiguration(s);
-        assertEquals(s, s2);
-
-        s.ipAddress = new LinkAddress(DNS1, 32);
-        assertNotEquals(s, s2);
-
-        s2 = new StaticIpConfiguration(s);
-        s.domains = "foo";
-        assertNotEquals(s, s2);
-
-        s2 = new StaticIpConfiguration(s);
-        s.gateway = DNS2;
-        assertNotEquals(s, s2);
-
-        s2 = new StaticIpConfiguration(s);
-        s.dnsServers.add(DNS3);
-        assertNotEquals(s, s2);
-    }
-
-    @SmallTest
-    public void testToLinkProperties() {
-        LinkProperties expected = new LinkProperties();
-        expected.setInterfaceName(IFACE);
-
-        StaticIpConfiguration s = new StaticIpConfiguration();
-        assertEquals(expected, s.toLinkProperties(IFACE));
-
-        final RouteInfo connectedRoute = new RouteInfo(new IpPrefix(ADDRSTR), null, IFACE);
-        s.ipAddress = ADDR;
-        expected.addLinkAddress(ADDR);
-        expected.addRoute(connectedRoute);
-        assertEquals(expected, s.toLinkProperties(IFACE));
-
-        s.gateway = GATEWAY;
-        RouteInfo defaultRoute = new RouteInfo(new IpPrefix("0.0.0.0/0"), GATEWAY, IFACE);
-        expected.addRoute(defaultRoute);
-        assertEquals(expected, s.toLinkProperties(IFACE));
-
-        s.gateway = OFFLINKGATEWAY;
-        expected.removeRoute(defaultRoute);
-        defaultRoute = new RouteInfo(new IpPrefix("0.0.0.0/0"), OFFLINKGATEWAY, IFACE);
-        expected.addRoute(defaultRoute);
-
-        RouteInfo gatewayRoute = new RouteInfo(new IpPrefix("192.0.2.129/32"), null, IFACE);
-        expected.addRoute(gatewayRoute);
-        assertEquals(expected, s.toLinkProperties(IFACE));
-
-        s.dnsServers.add(DNS1);
-        expected.addDnsServer(DNS1);
-        assertEquals(expected, s.toLinkProperties(IFACE));
-
-        s.dnsServers.add(DNS2);
-        s.dnsServers.add(DNS3);
-        expected.addDnsServer(DNS2);
-        expected.addDnsServer(DNS3);
-        assertEquals(expected, s.toLinkProperties(IFACE));
-
-        s.domains = "google.com";
-        expected.setDomains("google.com");
-        assertEquals(expected, s.toLinkProperties(IFACE));
-
-        s.gateway = null;
-        expected.removeRoute(defaultRoute);
-        expected.removeRoute(gatewayRoute);
-        assertEquals(expected, s.toLinkProperties(IFACE));
-
-        // Without knowing the IP address, we don't have a directly-connected route, so we can't
-        // tell if the gateway is off-link or not and we don't add a host route. This isn't a real
-        // configuration, but we should at least not crash.
-        s.gateway = OFFLINKGATEWAY;
-        s.ipAddress = null;
-        expected.removeLinkAddress(ADDR);
-        expected.removeRoute(connectedRoute);
-        expected.addRoute(defaultRoute);
-        assertEquals(expected, s.toLinkProperties(IFACE));
-    }
-
-    private StaticIpConfiguration passThroughParcel(StaticIpConfiguration s) {
-        Parcel p = Parcel.obtain();
-        StaticIpConfiguration s2 = null;
-        try {
-            s.writeToParcel(p, 0);
-            p.setDataPosition(0);
-            s2 = StaticIpConfiguration.CREATOR.createFromParcel(p);
-        } finally {
-            p.recycle();
-        }
-        assertNotNull(s2);
-        return s2;
-    }
-
-    @SmallTest
-    public void testParceling() {
-        StaticIpConfiguration s = makeTestObject();
-        StaticIpConfiguration s2 = passThroughParcel(s);
-        assertEquals(s, s2);
-    }
-}
-
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 6731536..ebe0527 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -38,7 +38,6 @@
 import java.util.Set;
 
 /** Tests that ensure appropriate settings are backed up. */
-@Presubmit
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class SettingsBackupTest {
@@ -181,6 +180,7 @@
                     Settings.Global.DNS_RESOLVER_MIN_SAMPLES,
                     Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
                     Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
+                    Settings.Global.DNS_TLS_DISABLED,
                     Settings.Global.DOCK_SOUNDS_ENABLED_WHEN_ACCESSIBILITY,
                     Settings.Global.DOWNLOAD_MAX_BYTES_OVER_MOBILE,
                     Settings.Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE,
@@ -342,6 +342,7 @@
                     Settings.Global.TETHER_DUN_REQUIRED,
                     Settings.Global.TETHER_OFFLOAD_DISABLED,
                     Settings.Global.TETHER_SUPPORTED,
+                    Settings.Global.TEXT_CLASSIFIER_CONSTANTS,
                     Settings.Global.THEATER_MODE_ON,
                     Settings.Global.TRANSITION_ANIMATION_SCALE,
                     Settings.Global.TRUSTED_SOUND,
@@ -463,7 +464,6 @@
                  Settings.Secure.NFC_PAYMENT_FOREGROUND,
                  Settings.Secure.NIGHT_DISPLAY_ACTIVATED,
                  Settings.Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
-                 Settings.Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME,
                  Settings.Secure.PACKAGE_VERIFIER_STATE,
                  Settings.Secure.PACKAGE_VERIFIER_USER_CONSENT,
                  Settings.Secure.PARENTAL_CONTROL_LAST_UPDATE,
diff --git a/core/tests/coretests/src/android/service/settings/suggestions/MockSuggestionService.java b/core/tests/coretests/src/android/service/settings/suggestions/MockSuggestionService.java
index c158b9f..ab541a1 100644
--- a/core/tests/coretests/src/android/service/settings/suggestions/MockSuggestionService.java
+++ b/core/tests/coretests/src/android/service/settings/suggestions/MockSuggestionService.java
@@ -16,11 +16,23 @@
 
 package android.service.settings.suggestions;
 
+import android.support.annotation.VisibleForTesting;
+
 import java.util.ArrayList;
 import java.util.List;
 
 public class MockSuggestionService extends SuggestionService {
 
+    @VisibleForTesting
+    static boolean sOnSuggestionLaunchedCalled;
+    @VisibleForTesting
+    static boolean sOnSuggestionDismissedCalled;
+
+    public static void reset() {
+        sOnSuggestionLaunchedCalled = false;
+        sOnSuggestionDismissedCalled = false;
+    }
+
     @Override
     public List<Suggestion> onGetSuggestions() {
         final List<Suggestion> data = new ArrayList<>();
@@ -34,5 +46,11 @@
 
     @Override
     public void onSuggestionDismissed(Suggestion suggestion) {
+        sOnSuggestionDismissedCalled = true;
+    }
+
+    @Override
+    public void onSuggestionLaunched(Suggestion suggestion) {
+        sOnSuggestionLaunchedCalled = true;
     }
 }
diff --git a/core/tests/coretests/src/android/service/settings/suggestions/SuggestionServiceTest.java b/core/tests/coretests/src/android/service/settings/suggestions/SuggestionServiceTest.java
index bc88231..dca8c09 100644
--- a/core/tests/coretests/src/android/service/settings/suggestions/SuggestionServiceTest.java
+++ b/core/tests/coretests/src/android/service/settings/suggestions/SuggestionServiceTest.java
@@ -16,12 +16,17 @@
 
 package android.service.settings.suggestions;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.rule.ServiceTestRule;
 import android.support.test.runner.AndroidJUnit4;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -45,9 +50,36 @@
                 MockSuggestionService.class);
     }
 
+    @After
+    public void tearUp() {
+        MockSuggestionService.reset();
+    }
+
     @Test
     public void canStartService() throws TimeoutException {
         mServiceTestRule.startService(mMockServiceIntent);
         // Do nothing after starting service.
     }
+
+    @Test
+    public void dismissSuggestion_shouldCallImplementation()
+            throws TimeoutException, RemoteException {
+        MockSuggestionService service = new MockSuggestionService();
+        IBinder binder = mServiceTestRule.bindService(mMockServiceIntent);
+        ISuggestionService serviceBinder = ISuggestionService.Stub.asInterface(binder);
+        serviceBinder.dismissSuggestion(null);
+
+        assertThat(service.sOnSuggestionDismissedCalled).isTrue();
+    }
+
+    @Test
+    public void launchSuggestion_shouldCallImplementation()
+            throws TimeoutException, RemoteException {
+        MockSuggestionService service = new MockSuggestionService();
+        IBinder binder = mServiceTestRule.bindService(mMockServiceIntent);
+        ISuggestionService serviceBinder = ISuggestionService.Stub.asInterface(binder);
+        serviceBinder.launchSuggestion(null);
+
+        assertThat(service.sOnSuggestionLaunchedCalled).isTrue();
+    }
 }
diff --git a/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java b/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
index d16cce8..8092203 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
@@ -96,7 +96,7 @@
         int n = chs.length;
         byte[] chInfo = new byte[n];
 
-        int resultDir = AndroidBidi.bidi(dir, chs, chInfo, n, false);
+        int resultDir = AndroidBidi.bidi(dir, chs, chInfo);
 
         {
             StringBuilder sb = new StringBuilder("info:");
diff --git a/core/tests/coretests/src/android/text/StaticLayoutLineBreakingTest.java b/core/tests/coretests/src/android/text/StaticLayoutLineBreakingTest.java
deleted file mode 100644
index f7dbafa..0000000
--- a/core/tests/coretests/src/android/text/StaticLayoutLineBreakingTest.java
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.text;
-
-import static org.junit.Assert.assertEquals;
-
-import android.content.Context;;
-import android.graphics.Typeface;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.text.Layout.Alignment;
-import android.text.style.MetricAffectingSpan;
-import android.util.Log;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class StaticLayoutLineBreakingTest {
-    // Span test are currently not supported because text measurement uses the MeasuredText
-    // internal mWorkPaint instead of the provided MockTestPaint.
-    private static final boolean SPAN_TESTS_SUPPORTED = false;
-    private static final boolean DEBUG = false;
-
-    private static final float SPACE_MULTI = 1.0f;
-    private static final float SPACE_ADD = 0.0f;
-    private static final int WIDTH = 100;
-    private static final Alignment ALIGN = Alignment.ALIGN_LEFT;
-
-    private static final char SURR_FIRST = '\uD800';
-    private static final char SURR_SECOND = '\uDF31';
-
-    private static final int[] NO_BREAK = new int[] {};
-
-    private static final TextPaint sTextPaint = new TextPaint();
-
-    static {
-        // The test font has following coverage and width.
-        // U+0020: 10em
-        // U+002E (.): 10em
-        // U+0043 (C): 100em
-        // U+0049 (I): 1em
-        // U+004C (L): 50em
-        // U+0056 (V): 5em
-        // U+0058 (X): 10em
-        // U+005F (_): 0em
-        // U+FFFD (invalid surrogate will be replaced to this): 7em
-        // U+10331 (\uD800\uDF31): 10em
-        Context context = InstrumentationRegistry.getTargetContext();
-        sTextPaint.setTypeface(Typeface.createFromAsset(context.getAssets(),
-                  "fonts/StaticLayoutLineBreakingTestFont.ttf"));
-        sTextPaint.setTextSize(1.0f);  // Make 1em == 1px.
-    }
-
-    private static StaticLayout getStaticLayout(CharSequence source, int width) {
-        return new StaticLayout(source, sTextPaint, width, ALIGN, SPACE_MULTI, SPACE_ADD, false);
-    }
-
-    private static int[] getBreaks(CharSequence source) {
-        return getBreaks(source, WIDTH);
-    }
-
-    private static int[] getBreaks(CharSequence source, int width) {
-        StaticLayout staticLayout = getStaticLayout(source, width);
-
-        int[] breaks = new int[staticLayout.getLineCount() - 1];
-        for (int line = 0; line < breaks.length; line++) {
-            breaks[line] = staticLayout.getLineEnd(line);
-        }
-        return breaks;
-    }
-
-    private static void debugLayout(CharSequence source, StaticLayout staticLayout) {
-        if (DEBUG) {
-            int count = staticLayout.getLineCount();
-            Log.i("SLLBTest", "\"" + source.toString() + "\": "
-                    + count + " lines");
-            for (int line = 0; line < count; line++) {
-                int lineStart = staticLayout.getLineStart(line);
-                int lineEnd = staticLayout.getLineEnd(line);
-                Log.i("SLLBTest", "Line " + line + " [" + lineStart + ".."
-                        + lineEnd + "]\t" + source.subSequence(lineStart, lineEnd));
-            }
-        }
-    }
-
-    private static void layout(CharSequence source, int[] breaks) {
-        layout(source, breaks, WIDTH);
-    }
-
-    private static void layout(CharSequence source, int[] breaks, int width) {
-        StaticLayout staticLayout = getStaticLayout(source, width);
-
-        debugLayout(source, staticLayout);
-
-        int lineCount = breaks.length + 1;
-        assertEquals("Number of lines", lineCount, staticLayout.getLineCount());
-
-        for (int line = 0; line < lineCount; line++) {
-            int lineStart = staticLayout.getLineStart(line);
-            int lineEnd = staticLayout.getLineEnd(line);
-
-            if (line == 0) {
-                assertEquals("Line start for first line", 0, lineStart);
-            } else {
-                assertEquals("Line start for line " + line, breaks[line - 1], lineStart);
-            }
-
-            if (line == lineCount - 1) {
-                assertEquals("Line end for last line", source.length(), lineEnd);
-            } else {
-                assertEquals("Line end for line " + line, breaks[line], lineEnd);
-            }
-        }
-    }
-
-    private static void layoutMaxLines(CharSequence source, int[] breaks, int maxLines) {
-        StaticLayout staticLayout = new StaticLayout(source, 0, source.length(), sTextPaint, WIDTH,
-                ALIGN, TextDirectionHeuristics.LTR, SPACE_MULTI, SPACE_ADD, false /* includePad */,
-                null, WIDTH, maxLines);
-
-        debugLayout(source, staticLayout);
-
-        final int lineCount = staticLayout.getLineCount();
-
-        for (int line = 0; line < lineCount; line++) {
-            int lineStart = staticLayout.getLineStart(line);
-            int lineEnd = staticLayout.getLineEnd(line);
-
-            if (line == 0) {
-                assertEquals("Line start for first line", 0, lineStart);
-            } else {
-                assertEquals("Line start for line " + line, breaks[line - 1], lineStart);
-            }
-
-            if (line == lineCount - 1 && line != breaks.length - 1) {
-                assertEquals("Line end for last line", source.length(), lineEnd);
-            } else {
-                assertEquals("Line end for line " + line, breaks[line], lineEnd);
-            }
-        }
-    }
-
-    private static final int MAX_SPAN_COUNT = 10;
-    private static final int[] sSpanStarts = new int[MAX_SPAN_COUNT];
-    private static final int[] sSpanEnds = new int[MAX_SPAN_COUNT];
-
-    private static MetricAffectingSpan getMetricAffectingSpan() {
-        return new MetricAffectingSpan() {
-            @Override
-            public void updateDrawState(TextPaint tp) { /* empty */ }
-
-            @Override
-            public void updateMeasureState(TextPaint p) { /* empty */ }
-        };
-    }
-
-    /**
-     * Replaces the "<...>" blocks by spans, assuming non overlapping, correctly defined spans
-     * @param text
-     * @return A CharSequence with '<' '>' replaced by MetricAffectingSpan
-     */
-    private static CharSequence spanify(String text) {
-        int startIndex = text.indexOf('<');
-        if (startIndex < 0) return text;
-
-        int spanCount = 0;
-        do {
-            int endIndex = text.indexOf('>');
-            if (endIndex < 0) throw new IllegalArgumentException("Unbalanced span markers");
-
-            text = text.substring(0, startIndex) + text.substring(startIndex + 1, endIndex)
-                    + text.substring(endIndex + 1);
-
-            sSpanStarts[spanCount] = startIndex;
-            sSpanEnds[spanCount] = endIndex - 2;
-            spanCount++;
-
-            startIndex = text.indexOf('<');
-        } while (startIndex >= 0);
-
-        SpannableStringBuilder result = new SpannableStringBuilder(text);
-        for (int i = 0; i < spanCount; i++) {
-            result.setSpan(getMetricAffectingSpan(), sSpanStarts[i], sSpanEnds[i],
-                    Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-        }
-        return result;
-    }
-
-    @Test
-    public void testNoLineBreak() {
-        // Width lower than WIDTH
-        layout("", NO_BREAK);
-        layout("I", NO_BREAK);
-        layout("V", NO_BREAK);
-        layout("X", NO_BREAK);
-        layout("L", NO_BREAK);
-        layout("I VILI", NO_BREAK);
-        layout("XXXX", NO_BREAK);
-        layout("LXXXX", NO_BREAK);
-
-        // Width equal to WIDTH
-        layout("C", NO_BREAK);
-        layout("LL", NO_BREAK);
-        layout("L XXXX", NO_BREAK);
-        layout("XXXXXXXXXX", NO_BREAK);
-        layout("XXX XXXXXX", NO_BREAK);
-        layout("XXX XXXX X", NO_BREAK);
-        layout("XXX XXXXX ", NO_BREAK);
-        layout(" XXXXXXXX ", NO_BREAK);
-        layout("  XX  XXX ", NO_BREAK);
-        //      0123456789
-
-        // Width greater than WIDTH, but no break
-        layout("  XX  XXX  ", NO_BREAK);
-        layout("XX XXX XXX ", NO_BREAK);
-        layout("XX XXX XXX     ", NO_BREAK);
-        layout("XXXXXXXXXX     ", NO_BREAK);
-        //      01234567890
-    }
-
-    @Test
-    public void testOneLineBreak() {
-        //      01234567890
-        layout("XX XXX XXXX", new int[] {7});
-        layout("XX XXXX XXX", new int[] {8});
-        layout("XX XXXXX XX", new int[] {9});
-        layout("XX XXXXXX X", new int[] {10});
-        //      01234567890
-        layout("XXXXXXXXXXX", new int[] {10});
-        layout("XXXXXXXXX X", new int[] {10});
-        layout("XXXXXXXX XX", new int[] {9});
-        layout("XXXXXXX XXX", new int[] {8});
-        layout("XXXXXX XXXX", new int[] {7});
-        //      01234567890
-        layout("LL LL", new int[] {3});
-        layout("LLLL", new int[] {2});
-        layout("C C", new int[] {2});
-        layout("CC", new int[] {1});
-    }
-
-    @Test
-    public void testSpaceAtBreak() {
-        //      0123456789012
-        layout("XXXX XXXXX X", new int[] {11});
-        layout("XXXXXXXXXX X", new int[] {11});
-        layout("XXXXXXXXXV X", new int[] {11});
-        layout("C X", new int[] {2});
-    }
-
-    @Test
-    public void testMultipleSpacesAtBreak() {
-        //      0123456789012
-        layout("LXX XXXX", new int[] {4});
-        layout("LXX  XXXX", new int[] {5});
-        layout("LXX   XXXX", new int[] {6});
-        layout("LXX    XXXX", new int[] {7});
-        layout("LXX     XXXX", new int[] {8});
-    }
-
-    @Test
-    public void testZeroWidthCharacters() {
-        //      0123456789012345678901234
-        layout("X_X_X_X_X_X_X_X_X_X", NO_BREAK);
-        layout("___X_X_X_X_X_X_X_X_X_X___", NO_BREAK);
-        layout("C_X", new int[] {2});
-        layout("C__X", new int[] {3});
-    }
-
-    /**
-     * Note that when the text has spans, StaticLayout does not use the provided TextPaint to
-     * measure text runs anymore. This is probably a bug.
-     * To be able to use the fake sTextPaint and make this test pass, use mPaint instead of
-     * mWorkPaint in MeasuredText#addStyleRun
-     */
-    @Test
-    public void testWithSpans() {
-        if (!SPAN_TESTS_SUPPORTED) return;
-
-        layout(spanify("<012 456 89>"), NO_BREAK);
-        layout(spanify("012 <456> 89"), NO_BREAK);
-        layout(spanify("<012> <456>< 89>"), NO_BREAK);
-        layout(spanify("<012> <456> <89>"), NO_BREAK);
-
-        layout(spanify("<012> <456> <89>012"), new int[] {8});
-        layout(spanify("<012> <456> 89<012>"), new int[] {8});
-        layout(spanify("<012> <456> <89><012>"), new int[] {8});
-        layout(spanify("<012> <456> 89 <123>"), new int[] {11});
-        layout(spanify("<012> <456> 89< 123>"), new int[] {11});
-        layout(spanify("<012> <456> <89> <123>"), new int[] {11});
-        layout(spanify("012 456 89 <LXX> XX XX"), new int[] {11, 18});
-    }
-
-    /*
-     * Adding a span to the string should not change the layout, since the metrics are unchanged.
-     */
-    @Test
-    public void testWithOneSpan() {
-        if (!SPAN_TESTS_SUPPORTED) return;
-
-        String[] texts = new String[] { "0123", "012 456", "012 456 89 123", "012 45678 012",
-                "012 456 89012 456 89012", "0123456789012" };
-
-        MetricAffectingSpan metricAffectingSpan = getMetricAffectingSpan();
-
-        for (String text : texts) {
-            // Get the line breaks without any span
-            int[] breaks = getBreaks(text);
-
-            // Add spans on all possible offsets
-            for (int spanStart = 0; spanStart < text.length(); spanStart++) {
-                for (int spanEnd = spanStart; spanEnd < text.length(); spanEnd++) {
-                    SpannableStringBuilder ssb = new SpannableStringBuilder(text);
-                    ssb.setSpan(metricAffectingSpan, spanStart, spanEnd,
-                            Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-                    layout(ssb, breaks);
-                }
-            }
-        }
-    }
-
-    @Test
-    public void testWithTwoSpans() {
-        if (!SPAN_TESTS_SUPPORTED) return;
-
-        String[] texts = new String[] { "0123", "012 456", "012 456 89 123", "012 45678 012",
-                "012 456 89012 456 89012", "0123456789012" };
-
-        MetricAffectingSpan metricAffectingSpan1 = getMetricAffectingSpan();
-        MetricAffectingSpan metricAffectingSpan2 = getMetricAffectingSpan();
-
-        for (String text : texts) {
-            // Get the line breaks without any span
-            int[] breaks = getBreaks(text);
-
-            // Add spans on all possible offsets
-            for (int spanStart1 = 0; spanStart1 < text.length(); spanStart1++) {
-                for (int spanEnd1 = spanStart1; spanEnd1 < text.length(); spanEnd1++) {
-                    SpannableStringBuilder ssb = new SpannableStringBuilder(text);
-                    ssb.setSpan(metricAffectingSpan1, spanStart1, spanEnd1,
-                            Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-
-                    for (int spanStart2 = 0; spanStart2 < text.length(); spanStart2++) {
-                        for (int spanEnd2 = spanStart2; spanEnd2 < text.length(); spanEnd2++) {
-                            ssb.setSpan(metricAffectingSpan2, spanStart2, spanEnd2,
-                                    Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-                            layout(ssb, breaks);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    public static String replace(String string, char c, char r) {
-        return string.replaceAll(String.valueOf(c), String.valueOf(r));
-    }
-
-    @Test
-    public void testWithSurrogate() {
-        layout("LX" + SURR_FIRST + SURR_SECOND, NO_BREAK);
-        layout("LXXXX" + SURR_FIRST + SURR_SECOND, NO_BREAK);
-        // LXXXXI (91) + SURR_FIRST + SURR_SECOND (10). Do not break in the middle point of
-        // surrogatge pair.
-        layout("LXXXXI" + SURR_FIRST + SURR_SECOND, new int[] {6});
-
-        // LXXXXI (91) + SURR_SECOND (replaced with REPLACEMENT CHARACTER. width is 7px) fits.
-        // Break just after invalid trailing surrogate.
-        layout("LXXXXI" + SURR_SECOND + SURR_FIRST, new int[] {7});
-
-        layout("C" + SURR_FIRST + SURR_SECOND, new int[] {1});
-    }
-
-    @Test
-    public void testNarrowWidth() {
-        int[] widths = new int[] { 0, 4, 10 };
-        String[] texts = new String[] { "", "X", " ", "XX", " X", "XXX" };
-
-        for (String text: texts) {
-            // 15 is such that only one character will fit
-            int[] breaks = getBreaks(text, 15);
-
-            // Width under 15 should all lead to the same line break
-            for (int width: widths) {
-                layout(text, breaks, width);
-            }
-        }
-    }
-
-    @Test
-    public void testNarrowWidthZeroWidth() {
-        int[] widths = new int[] { 1, 4 };
-        for (int width: widths) {
-            layout("X.", new int[] {1}, width);
-            layout("X__", NO_BREAK, width);
-            layout("X__X", new int[] {3}, width);
-            layout("X__X_", new int[] {3}, width);
-
-            layout("_", NO_BREAK, width);
-            layout("__", NO_BREAK, width);
-            layout("_X", new int[] {1}, width);
-            layout("_X_", new int[] {1}, width);
-            layout("__X__", new int[] {2}, width);
-        }
-    }
-
-    @Test
-    public void testMaxLines() {
-        layoutMaxLines("C", NO_BREAK, 1);
-        layoutMaxLines("C C", new int[] {2}, 1);
-        layoutMaxLines("C C", new int[] {2}, 2);
-        layoutMaxLines("CC", new int[] {1}, 1);
-        layoutMaxLines("CC", new int[] {1}, 2);
-    }
-}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 902b872..6f2b038 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -20,6 +20,10 @@
 applications that come with the platform
 -->
 <permissions>
+    <privapp-permissions package="android.ext.services">
+        <permission name="android.permission.PROVIDE_RESOLVER_RANKER_SERVICE" />
+    </privapp-permissions>
+
     <privapp-permissions package="com.android.backupconfirm">
         <permission name="android.permission.BACKUP"/>
         <permission name="android.permission.CRYPT_KEEPER"/>
@@ -367,8 +371,4 @@
         <permission name="android.permission.CONTROL_VPN"/>
     </privapp-permissions>
 
-    <privapp-permissions package="com.google.android.ext.services">
-        <permission name="android.permission.PROVIDE_RESOLVER_RANKER_SERVICE" />
-    </privapp-permissions>
-
 </permissions>
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index cfc389f..9961ed6 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -250,9 +250,9 @@
 
         FontFamily fontFamily = new FontFamily();
         for (final FontFileResourceEntry fontFile : filesEntry.getEntries()) {
-            // TODO: Add ttc and variation font support. (b/37853920)
+            // TODO: Add variation font support. (b/37853920)
             if (!fontFamily.addFontFromAssetManager(mgr, fontFile.getFileName(),
-                    0 /* resourceCookie */, false /* isAsset */, 0 /* ttcIndex */,
+                    0 /* resourceCookie */, false /* isAsset */, fontFile.getTtcIndex(),
                     fontFile.getWeight(), fontFile.getItalic(), null /* axes */)) {
                 return null;
             }
diff --git a/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java
index 0c509b7..3821bc7 100644
--- a/graphics/java/android/graphics/pdf/PdfEditor.java
+++ b/graphics/java/android/graphics/pdf/PdfEditor.java
@@ -23,6 +23,7 @@
 import android.graphics.Rect;
 import android.os.ParcelFileDescriptor;
 import android.system.ErrnoException;
+import android.system.Os;
 import android.system.OsConstants;
 import dalvik.system.CloseGuard;
 import libcore.io.IoUtils;
@@ -72,8 +73,8 @@
 
         final long size;
         try {
-            Libcore.os.lseek(input.getFileDescriptor(), 0, OsConstants.SEEK_SET);
-            size = Libcore.os.fstat(input.getFileDescriptor()).st_size;
+            Os.lseek(input.getFileDescriptor(), 0, OsConstants.SEEK_SET);
+            size = Os.fstat(input.getFileDescriptor()).st_size;
         } catch (ErrnoException ee) {
             throw new IllegalArgumentException("file descriptor not seekable");
         }
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
index c82ab0d..4a91705 100644
--- a/graphics/java/android/graphics/pdf/PdfRenderer.java
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -26,12 +26,12 @@
 import android.graphics.Rect;
 import android.os.ParcelFileDescriptor;
 import android.system.ErrnoException;
+import android.system.Os;
 import android.system.OsConstants;
 import com.android.internal.util.Preconditions;
 import dalvik.system.CloseGuard;
 
 import libcore.io.IoUtils;
-import libcore.io.Libcore;
 
 import java.io.IOException;
 import java.lang.annotation.Retention;
@@ -156,8 +156,8 @@
 
         final long size;
         try {
-            Libcore.os.lseek(input.getFileDescriptor(), 0, OsConstants.SEEK_SET);
-            size = Libcore.os.fstat(input.getFileDescriptor()).st_size;
+            Os.lseek(input.getFileDescriptor(), 0, OsConstants.SEEK_SET);
+            size = Os.fstat(input.getFileDescriptor()).st_size;
         } catch (ErrnoException ee) {
             throw new IllegalArgumentException("file descriptor not seekable");
         }
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index c4c14c9e..5484cf0 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -14,15 +14,27 @@
 
 // libandroidfw is partially built for the host (used by obbtool, aapt, and others)
 
-cc_library {
-    name: "libandroidfw",
-    host_supported: true,
+cc_defaults {
+    name: "libandroidfw_defaults",
     cflags: [
-        "-Wall",
         "-Werror",
-        "-Wunused",
         "-Wunreachable-code",
     ],
+    target: {
+        windows: {
+            // The Windows compiler warns incorrectly for value initialization with {}.
+            cppflags: ["-Wno-missing-field-initializers"],
+        },
+        host: {
+            cflags: ["-DSTATIC_ANDROIDFW_FOR_TOOLS"],
+        },
+    },
+}
+
+cc_library {
+    name: "libandroidfw",
+    defaults: ["libandroidfw_defaults"],
+    host_supported: true,
     srcs: [
         "ApkAssets.cpp",
         "Asset.cpp",
@@ -31,6 +43,7 @@
         "AssetManager2.cpp",
         "AttributeResolution.cpp",
         "ChunkIterator.cpp",
+        "Idmap.cpp",
         "LoadedArsc.cpp",
         "LocaleData.cpp",
         "misc.cpp",
@@ -67,7 +80,6 @@
             },
         },
         host: {
-            cflags: ["-DSTATIC_ANDROIDFW_FOR_TOOLS"],
             shared: {
                 enabled: false,
             },
@@ -84,9 +96,82 @@
         },
         windows: {
             enabled: true,
-            cppflags: ["-Wno-missing-field-initializers"],  // The Windows compiler warns
-                                                            // incorrectly for value
-                                                            // initialization with {}.
         },
     },
 }
+
+common_test_libs = [
+    "libandroidfw",
+    "libbase",
+    "libcutils",
+    "libutils",
+    "libziparchive",
+]
+
+cc_test {
+    name: "libandroidfw_tests",
+    host_supported: true,
+    defaults: ["libandroidfw_defaults"],
+    cppflags: [
+        // This is to suppress warnings/errors from gtest
+        "-Wno-unnamed-type-template-args",
+    ],
+    srcs: [
+        // Helpers/infra for testing.
+        "tests/CommonHelpers.cpp",
+        "tests/TestHelpers.cpp",
+        "tests/TestMain.cpp",
+
+        // Actual tests.
+        "tests/ApkAssets_test.cpp",
+        "tests/AppAsLib_test.cpp",
+        "tests/Asset_test.cpp",
+        "tests/AssetManager2_test.cpp",
+        "tests/AttributeFinder_test.cpp",
+        "tests/AttributeResolution_test.cpp",
+        "tests/ByteBucketArray_test.cpp",
+        "tests/Config_test.cpp",
+        "tests/ConfigLocale_test.cpp",
+        "tests/Idmap_test.cpp",
+        "tests/LoadedArsc_test.cpp",
+        "tests/ResourceUtils_test.cpp",
+        "tests/ResTable_test.cpp",
+        "tests/Split_test.cpp",
+        "tests/StringPiece_test.cpp",
+        "tests/Theme_test.cpp",
+        "tests/TypeWrappers_test.cpp",
+        "tests/ZipUtils_test.cpp",
+    ],
+    target: {
+        android: {
+            srcs: [
+                "tests/BackupData_test.cpp",
+                "tests/ObbFile_test.cpp",
+            ],
+            shared_libs: common_test_libs + ["libui"],
+        },
+        host: {
+            static_libs: common_test_libs + ["liblog", "libz"],
+        },
+    },
+    data: ["tests/data/**/*.apk"],
+}
+
+cc_benchmark {
+    name: "libandroidfw_benchmarks",
+    defaults: ["libandroidfw_defaults"],
+    srcs: [
+        // Helpers/infra for benchmarking.
+        "tests/BenchMain.cpp",
+        "tests/BenchmarkHelpers.cpp",
+        "tests/CommonHelpers.cpp",
+
+        // Actual benchmarks.
+        "tests/AssetManager2_bench.cpp",
+        "tests/SparseEntry_bench.cpp",
+        "tests/Theme_bench.cpp",
+    ],
+    shared_libs: common_test_libs,
+    data: ["tests/data/**/*.apk"],
+}
+
diff --git a/libs/androidfw/Android.mk b/libs/androidfw/Android.mk
deleted file mode 100644
index 68c51ef..0000000
--- a/libs/androidfw/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index 0e577d1..158df13 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -20,64 +20,126 @@
 
 #include <algorithm>
 
+#include "android-base/errors.h"
+#include "android-base/file.h"
 #include "android-base/logging.h"
+#include "android-base/unique_fd.h"
+#include "android-base/utf8.h"
+#include "utils/Compat.h"
 #include "utils/FileMap.h"
 #include "utils/Trace.h"
 #include "ziparchive/zip_archive.h"
 
 #include "androidfw/Asset.h"
+#include "androidfw/Idmap.h"
+#include "androidfw/ResourceTypes.h"
 #include "androidfw/Util.h"
 
 namespace android {
 
-ApkAssets::ApkAssets() : zip_handle_(nullptr, ::CloseArchive) {}
+using base::SystemErrorCodeToString;
+using base::unique_fd;
+
+static const std::string kResourcesArsc("resources.arsc");
+
+ApkAssets::ApkAssets(void* unmanaged_handle, const std::string& path)
+    : zip_handle_(unmanaged_handle, ::CloseArchive), path_(path) {
+}
 
 std::unique_ptr<const ApkAssets> ApkAssets::Load(const std::string& path, bool system) {
-  return ApkAssets::LoadImpl(path, system, false /*load_as_shared_library*/);
+  return ApkAssets::LoadImpl(path, nullptr, nullptr, system, false /*load_as_shared_library*/);
 }
 
 std::unique_ptr<const ApkAssets> ApkAssets::LoadAsSharedLibrary(const std::string& path,
                                                                 bool system) {
-  return ApkAssets::LoadImpl(path, system, true /*load_as_shared_library*/);
+  return ApkAssets::LoadImpl(path, nullptr, nullptr, system, true /*load_as_shared_library*/);
 }
 
-std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(const std::string& path, bool system,
-                                                     bool load_as_shared_library) {
+std::unique_ptr<const ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap_path,
+                                                        bool system) {
+  std::unique_ptr<Asset> idmap_asset = CreateAssetFromFile(idmap_path);
+  if (idmap_asset == nullptr) {
+    return {};
+  }
+
+  const StringPiece idmap_data(
+      reinterpret_cast<const char*>(idmap_asset->getBuffer(true /*wordAligned*/)),
+      static_cast<size_t>(idmap_asset->getLength()));
+  std::unique_ptr<const LoadedIdmap> loaded_idmap = LoadedIdmap::Load(idmap_data);
+  if (loaded_idmap == nullptr) {
+    LOG(ERROR) << "failed to load IDMAP " << idmap_path;
+    return {};
+  }
+  return LoadImpl(loaded_idmap->OverlayApkPath(), std::move(idmap_asset), std::move(loaded_idmap),
+                  system, false /*load_as_shared_library*/);
+}
+
+std::unique_ptr<Asset> ApkAssets::CreateAssetFromFile(const std::string& path) {
+  unique_fd fd(base::utf8::open(path.c_str(), O_RDONLY | O_BINARY | O_CLOEXEC));
+  if (fd == -1) {
+    LOG(ERROR) << "Failed to open file '" << path << "': " << SystemErrorCodeToString(errno);
+    return {};
+  }
+
+  const off64_t file_len = lseek64(fd, 0, SEEK_END);
+  if (file_len < 0) {
+    LOG(ERROR) << "Failed to get size of file '" << path << "': " << SystemErrorCodeToString(errno);
+    return {};
+  }
+
+  std::unique_ptr<FileMap> file_map = util::make_unique<FileMap>();
+  if (!file_map->create(path.c_str(), fd, 0, static_cast<size_t>(file_len), true /*readOnly*/)) {
+    LOG(ERROR) << "Failed to mmap file '" << path << "': " << SystemErrorCodeToString(errno);
+    return {};
+  }
+  return Asset::createFromUncompressedMap(std::move(file_map), Asset::AccessMode::ACCESS_RANDOM);
+}
+
+std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(
+    const std::string& path, std::unique_ptr<Asset> idmap_asset,
+    std::unique_ptr<const LoadedIdmap> loaded_idmap, bool system, bool load_as_shared_library) {
   ATRACE_CALL();
   ::ZipArchiveHandle unmanaged_handle;
   int32_t result = ::OpenArchive(path.c_str(), &unmanaged_handle);
   if (result != 0) {
-    LOG(ERROR) << ::ErrorCodeString(result);
+    LOG(ERROR) << "Failed to open APK '" << path << "' " << ::ErrorCodeString(result);
     return {};
   }
 
   // Wrap the handle in a unique_ptr so it gets automatically closed.
-  std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets());
-  loaded_apk->zip_handle_.reset(unmanaged_handle);
+  std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets(unmanaged_handle, path));
 
-  ::ZipString entry_name("resources.arsc");
+  // Find the resource table.
+  ::ZipString entry_name(kResourcesArsc.c_str());
   ::ZipEntry entry;
   result = ::FindEntry(loaded_apk->zip_handle_.get(), entry_name, &entry);
   if (result != 0) {
-    LOG(ERROR) << ::ErrorCodeString(result);
-    return {};
+    // There is no resources.arsc, so create an empty LoadedArsc and return.
+    loaded_apk->loaded_arsc_ = LoadedArsc::CreateEmpty();
+    return std::move(loaded_apk);
   }
 
   if (entry.method == kCompressDeflated) {
-    LOG(WARNING) << "resources.arsc is compressed.";
+    LOG(WARNING) << kResourcesArsc << " in APK '" << path << "' is compressed.";
   }
 
-  loaded_apk->path_ = path;
-  loaded_apk->resources_asset_ =
-      loaded_apk->Open("resources.arsc", Asset::AccessMode::ACCESS_BUFFER);
+  // Open the resource table via mmap unless it is compressed. This logic is taken care of by Open.
+  loaded_apk->resources_asset_ = loaded_apk->Open(kResourcesArsc, Asset::AccessMode::ACCESS_BUFFER);
   if (loaded_apk->resources_asset_ == nullptr) {
+    LOG(ERROR) << "Failed to open '" << kResourcesArsc << "' in APK '" << path << "'.";
     return {};
   }
 
+  // Must retain ownership of the IDMAP Asset so that all pointers to its mmapped data remain valid.
+  loaded_apk->idmap_asset_ = std::move(idmap_asset);
+
+  const StringPiece data(
+      reinterpret_cast<const char*>(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/)),
+      loaded_apk->resources_asset_->getLength());
   loaded_apk->loaded_arsc_ =
-      LoadedArsc::Load(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/),
-                       loaded_apk->resources_asset_->getLength(), system, load_as_shared_library);
+      LoadedArsc::Load(data, loaded_idmap.get(), system, load_as_shared_library);
   if (loaded_apk->loaded_arsc_ == nullptr) {
+    LOG(ERROR) << "Failed to load '" << kResourcesArsc << "' in APK '" << path << "'.";
     return {};
   }
 
@@ -93,7 +155,6 @@
   ::ZipEntry entry;
   int32_t result = ::FindEntry(zip_handle_.get(), name, &entry);
   if (result != 0) {
-    LOG(ERROR) << "No entry '" << path << "' found in APK '" << path_ << "'";
     return {};
   }
 
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index f1f2e2d..83c82af 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -18,6 +18,7 @@
 
 #include "androidfw/AssetManager2.h"
 
+#include <iterator>
 #include <set>
 
 #include "android-base/logging.h"
@@ -35,7 +36,9 @@
 
 namespace android {
 
-AssetManager2::AssetManager2() { memset(&configuration_, 0, sizeof(configuration_)); }
+AssetManager2::AssetManager2() {
+  memset(&configuration_, 0, sizeof(configuration_));
+}
 
 bool AssetManager2::SetApkAssets(const std::vector<const ApkAssets*>& apk_assets,
                                  bool invalidate_caches) {
@@ -55,9 +58,9 @@
   int next_package_id = 0x02;
   const size_t apk_assets_count = apk_assets_.size();
   for (size_t i = 0; i < apk_assets_count; i++) {
-    const ApkAssets* apk_asset = apk_assets_[i];
-    for (const std::unique_ptr<const LoadedPackage>& package :
-         apk_asset->GetLoadedArsc()->GetPackages()) {
+    const LoadedArsc* loaded_arsc = apk_assets_[i]->GetLoadedArsc();
+
+    for (const std::unique_ptr<const LoadedPackage>& package : loaded_arsc->GetPackages()) {
       // Get the package ID or assign one if a shared library.
       int package_id;
       if (package->IsDynamic()) {
@@ -261,9 +264,7 @@
 }
 
 ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_override,
-                                         bool stop_at_first_match, LoadedArscEntry* out_entry,
-                                         ResTable_config* out_selected_config,
-                                         uint32_t* out_flags) {
+                                         bool stop_at_first_match, FindEntryResult* out_entry) {
   ATRACE_CALL();
 
   // Might use this if density_override != 0.
@@ -292,29 +293,28 @@
     return kInvalidCookie;
   }
 
-  LoadedArscEntry best_entry;
-  ResTable_config best_config;
+  FindEntryResult best_entry;
   ApkAssetsCookie best_cookie = kInvalidCookie;
   uint32_t cumulated_flags = 0u;
 
   const PackageGroup& package_group = package_groups_[idx];
   const size_t package_count = package_group.packages_.size();
   for (size_t i = 0; i < package_count; i++) {
-    LoadedArscEntry current_entry;
-    ResTable_config current_config;
-    uint32_t current_flags = 0;
-
     const LoadedPackage* loaded_package = package_group.packages_[i];
-    if (!loaded_package->FindEntry(type_idx, entry_id, *desired_config, &current_entry,
-                                   &current_config, &current_flags)) {
+
+    FindEntryResult current_entry;
+    if (!loaded_package->FindEntry(type_idx, entry_id, *desired_config, &current_entry)) {
       continue;
     }
 
-    cumulated_flags |= current_flags;
+    cumulated_flags |= current_entry.type_flags;
 
-    if (best_cookie == kInvalidCookie || current_config.isBetterThan(best_config, desired_config)) {
+    const ResTable_config* current_config = current_entry.config;
+    const ResTable_config* best_config = best_entry.config;
+    if (best_cookie == kInvalidCookie ||
+        current_config->isBetterThan(*best_config, desired_config) ||
+        (loaded_package->IsOverlay() && current_config->compare(*best_config) == 0)) {
       best_entry = current_entry;
-      best_config = current_config;
       best_cookie = package_group.cookies_[i];
       if (stop_at_first_match) {
         break;
@@ -328,19 +328,16 @@
 
   *out_entry = best_entry;
   out_entry->dynamic_ref_table = &package_group.dynamic_ref_table;
-  *out_selected_config = best_config;
-  *out_flags = cumulated_flags;
+  out_entry->type_flags = cumulated_flags;
   return best_cookie;
 }
 
 bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) {
   ATRACE_CALL();
 
-  LoadedArscEntry entry;
-  ResTable_config config;
-  uint32_t flags = 0u;
-  ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
-                                     true /* stop_at_first_match */, &entry, &config, &flags);
+  FindEntryResult entry;
+  ApkAssetsCookie cookie =
+      FindEntry(resid, 0u /* density_override */, true /* stop_at_first_match */, &entry);
   if (cookie == kInvalidCookie) {
     return false;
   }
@@ -374,11 +371,14 @@
 }
 
 bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) {
-  LoadedArscEntry entry;
-  ResTable_config config;
-  ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
-                                     false /* stop_at_first_match */, &entry, &config, out_flags);
-  return cookie != kInvalidCookie;
+  FindEntryResult entry;
+  ApkAssetsCookie cookie =
+      FindEntry(resid, 0u /* density_override */, false /* stop_at_first_match */, &entry);
+  if (cookie != kInvalidCookie) {
+    *out_flags = entry.type_flags;
+    return cookie;
+  }
+  return kInvalidCookie;
 }
 
 ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
@@ -387,11 +387,9 @@
                                            uint32_t* out_flags) {
   ATRACE_CALL();
 
-  LoadedArscEntry entry;
-  ResTable_config config;
-  uint32_t flags = 0u;
+  FindEntryResult entry;
   ApkAssetsCookie cookie =
-      FindEntry(resid, density_override, false /* stop_at_first_match */, &entry, &config, &flags);
+      FindEntry(resid, density_override, false /* stop_at_first_match */, &entry);
   if (cookie == kInvalidCookie) {
     return kInvalidCookie;
   }
@@ -405,8 +403,8 @@
     // Create a reference since we can't represent this complex type as a Res_value.
     out_value->dataType = Res_value::TYPE_REFERENCE;
     out_value->data = resid;
-    *out_selected_config = config;
-    *out_flags = flags;
+    *out_selected_config = *entry.config;
+    *out_flags = entry.type_flags;
     return cookie;
   }
 
@@ -417,8 +415,8 @@
   // Convert the package ID to the runtime assigned package ID.
   entry.dynamic_ref_table->lookupResourceValue(out_value);
 
-  *out_selected_config = config;
-  *out_flags = flags;
+  *out_selected_config = *entry.config;
+  *out_flags = entry.type_flags;
   return cookie;
 }
 
@@ -461,11 +459,9 @@
     return cached_iter->second.get();
   }
 
-  LoadedArscEntry entry;
-  ResTable_config config;
-  uint32_t flags = 0u;
-  ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
-                                     false /* stop_at_first_match */, &entry, &config, &flags);
+  FindEntryResult entry;
+  ApkAssetsCookie cookie =
+      FindEntry(resid, 0u /* density_override */, false /* stop_at_first_match */, &entry);
   if (cookie == kInvalidCookie) {
     return nullptr;
   }
@@ -503,13 +499,20 @@
         }
       }
       new_entry->cookie = cookie;
-      new_entry->value.copyFrom_dtoh(map_entry->value);
       new_entry->key = new_key;
       new_entry->key_pool = nullptr;
       new_entry->type_pool = nullptr;
+      new_entry->value.copyFrom_dtoh(map_entry->value);
+      status_t err = entry.dynamic_ref_table->lookupResourceValue(&new_entry->value);
+      if (err != NO_ERROR) {
+        LOG(ERROR) << base::StringPrintf(
+            "Failed to resolve value t=0x%02x d=0x%08x for key 0x%08x.", new_entry->value.dataType,
+            new_entry->value.data, new_key);
+        return nullptr;
+      }
       ++new_entry;
     }
-    new_bag->type_spec_flags = flags;
+    new_bag->type_spec_flags = entry.type_flags;
     new_bag->entry_count = static_cast<uint32_t>(entry_count);
     ResolvedBag* result = new_bag.get();
     cached_bags_[resid] = std::move(new_bag);
@@ -527,9 +530,6 @@
     return nullptr;
   }
 
-  // Combine flags from the parent and our own bag.
-  flags |= parent_bag->type_spec_flags;
-
   // Create the max possible entries we can make. Once we construct the bag,
   // we will realloc to fit to size.
   const size_t max_count = parent_bag->entry_count + dtohl(map->count);
@@ -554,10 +554,17 @@
       // Use the child key if it comes before the parent
       // or is equal to the parent (overrides).
       new_entry->cookie = cookie;
-      new_entry->value.copyFrom_dtoh(map_entry->value);
       new_entry->key = child_key;
       new_entry->key_pool = nullptr;
       new_entry->type_pool = nullptr;
+      new_entry->value.copyFrom_dtoh(map_entry->value);
+      status_t err = entry.dynamic_ref_table->lookupResourceValue(&new_entry->value);
+      if (err != NO_ERROR) {
+        LOG(ERROR) << base::StringPrintf(
+            "Failed to resolve value t=0x%02x d=0x%08x for key 0x%08x.", new_entry->value.dataType,
+            new_entry->value.data, child_key);
+        return nullptr;
+      }
       ++map_entry;
     } else {
       // Take the parent entry as-is.
@@ -582,10 +589,16 @@
       }
     }
     new_entry->cookie = cookie;
-    new_entry->value.copyFrom_dtoh(map_entry->value);
     new_entry->key = new_key;
     new_entry->key_pool = nullptr;
     new_entry->type_pool = nullptr;
+    new_entry->value.copyFrom_dtoh(map_entry->value);
+    status_t err = entry.dynamic_ref_table->lookupResourceValue(&new_entry->value);
+    if (err != NO_ERROR) {
+      LOG(ERROR) << base::StringPrintf("Failed to resolve value t=0x%02x d=0x%08x for key 0x%08x.",
+                                       new_entry->value.dataType, new_entry->value.data, new_key);
+      return nullptr;
+    }
     ++map_entry;
     ++new_entry;
   }
@@ -605,7 +618,8 @@
         new_bag.release(), sizeof(ResolvedBag) + (actual_count * sizeof(ResolvedBag::Entry)))));
   }
 
-  new_bag->type_spec_flags = flags;
+  // Combine flags from the parent and our own bag.
+  new_bag->type_spec_flags = entry.type_flags | parent_bag->type_spec_flags;
   new_bag->entry_count = static_cast<uint32_t>(actual_count);
   ResolvedBag* result = new_bag.get();
   cached_bags_[resid] = std::move(new_bag);
@@ -698,7 +712,37 @@
   }
 }
 
-std::unique_ptr<Theme> AssetManager2::NewTheme() { return std::unique_ptr<Theme>(new Theme(this)); }
+std::unique_ptr<Theme> AssetManager2::NewTheme() {
+  return std::unique_ptr<Theme>(new Theme(this));
+}
+
+Theme::Theme(AssetManager2* asset_manager) : asset_manager_(asset_manager) {
+}
+
+Theme::~Theme() = default;
+
+namespace {
+
+struct ThemeEntry {
+  ApkAssetsCookie cookie;
+  uint32_t type_spec_flags;
+  Res_value value;
+};
+
+struct ThemeType {
+  int entry_count;
+  ThemeEntry entries[0];
+};
+
+constexpr size_t kTypeCount = std::numeric_limits<uint8_t>::max() + 1;
+
+}  // namespace
+
+struct Theme::Package {
+  // Each element of Type will be a dynamically sized object
+  // allocated to have the entries stored contiguously with the Type.
+  std::array<util::unique_cptr<ThemeType>, kTypeCount> types;
+};
 
 bool Theme::ApplyStyle(uint32_t resid, bool force) {
   ATRACE_CALL();
@@ -711,71 +755,69 @@
   // Merge the flags from this style.
   type_spec_flags_ |= bag->type_spec_flags;
 
-  // On the first iteration, verify the attribute IDs and
-  // update the entry count in each type.
-  const auto bag_iter_end = end(bag);
-  for (auto bag_iter = begin(bag); bag_iter != bag_iter_end; ++bag_iter) {
+  int last_type_idx = -1;
+  int last_package_idx = -1;
+  Package* last_package = nullptr;
+  ThemeType* last_type = nullptr;
+
+  // Iterate backwards, because each bag is sorted in ascending key ID order, meaning we will only
+  // need to perform one resize per type.
+  using reverse_bag_iterator = std::reverse_iterator<const ResolvedBag::Entry*>;
+  const auto bag_iter_end = reverse_bag_iterator(begin(bag));
+  for (auto bag_iter = reverse_bag_iterator(end(bag)); bag_iter != bag_iter_end; ++bag_iter) {
     const uint32_t attr_resid = bag_iter->key;
 
-    // If the resource ID passed in is not a style, the key can be
-    // some other identifier that is not a resource ID.
+    // If the resource ID passed in is not a style, the key can be some other identifier that is not
+    // a resource ID. We should fail fast instead of operating with strange resource IDs.
     if (!is_valid_resid(attr_resid)) {
       return false;
     }
 
-    const uint32_t package_idx = get_package_id(attr_resid);
+    // We don't use the 0-based index for the type so that we can avoid doing ID validation
+    // upon lookup. Instead, we keep space for the type ID 0 in our data structures. Since
+    // the construction of this type is guarded with a resource ID check, it will never be
+    // populated, and querying type ID 0 will always fail.
+    const int package_idx = get_package_id(attr_resid);
+    const int type_idx = get_type_id(attr_resid);
+    const int entry_idx = get_entry_id(attr_resid);
 
-    // The type ID is 1-based, so subtract 1 to get an index.
-    const uint32_t type_idx = get_type_id(attr_resid) - 1;
-    const uint32_t entry_idx = get_entry_id(attr_resid);
-
-    std::unique_ptr<Package>& package = packages_[package_idx];
-    if (package == nullptr) {
-      package.reset(new Package());
-    }
-
-    util::unique_cptr<Type>& type = package->types[type_idx];
-    if (type == nullptr) {
-      // Set the initial capacity to take up a total amount of 1024 bytes.
-      constexpr uint32_t kInitialCapacity = (1024u - sizeof(Type)) / sizeof(Entry);
-      const uint32_t initial_capacity = std::max(entry_idx, kInitialCapacity);
-      type.reset(
-          reinterpret_cast<Type*>(calloc(sizeof(Type) + (initial_capacity * sizeof(Entry)), 1)));
-      type->entry_capacity = initial_capacity;
-    }
-
-    // Set the entry_count to include this entry. We will populate
-    // and resize the array as necessary in the next pass.
-    if (entry_idx + 1 > type->entry_count) {
-      // Increase the entry count to include this.
-      type->entry_count = entry_idx + 1;
-    }
-  }
-
-  // On the second pass, we will realloc to fit the entry counts
-  // and populate the structures.
-  for (auto bag_iter = begin(bag); bag_iter != bag_iter_end; ++bag_iter) {
-    const uint32_t attr_resid = bag_iter->key;
-    const uint32_t package_idx = get_package_id(attr_resid);
-    const uint32_t type_idx = get_type_id(attr_resid) - 1;
-    const uint32_t entry_idx = get_entry_id(attr_resid);
-    Package* package = packages_[package_idx].get();
-    util::unique_cptr<Type>& type = package->types[type_idx];
-    if (type->entry_count != type->entry_capacity) {
-      // Resize to fit the actual entries that will be included.
-      Type* type_ptr = type.release();
-      type.reset(reinterpret_cast<Type*>(
-          realloc(type_ptr, sizeof(Type) + (type_ptr->entry_count * sizeof(Entry)))));
-      if (type->entry_capacity < type->entry_count) {
-        // Clear the newly allocated memory (which does not get zero initialized).
-        // We need to do this because we |= type_spec_flags.
-        memset(type->entries + type->entry_capacity, 0,
-               sizeof(Entry) * (type->entry_count - type->entry_capacity));
+    if (last_package_idx != package_idx) {
+      std::unique_ptr<Package>& package = packages_[package_idx];
+      if (package == nullptr) {
+        package.reset(new Package());
       }
-      type->entry_capacity = type->entry_count;
+      last_package_idx = package_idx;
+      last_package = package.get();
+      last_type_idx = -1;
     }
-    Entry& entry = type->entries[entry_idx];
-    if (force || entry.value.dataType == Res_value::TYPE_NULL) {
+
+    if (last_type_idx != type_idx) {
+      util::unique_cptr<ThemeType>& type = last_package->types[type_idx];
+      if (type == nullptr) {
+        // Allocate enough memory to contain this entry_idx. Since we're iterating in reverse over
+        // a sorted list of attributes, this shouldn't be resized again during this method call.
+        type.reset(reinterpret_cast<ThemeType*>(
+            calloc(sizeof(ThemeType) + (entry_idx + 1) * sizeof(ThemeEntry), 1)));
+        type->entry_count = entry_idx + 1;
+      } else if (entry_idx >= type->entry_count) {
+        // Reallocate the memory to contain this entry_idx. Since we're iterating in reverse over
+        // a sorted list of attributes, this shouldn't be resized again during this method call.
+        const int new_count = entry_idx + 1;
+        type.reset(reinterpret_cast<ThemeType*>(
+            realloc(type.release(), sizeof(ThemeType) + (new_count * sizeof(ThemeEntry)))));
+
+        // Clear out the newly allocated space (which isn't zeroed).
+        memset(type->entries + type->entry_count, 0,
+               (new_count - type->entry_count) * sizeof(ThemeEntry));
+        type->entry_count = new_count;
+      }
+      last_type_idx = type_idx;
+      last_type = type.get();
+    }
+
+    ThemeEntry& entry = last_type->entries[entry_idx];
+    if (force || (entry.value.dataType == Res_value::TYPE_NULL &&
+                  entry.value.data != Res_value::DATA_NULL_EMPTY)) {
       entry.cookie = bag_iter->cookie;
       entry.type_spec_flags |= bag->type_spec_flags;
       entry.value = bag_iter->value;
@@ -786,88 +828,46 @@
 
 ApkAssetsCookie Theme::GetAttribute(uint32_t resid, Res_value* out_value,
                                     uint32_t* out_flags) const {
-  constexpr const int kMaxIterations = 20;
+  int cnt = 20;
 
   uint32_t type_spec_flags = 0u;
 
-  for (int iterations_left = kMaxIterations; iterations_left > 0; iterations_left--) {
-    if (!is_valid_resid(resid)) {
-      return kInvalidCookie;
-    }
-
-    const uint32_t package_idx = get_package_id(resid);
-
-    // Type ID is 1-based, subtract 1 to get the index.
-    const uint32_t type_idx = get_type_id(resid) - 1;
-    const uint32_t entry_idx = get_entry_id(resid);
-
+  do {
+    const int package_idx = get_package_id(resid);
     const Package* package = packages_[package_idx].get();
-    if (package == nullptr) {
-      return kInvalidCookie;
-    }
+    if (package != nullptr) {
+      // The themes are constructed with a 1-based type ID, so no need to decrement here.
+      const int type_idx = get_type_id(resid);
+      const ThemeType* type = package->types[type_idx].get();
+      if (type != nullptr) {
+        const int entry_idx = get_entry_id(resid);
+        if (entry_idx < type->entry_count) {
+          const ThemeEntry& entry = type->entries[entry_idx];
+          type_spec_flags |= entry.type_spec_flags;
 
-    const Type* type = package->types[type_idx].get();
-    if (type == nullptr) {
-      return kInvalidCookie;
-    }
+          if (entry.value.dataType == Res_value::TYPE_ATTRIBUTE) {
+            if (cnt > 0) {
+              cnt--;
+              resid = entry.value.data;
+              continue;
+            }
+            return kInvalidCookie;
+          }
 
-    if (entry_idx >= type->entry_count) {
-      return kInvalidCookie;
-    }
+          // @null is different than @empty.
+          if (entry.value.dataType == Res_value::TYPE_NULL &&
+              entry.value.data != Res_value::DATA_NULL_EMPTY) {
+            return kInvalidCookie;
+          }
 
-    const Entry& entry = type->entries[entry_idx];
-    type_spec_flags |= entry.type_spec_flags;
-
-    switch (entry.value.dataType) {
-      case Res_value::TYPE_NULL:
-        return kInvalidCookie;
-
-      case Res_value::TYPE_ATTRIBUTE:
-        resid = entry.value.data;
-        break;
-
-      case Res_value::TYPE_DYNAMIC_ATTRIBUTE: {
-        // Resolve the dynamic attribute to a normal attribute
-        // (with the right package ID).
-        resid = entry.value.data;
-        const DynamicRefTable* ref_table =
-            asset_manager_->GetDynamicRefTableForPackage(package_idx);
-        if (ref_table == nullptr || ref_table->lookupResourceId(&resid) != NO_ERROR) {
-          LOG(ERROR) << base::StringPrintf("Failed to resolve dynamic attribute 0x%08x", resid);
-          return kInvalidCookie;
-        }
-      } break;
-
-      case Res_value::TYPE_DYNAMIC_REFERENCE: {
-        // Resolve the dynamic reference to a normal reference
-        // (with the right package ID).
-        out_value->dataType = Res_value::TYPE_REFERENCE;
-        out_value->data = entry.value.data;
-        const DynamicRefTable* ref_table =
-            asset_manager_->GetDynamicRefTableForPackage(package_idx);
-        if (ref_table == nullptr || ref_table->lookupResourceId(&out_value->data) != NO_ERROR) {
-          LOG(ERROR) << base::StringPrintf("Failed to resolve dynamic reference 0x%08x",
-                                           out_value->data);
-          return kInvalidCookie;
-        }
-
-        if (out_flags != nullptr) {
+          *out_value = entry.value;
           *out_flags = type_spec_flags;
+          return entry.cookie;
         }
-        return entry.cookie;
       }
-
-      default:
-        *out_value = entry.value;
-        if (out_flags != nullptr) {
-          *out_flags = type_spec_flags;
-        }
-        return entry.cookie;
     }
-  }
-
-  LOG(WARNING) << base::StringPrintf("Too many (%d) attribute references, stopped at: 0x%08x",
-                                     kMaxIterations, resid);
+    break;
+  } while (true);
   return kInvalidCookie;
 }
 
@@ -920,7 +920,7 @@
     }
 
     for (size_t t = 0; t < package->types.size(); t++) {
-      const Type* type = package->types[t].get();
+      const ThemeType* type = package->types[t].get();
       if (type == nullptr) {
         // The other theme doesn't have this type, clear ours.
         packages_[p]->types[t].reset();
@@ -928,10 +928,10 @@
       }
 
       // Create a new type and update it to theirs.
-      const size_t type_alloc_size = sizeof(Type) + (type->entry_capacity * sizeof(Entry));
+      const size_t type_alloc_size = sizeof(ThemeType) + (type->entry_count * sizeof(ThemeEntry));
       void* copied_data = malloc(type_alloc_size);
       memcpy(copied_data, type, type_alloc_size);
-      packages_[p]->types[t].reset(reinterpret_cast<Type*>(copied_data));
+      packages_[p]->types[t].reset(reinterpret_cast<ThemeType*>(copied_data));
     }
   }
   return true;
diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp
new file mode 100644
index 0000000..7c1ee5c
--- /dev/null
+++ b/libs/androidfw/Idmap.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_RESOURCES
+
+#include "androidfw/Idmap.h"
+
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+#include "utils/ByteOrder.h"
+#include "utils/Trace.h"
+
+#ifdef _WIN32
+#ifdef ERROR
+#undef ERROR
+#endif
+#endif
+
+#include "androidfw/ResourceTypes.h"
+
+using ::android::base::StringPrintf;
+
+namespace android {
+
+constexpr static inline bool is_valid_package_id(uint16_t id) {
+  return id != 0 && id <= 255;
+}
+
+constexpr static inline bool is_valid_type_id(uint16_t id) {
+  // Type IDs and package IDs have the same constraints in the IDMAP.
+  return is_valid_package_id(id);
+}
+
+bool LoadedIdmap::Lookup(const IdmapEntry_header* header, uint16_t input_entry_id,
+                         uint16_t* output_entry_id) {
+  if (input_entry_id < dtohs(header->entry_id_offset)) {
+    // After applying the offset, the entry is not present.
+    return false;
+  }
+
+  input_entry_id -= dtohs(header->entry_id_offset);
+  if (input_entry_id >= dtohs(header->entry_count)) {
+    // The entry is not present.
+    return false;
+  }
+
+  uint32_t result = dtohl(header->entries[input_entry_id]);
+  if (result == 0xffffffffu) {
+    return false;
+  }
+  *output_entry_id = static_cast<uint16_t>(result);
+  return true;
+}
+
+static bool is_word_aligned(const void* data) {
+  return (reinterpret_cast<uintptr_t>(data) & 0x03) == 0;
+}
+
+static bool IsValidIdmapHeader(const StringPiece& data) {
+  if (!is_word_aligned(data.data())) {
+    LOG(ERROR) << "Idmap header is not word aligned.";
+    return false;
+  }
+
+  if (data.size() < sizeof(Idmap_header)) {
+    LOG(ERROR) << "Idmap header is too small.";
+    return false;
+  }
+
+  const Idmap_header* header = reinterpret_cast<const Idmap_header*>(data.data());
+  if (dtohl(header->magic) != kIdmapMagic) {
+    LOG(ERROR) << StringPrintf("Invalid Idmap file: bad magic value (was 0x%08x, expected 0x%08x)",
+                               dtohl(header->magic), kIdmapMagic);
+    return false;
+  }
+
+  if (dtohl(header->version) != kIdmapCurrentVersion) {
+    // We are strict about versions because files with this format are auto-generated and don't need
+    // backwards compatibility.
+    LOG(ERROR) << StringPrintf("Version mismatch in Idmap (was 0x%08x, expected 0x%08x)",
+                               dtohl(header->version), kIdmapCurrentVersion);
+    return false;
+  }
+
+  if (!is_valid_package_id(dtohs(header->target_package_id))) {
+    LOG(ERROR) << StringPrintf("Target package ID in Idmap is invalid: 0x%02x",
+                               dtohs(header->target_package_id));
+    return false;
+  }
+
+  if (dtohs(header->type_count) > 255) {
+    LOG(ERROR) << StringPrintf("Idmap has too many type mappings (was %d, max 255)",
+                               (int)dtohs(header->type_count));
+    return false;
+  }
+  return true;
+}
+
+LoadedIdmap::LoadedIdmap(const Idmap_header* header) : header_(header) {
+  size_t length = strnlen(reinterpret_cast<const char*>(header_->overlay_path),
+                          arraysize(header_->overlay_path));
+  overlay_apk_path_.assign(reinterpret_cast<const char*>(header_->overlay_path), length);
+}
+
+std::unique_ptr<const LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_data) {
+  ATRACE_CALL();
+  if (!IsValidIdmapHeader(idmap_data)) {
+    return {};
+  }
+
+  const Idmap_header* header = reinterpret_cast<const Idmap_header*>(idmap_data.data());
+
+  // Can't use make_unique because LoadedImpl constructor is private.
+  std::unique_ptr<LoadedIdmap> loaded_idmap = std::unique_ptr<LoadedIdmap>(new LoadedIdmap(header));
+
+  const uint8_t* data_ptr = reinterpret_cast<const uint8_t*>(idmap_data.data()) + sizeof(*header);
+  size_t data_size = idmap_data.size() - sizeof(*header);
+
+  size_t type_maps_encountered = 0u;
+  while (data_size >= sizeof(IdmapEntry_header)) {
+    if (!is_word_aligned(data_ptr)) {
+      LOG(ERROR) << "Type mapping in Idmap is not word aligned";
+      return {};
+    }
+
+    // Validate the type IDs.
+    const IdmapEntry_header* entry_header = reinterpret_cast<const IdmapEntry_header*>(data_ptr);
+    if (!is_valid_type_id(dtohs(entry_header->target_type_id)) || !is_valid_type_id(dtohs(entry_header->overlay_type_id))) {
+      LOG(ERROR) << StringPrintf("Invalid type map (0x%02x -> 0x%02x)",
+                                 dtohs(entry_header->target_type_id),
+                                 dtohs(entry_header->overlay_type_id));
+      return {};
+    }
+
+    // Make sure there is enough space for the entries declared in the header.
+    if ((data_size - sizeof(*entry_header)) / sizeof(uint32_t) <
+        static_cast<size_t>(dtohs(entry_header->entry_count))) {
+      LOG(ERROR) << StringPrintf("Idmap too small for the number of entries (%d)",
+                                 (int)dtohs(entry_header->entry_count));
+      return {};
+    }
+
+    // Only add a non-empty overlay.
+    if (dtohs(entry_header->entry_count != 0)) {
+      loaded_idmap->type_map_[static_cast<uint8_t>(dtohs(entry_header->overlay_type_id))] =
+          entry_header;
+    }
+
+    const size_t entry_size_bytes =
+        sizeof(*entry_header) + (dtohs(entry_header->entry_count) * sizeof(uint32_t));
+    data_ptr += entry_size_bytes;
+    data_size -= entry_size_bytes;
+    type_maps_encountered++;
+  }
+
+  // Verify that we parsed all the type maps.
+  if (type_maps_encountered != static_cast<size_t>(dtohs(header->type_count))) {
+    LOG(ERROR) << "Parsed " << type_maps_encountered << " type maps but expected "
+               << (int)dtohs(header->type_count);
+    return {};
+  }
+  return std::move(loaded_idmap);
+}
+
+uint8_t LoadedIdmap::TargetPackageId() const {
+  return static_cast<uint8_t>(dtohs(header_->target_package_id));
+}
+
+const IdmapEntry_header* LoadedIdmap::GetEntryMapForType(uint8_t type_id) const {
+  auto iter = type_map_.find(type_id);
+  if (iter != type_map_.end()) {
+    return iter->second;
+  }
+  return nullptr;
+}
+
+}  // namespace android
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index bd7b804..c361ea2 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -37,7 +37,7 @@
 #include "androidfw/ResourceUtils.h"
 #include "androidfw/Util.h"
 
-using android::base::StringPrintf;
+using ::android::base::StringPrintf;
 
 namespace android {
 
@@ -61,6 +61,10 @@
   // and under which configurations it varies.
   const ResTable_typeSpec* type_spec;
 
+  // Pointer to the mmapped data where the IDMAP mappings for this type
+  // exist. May be nullptr if no IDMAP exists.
+  const IdmapEntry_header* idmap_entries;
+
   // The number of types that follow this struct.
   // There is a type for each configuration
   // that entries are defined for.
@@ -84,7 +88,10 @@
 // the Type structs.
 class TypeSpecPtrBuilder {
  public:
-  TypeSpecPtrBuilder(const ResTable_typeSpec* header) : header_(header) {}
+  explicit TypeSpecPtrBuilder(const ResTable_typeSpec* header,
+                              const IdmapEntry_header* idmap_header)
+      : header_(header), idmap_header_(idmap_header) {
+  }
 
   void AddType(const ResTable_type* type) {
     ResTable_config config;
@@ -99,6 +106,7 @@
     }
     TypeSpec* type_spec = (TypeSpec*)::malloc(sizeof(TypeSpec) + (types_.size() * sizeof(Type)));
     type_spec->type_spec = header_;
+    type_spec->idmap_entries = idmap_header_;
     type_spec->type_count = types_.size();
     memcpy(type_spec + 1, types_.data(), types_.size() * sizeof(Type));
     return TypeSpecPtr(type_spec);
@@ -108,50 +116,157 @@
   DISALLOW_COPY_AND_ASSIGN(TypeSpecPtrBuilder);
 
   const ResTable_typeSpec* header_;
+  const IdmapEntry_header* idmap_header_;
   std::vector<Type> types_;
 };
 
 }  // namespace
 
-bool LoadedPackage::FindEntry(uint8_t type_idx, uint16_t entry_idx, const ResTable_config& config,
-                              LoadedArscEntry* out_entry, ResTable_config* out_selected_config,
-                              uint32_t* out_flags) const {
-  ATRACE_CALL();
+LoadedPackage::LoadedPackage() = default;
+LoadedPackage::~LoadedPackage() = default;
 
-  // If the type IDs are offset in this package, we need to take that into account when searching
-  // for a type.
-  const TypeSpecPtr& ptr = type_specs_[type_idx - type_id_offset_];
-  if (ptr == nullptr) {
+// Precondition: The header passed in has already been verified, so reading any fields and trusting
+// the ResChunk_header is safe.
+static bool VerifyResTableType(const ResTable_type* header) {
+  const size_t entry_count = dtohl(header->entryCount);
+  if (entry_count > std::numeric_limits<uint16_t>::max()) {
+    LOG(ERROR) << "Too many entries in RES_TABLE_TYPE_TYPE.";
     return false;
   }
 
-  // Don't bother checking if the entry ID is larger than
-  // the number of entries.
-  if (entry_idx >= dtohl(ptr->type_spec->entryCount)) {
+  // Make sure that there is enough room for the entry offsets.
+  const size_t offsets_offset = dtohs(header->header.headerSize);
+  const size_t entries_offset = dtohl(header->entriesStart);
+  const size_t offsets_length = sizeof(uint32_t) * entry_count;
+
+  if (offsets_offset > entries_offset || entries_offset - offsets_offset < offsets_length) {
+    LOG(ERROR) << "Entry offsets overlap actual entry data.";
     return false;
   }
 
+  if (entries_offset > dtohl(header->header.size)) {
+    LOG(ERROR) << "Entry offsets extend beyond chunk.";
+    return false;
+  }
+
+  if (entries_offset & 0x03) {
+    LOG(ERROR) << "Entries start at unaligned address.";
+    return false;
+  }
+  return true;
+}
+
+static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset,
+                                size_t entry_idx) {
+  // Check that the offset is aligned.
+  if (entry_offset & 0x03) {
+    LOG(ERROR) << "Entry offset at index " << entry_idx << " is not 4-byte aligned.";
+    return false;
+  }
+
+  // Check that the offset doesn't overflow.
+  if (entry_offset > std::numeric_limits<uint32_t>::max() - dtohl(type->entriesStart)) {
+    // Overflow in offset.
+    LOG(ERROR) << "Entry offset at index " << entry_idx << " is too large.";
+    return false;
+  }
+
+  const size_t chunk_size = dtohl(type->header.size);
+
+  entry_offset += dtohl(type->entriesStart);
+  if (entry_offset > chunk_size - sizeof(ResTable_entry)) {
+    LOG(ERROR) << "Entry offset at index " << entry_idx
+               << " is too large. No room for ResTable_entry.";
+    return false;
+  }
+
+  const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>(
+      reinterpret_cast<const uint8_t*>(type) + entry_offset);
+
+  const size_t entry_size = dtohs(entry->size);
+  if (entry_size < sizeof(*entry)) {
+    LOG(ERROR) << "ResTable_entry size " << entry_size << " at index " << entry_idx
+               << " is too small.";
+    return false;
+  }
+
+  if (entry_size > chunk_size || entry_offset > chunk_size - entry_size) {
+    LOG(ERROR) << "ResTable_entry size " << entry_size << " at index " << entry_idx
+               << " is too large.";
+    return false;
+  }
+
+  if (entry_size < sizeof(ResTable_map_entry)) {
+    // There needs to be room for one Res_value struct.
+    if (entry_offset + entry_size > chunk_size - sizeof(Res_value)) {
+      LOG(ERROR) << "No room for Res_value after ResTable_entry at index " << entry_idx
+                 << " for type " << (int)type->id << ".";
+      return false;
+    }
+
+    const Res_value* value =
+        reinterpret_cast<const Res_value*>(reinterpret_cast<const uint8_t*>(entry) + entry_size);
+    const size_t value_size = dtohs(value->size);
+    if (value_size < sizeof(Res_value)) {
+      LOG(ERROR) << "Res_value at index " << entry_idx << " is too small.";
+      return false;
+    }
+
+    if (value_size > chunk_size || entry_offset + entry_size > chunk_size - value_size) {
+      LOG(ERROR) << "Res_value size " << value_size << " at index " << entry_idx
+                 << " is too large.";
+      return false;
+    }
+  } else {
+    const ResTable_map_entry* map = reinterpret_cast<const ResTable_map_entry*>(entry);
+    const size_t map_entry_count = dtohl(map->count);
+    size_t map_entries_start = entry_offset + entry_size;
+    if (map_entries_start & 0x03) {
+      LOG(ERROR) << "Map entries at index " << entry_idx << " start at unaligned offset.";
+      return false;
+    }
+
+    // Each entry is sizeof(ResTable_map) big.
+    if (map_entry_count > ((chunk_size - map_entries_start) / sizeof(ResTable_map))) {
+      LOG(ERROR) << "Too many map entries in ResTable_map_entry at index " << entry_idx << ".";
+      return false;
+    }
+  }
+  return true;
+}
+
+template <bool Verified>
+bool LoadedPackage::FindEntry(const TypeSpecPtr& type_spec_ptr, uint16_t entry_idx,
+                              const ResTable_config& config, FindEntryResult* out_entry) const {
   const ResTable_config* best_config = nullptr;
   const ResTable_type* best_type = nullptr;
   uint32_t best_offset = 0;
 
-  for (uint32_t i = 0; i < ptr->type_count; i++) {
-    const Type* type = &ptr->types[i];
+  for (uint32_t i = 0; i < type_spec_ptr->type_count; i++) {
+    const Type* type = &type_spec_ptr->types[i];
 
     if (type->configuration.match(config) &&
         (best_config == nullptr || type->configuration.isBetterThan(*best_config, &config))) {
       // The configuration matches and is better than the previous selection.
       // Find the entry value if it exists for this configuration.
-      size_t entry_count = dtohl(type->type->entryCount);
+      const size_t entry_count = dtohl(type->type->entryCount);
+      const size_t offsets_offset = dtohs(type->type->header.headerSize);
       if (entry_idx < entry_count) {
+        // If the package hasn't been verified, do bounds checking.
+        if (!Verified) {
+          if (!VerifyResTableType(type->type)) {
+            continue;
+          }
+        }
+
         const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
-            reinterpret_cast<const uint8_t*>(type->type) + dtohs(type->type->header.headerSize));
+            reinterpret_cast<const uint8_t*>(type->type) + offsets_offset);
         const uint32_t offset = dtohl(entry_offsets[entry_idx]);
         if (offset != ResTable_type::NO_ENTRY) {
           // There is an entry for this resource, record it.
           best_config = &type->configuration;
           best_type = type->type;
-          best_offset = offset + dtohl(type->type->entriesStart);
+          best_offset = offset;
         }
       }
     }
@@ -161,84 +276,64 @@
     return false;
   }
 
-  const uint32_t* flags = reinterpret_cast<const uint32_t*>(ptr->type_spec + 1);
-  *out_flags = dtohl(flags[entry_idx]);
-  *out_selected_config = *best_config;
+  if (!Verified) {
+    if (!VerifyResTableEntry(best_type, best_offset, entry_idx)) {
+      return false;
+    }
+  }
 
   const ResTable_entry* best_entry = reinterpret_cast<const ResTable_entry*>(
-      reinterpret_cast<const uint8_t*>(best_type) + best_offset);
+      reinterpret_cast<const uint8_t*>(best_type) + best_offset + dtohl(best_type->entriesStart));
+
+  const uint32_t* flags = reinterpret_cast<const uint32_t*>(type_spec_ptr->type_spec + 1);
+  out_entry->type_flags = dtohl(flags[entry_idx]);
   out_entry->entry = best_entry;
+  out_entry->config = best_config;
   out_entry->type_string_ref = StringPoolRef(&type_string_pool_, best_type->id - 1);
   out_entry->entry_string_ref = StringPoolRef(&key_string_pool_, dtohl(best_entry->key.index));
   return true;
 }
 
-// The destructor gets generated into arbitrary translation units
-// if left implicit, which causes the compiler to complain about
-// forward declarations and incomplete types.
-LoadedArsc::~LoadedArsc() {}
-
-bool LoadedArsc::FindEntry(uint32_t resid, const ResTable_config& config,
-                           LoadedArscEntry* out_entry, ResTable_config* out_selected_config,
-                           uint32_t* out_flags) const {
+bool LoadedPackage::FindEntry(uint8_t type_idx, uint16_t entry_idx, const ResTable_config& config,
+                              FindEntryResult* out_entry) const {
   ATRACE_CALL();
-  const uint8_t package_id = get_package_id(resid);
-  const uint8_t type_id = get_type_id(resid);
-  const uint16_t entry_id = get_entry_id(resid);
 
-  if (type_id == 0) {
-    LOG(ERROR) << "Invalid ID 0x" << std::hex << resid << std::dec << ".";
+  // If the type IDs are offset in this package, we need to take that into account when searching
+  // for a type.
+  const TypeSpecPtr& ptr = type_specs_[type_idx - type_id_offset_];
+  if (ptr == nullptr) {
     return false;
   }
 
-  for (const auto& loaded_package : packages_) {
-    if (loaded_package->package_id_ == package_id) {
-      return loaded_package->FindEntry(type_id - 1, entry_id, config, out_entry,
-                                       out_selected_config, out_flags);
+  // If there is an IDMAP supplied with this package, translate the entry ID.
+  if (ptr->idmap_entries != nullptr) {
+    if (!LoadedIdmap::Lookup(ptr->idmap_entries, entry_idx, &entry_idx)) {
+      // There is no mapping, so the resource is not meant to be in this overlay package.
+      return false;
     }
   }
-  return false;
-}
 
-const LoadedPackage* LoadedArsc::GetPackageForId(uint32_t resid) const {
-  const uint8_t package_id = get_package_id(resid);
-  for (const auto& loaded_package : packages_) {
-    if (loaded_package->package_id_ == package_id) {
-      return loaded_package.get();
-    }
+  // Don't bother checking if the entry ID is larger than the number of entries.
+  if (entry_idx >= dtohl(ptr->type_spec->entryCount)) {
+    return false;
   }
-  return nullptr;
+
+  if (verified_) {
+    return FindEntry<true>(ptr, entry_idx, config, out_entry);
+  }
+  return FindEntry<false>(ptr, entry_idx, config, out_entry);
 }
 
 static bool VerifyType(const Chunk& chunk) {
   ATRACE_CALL();
   const ResTable_type* header = chunk.header<ResTable_type, kResTableTypeMinSize>();
 
+  if (!VerifyResTableType(header)) {
+    return false;
+  }
+
   const size_t entry_count = dtohl(header->entryCount);
-  if (entry_count > std::numeric_limits<uint16_t>::max()) {
-    LOG(ERROR) << "Too many entries in RES_TABLE_TYPE_TYPE.";
-    return false;
-  }
-
-  // Make sure that there is enough room for the entry offsets.
   const size_t offsets_offset = chunk.header_size();
-  const size_t entries_offset = dtohl(header->entriesStart);
-  const size_t offsets_length = sizeof(uint32_t) * entry_count;
-
-  if (offsets_offset + offsets_length > entries_offset) {
-    LOG(ERROR) << "Entry offsets overlap actual entry data.";
-    return false;
-  }
-
-  if (entries_offset > chunk.size()) {
-    LOG(ERROR) << "Entry offsets extend beyond chunk.";
-    return false;
-  }
-
-  if (entries_offset & 0x03) {
-    LOG(ERROR) << "Entries start at unaligned address.";
-    return false;
-  }
 
   // Check each entry offset.
   const uint32_t* offsets =
@@ -246,77 +341,9 @@
   for (size_t i = 0; i < entry_count; i++) {
     uint32_t offset = dtohl(offsets[i]);
     if (offset != ResTable_type::NO_ENTRY) {
-      // Check that the offset is aligned.
-      if (offset & 0x03) {
-        LOG(ERROR) << "Entry offset at index " << i << " is not 4-byte aligned.";
+      if (!VerifyResTableEntry(header, offset, i)) {
         return false;
       }
-
-      // Check that the offset doesn't overflow.
-      if (offset > std::numeric_limits<uint32_t>::max() - entries_offset) {
-        // Overflow in offset.
-        LOG(ERROR) << "Entry offset at index " << i << " is too large.";
-        return false;
-      }
-
-      offset += entries_offset;
-      if (offset > chunk.size() - sizeof(ResTable_entry)) {
-        LOG(ERROR) << "Entry offset at index " << i << " is too large. No room for ResTable_entry.";
-        return false;
-      }
-
-      const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>(
-          reinterpret_cast<const uint8_t*>(header) + offset);
-      const size_t entry_size = dtohs(entry->size);
-      if (entry_size < sizeof(*entry)) {
-        LOG(ERROR) << "ResTable_entry size " << entry_size << " is too small.";
-        return false;
-      }
-
-      // Check the declared entrySize.
-      if (entry_size > chunk.size() || offset > chunk.size() - entry_size) {
-        LOG(ERROR) << "ResTable_entry size " << entry_size << " is too large.";
-        return false;
-      }
-
-      // If this is a map entry, then keep validating.
-      if (entry_size >= sizeof(ResTable_map_entry)) {
-        const ResTable_map_entry* map = reinterpret_cast<const ResTable_map_entry*>(entry);
-        const size_t map_entry_count = dtohl(map->count);
-
-        size_t map_entries_start = offset + entry_size;
-        if (map_entries_start & 0x03) {
-          LOG(ERROR) << "Map entries start at unaligned offset.";
-          return false;
-        }
-
-        // Each entry is sizeof(ResTable_map) big.
-        if (map_entry_count > ((chunk.size() - map_entries_start) / sizeof(ResTable_map))) {
-          LOG(ERROR) << "Too many map entries in ResTable_map_entry.";
-          return false;
-        }
-
-        // Great, all the map entries fit!.
-      } else {
-        // There needs to be room for one Res_value struct.
-        if (offset + entry_size > chunk.size() - sizeof(Res_value)) {
-          LOG(ERROR) << "No room for Res_value after ResTable_entry.";
-          return false;
-        }
-
-        const Res_value* value = reinterpret_cast<const Res_value*>(
-            reinterpret_cast<const uint8_t*>(entry) + entry_size);
-        const size_t value_size = dtohs(value->size);
-        if (value_size < sizeof(Res_value)) {
-          LOG(ERROR) << "Res_value is too small.";
-          return false;
-        }
-
-        if (value_size > chunk.size() || offset + entry_size > chunk.size() - value_size) {
-          LOG(ERROR) << "Res_value size is too large.";
-          return false;
-        }
-      }
     }
   }
   return true;
@@ -412,10 +439,24 @@
   return 0u;
 }
 
-std::unique_ptr<LoadedPackage> LoadedPackage::Load(const Chunk& chunk) {
-  ATRACE_CALL();
-  std::unique_ptr<LoadedPackage> loaded_package{new LoadedPackage()};
+const LoadedPackage* LoadedArsc::GetPackageForId(uint32_t resid) const {
+  const uint8_t package_id = get_package_id(resid);
+  for (const auto& loaded_package : packages_) {
+    if (loaded_package->GetPackageId() == package_id) {
+      return loaded_package.get();
+    }
+  }
+  return nullptr;
+}
 
+std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
+                                                         const LoadedIdmap* loaded_idmap,
+                                                         bool system, bool load_as_shared_library) {
+  ATRACE_CALL();
+  std::unique_ptr<LoadedPackage> loaded_package(new LoadedPackage());
+
+  // typeIdOffset was added at some point, but we still must recognize apps built before this
+  // was added.
   constexpr size_t kMinPackageSize =
       sizeof(ResTable_package) - sizeof(ResTable_package::typeIdOffset);
   const ResTable_package* header = chunk.header<ResTable_package, kMinPackageSize>();
@@ -424,12 +465,21 @@
     return {};
   }
 
+  loaded_package->system_ = system;
+
   loaded_package->package_id_ = dtohl(header->id);
-  if (loaded_package->package_id_ == 0) {
+  if (loaded_package->package_id_ == 0 ||
+      (loaded_package->package_id_ == kAppPackageId && load_as_shared_library)) {
     // Package ID of 0 means this is a shared library.
     loaded_package->dynamic_ = true;
   }
 
+  if (loaded_idmap != nullptr) {
+    // This is an overlay and so it needs to pretend to be the target package.
+    loaded_package->package_id_ = loaded_idmap->TargetPackageId();
+    loaded_package->overlay_ = true;
+  }
+
   if (header->header.headerSize >= sizeof(ResTable_package)) {
     uint32_t type_id_offset = dtohl(header->typeIdOffset);
     if (type_id_offset > std::numeric_limits<uint8_t>::max()) {
@@ -490,7 +540,16 @@
             LOG(ERROR) << "Too many type configurations, overflow detected.";
             return {};
           }
-          loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr);
+
+          // We only add the type to the package if there is no IDMAP, or if the type is
+          // overlaying something.
+          if (loaded_idmap == nullptr || type_spec_ptr->idmap_entries != nullptr) {
+            // If this is an overlay, insert it at the target type ID.
+            if (type_spec_ptr->idmap_entries != nullptr) {
+              last_type_idx = dtohs(type_spec_ptr->idmap_entries->target_type_id) - 1;
+            }
+            loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr);
+          }
 
           types_builder = {};
           last_type_idx = 0;
@@ -531,7 +590,15 @@
         }
 
         last_type_idx = type_spec->id - 1;
-        types_builder = util::make_unique<TypeSpecPtrBuilder>(type_spec);
+
+        // If this is an overlay, associate the mapping of this type to the target type
+        // from the IDMAP.
+        const IdmapEntry_header* idmap_entry_header = nullptr;
+        if (loaded_idmap != nullptr) {
+          idmap_entry_header = loaded_idmap->GetEntryMapForType(type_spec->id);
+        }
+
+        types_builder = util::make_unique<TypeSpecPtrBuilder>(type_spec, idmap_entry_header);
       } break;
 
       case RES_TABLE_TYPE_TYPE: {
@@ -548,13 +615,16 @@
 
         // Type chunks must be preceded by their TypeSpec chunks.
         if (!types_builder || type->id - 1 != last_type_idx) {
-          LOG(ERROR) << "Found RES_TABLE_TYPE_TYPE chunk without "
-                        "RES_TABLE_TYPE_SPEC_TYPE.";
+          LOG(ERROR) << "Found RES_TABLE_TYPE_TYPE chunk without RES_TABLE_TYPE_SPEC_TYPE.";
           return {};
         }
 
-        if (!VerifyType(child_chunk)) {
-          return {};
+        // Only verify the type if we haven't already failed verification.
+        if (loaded_package->verified_) {
+          if (!VerifyType(child_chunk)) {
+            LOG(WARNING) << "Package failed verification, resource retrieval may be slower";
+            loaded_package->verified_ = false;
+          }
         }
 
         types_builder->AddType(type);
@@ -608,17 +678,48 @@
       LOG(ERROR) << "Too many type configurations, overflow detected.";
       return {};
     }
-    loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr);
+
+    // We only add the type to the package if there is no IDMAP, or if the type is
+    // overlaying something.
+    if (loaded_idmap == nullptr || type_spec_ptr->idmap_entries != nullptr) {
+      // If this is an overlay, insert it at the target type ID.
+      if (type_spec_ptr->idmap_entries != nullptr) {
+        last_type_idx = dtohs(type_spec_ptr->idmap_entries->target_type_id) - 1;
+      }
+      loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr);
+    }
   }
 
   if (iter.HadError()) {
     LOG(ERROR) << iter.GetLastError();
     return {};
   }
-  return loaded_package;
+  return std::move(loaded_package);
 }
 
-bool LoadedArsc::LoadTable(const Chunk& chunk, bool load_as_shared_library) {
+bool LoadedArsc::FindEntry(uint32_t resid, const ResTable_config& config,
+                           FindEntryResult* out_entry) const {
+  ATRACE_CALL();
+
+  const uint8_t package_id = get_package_id(resid);
+  const uint8_t type_id = get_type_id(resid);
+  const uint16_t entry_id = get_entry_id(resid);
+
+  if (type_id == 0) {
+    LOG(ERROR) << base::StringPrintf("Invalid ID 0x%08x.", resid);
+    return false;
+  }
+
+  for (const auto& loaded_package : packages_) {
+    if (loaded_package->GetPackageId() == package_id) {
+      return loaded_package->FindEntry(type_id - 1, entry_id, config, out_entry);
+    }
+  }
+  return false;
+}
+
+bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap,
+                           bool load_as_shared_library) {
   ATRACE_CALL();
   const ResTable_header* header = chunk.header<ResTable_header>();
   if (header == nullptr) {
@@ -652,22 +753,16 @@
       case RES_TABLE_PACKAGE_TYPE: {
         if (packages_seen + 1 > package_count) {
           LOG(ERROR) << "More package chunks were found than the " << package_count
-                     << " declared in the "
-                        "header.";
+                     << " declared in the header.";
           return false;
         }
         packages_seen++;
 
-        std::unique_ptr<LoadedPackage> loaded_package = LoadedPackage::Load(child_chunk);
+        std::unique_ptr<const LoadedPackage> loaded_package =
+            LoadedPackage::Load(child_chunk, loaded_idmap, system_, load_as_shared_library);
         if (!loaded_package) {
           return false;
         }
-
-        // Mark the package as dynamic if we are forcefully loading the Apk as a shared library.
-        if (loaded_package->package_id_ == kAppPackageId) {
-          loaded_package->dynamic_ = load_as_shared_library;
-        }
-        loaded_package->system_ = system_;
         packages_.push_back(std::move(loaded_package));
       } break;
 
@@ -684,7 +779,8 @@
   return true;
 }
 
-std::unique_ptr<const LoadedArsc> LoadedArsc::Load(const void* data, size_t len, bool system,
+std::unique_ptr<const LoadedArsc> LoadedArsc::Load(const StringPiece& data,
+                                                   const LoadedIdmap* loaded_idmap, bool system,
                                                    bool load_as_shared_library) {
   ATRACE_CALL();
 
@@ -692,12 +788,12 @@
   std::unique_ptr<LoadedArsc> loaded_arsc(new LoadedArsc());
   loaded_arsc->system_ = system;
 
-  ChunkIterator iter(data, len);
+  ChunkIterator iter(data.data(), data.size());
   while (iter.HasNext()) {
     const Chunk chunk = iter.Next();
     switch (chunk.type()) {
       case RES_TABLE_TYPE:
-        if (!loaded_arsc->LoadTable(chunk, load_as_shared_library)) {
+        if (!loaded_arsc->LoadTable(chunk, loaded_idmap, load_as_shared_library)) {
           return {};
         }
         break;
@@ -717,4 +813,8 @@
   return std::move(loaded_arsc);
 }
 
+std::unique_ptr<const LoadedArsc> LoadedArsc::CreateEmpty() {
+  return std::unique_ptr<LoadedArsc>(new LoadedArsc());
+}
+
 }  // namespace android
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 7a0ef2b..87999c3 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -6014,9 +6014,6 @@
 StringPoolRef::StringPoolRef(const ResStringPool* pool, uint32_t index)
     : mPool(pool), mIndex(index) {}
 
-StringPoolRef::StringPoolRef()
-    : mPool(NULL), mIndex(0) {}
-
 const char* StringPoolRef::string8(size_t* outLen) const {
     if (mPool != NULL) {
         return mPool->string8At(mIndex, outLen);
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
index 2e392d5..3a307fc 100644
--- a/libs/androidfw/include/androidfw/ApkAssets.h
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -28,36 +28,63 @@
 
 namespace android {
 
+class LoadedIdmap;
+
 // Holds an APK.
 class ApkAssets {
  public:
+  // Creates an ApkAssets.
+  // If `system` is true, the package is marked as a system package, and allows some functions to
+  // filter out this package when computing what configurations/resources are available.
   static std::unique_ptr<const ApkAssets> Load(const std::string& path, bool system = false);
+
+  // Creates an ApkAssets, but forces any package with ID 0x7f to be loaded as a shared library.
+  // If `system` is true, the package is marked as a system package, and allows some functions to
+  // filter out this package when computing what configurations/resources are available.
   static std::unique_ptr<const ApkAssets> LoadAsSharedLibrary(const std::string& path,
                                                               bool system = false);
 
+  // Creates an ApkAssets from an IDMAP, which contains the original APK path, and the overlay
+  // data.
+  // If `system` is true, the package is marked as a system package, and allows some functions to
+  // filter out this package when computing what configurations/resources are available.
+  static std::unique_ptr<const ApkAssets> LoadOverlay(const std::string& idmap_path,
+                                                      bool system = false);
+
   std::unique_ptr<Asset> Open(const std::string& path,
                               Asset::AccessMode mode = Asset::AccessMode::ACCESS_RANDOM) const;
 
   bool ForEachFile(const std::string& path,
                    const std::function<void(const StringPiece&, FileType)>& f) const;
 
-  inline const std::string& GetPath() const { return path_; }
+  inline const std::string& GetPath() const {
+    return path_;
+  }
 
-  inline const LoadedArsc* GetLoadedArsc() const { return loaded_arsc_.get(); }
+  // This is never nullptr.
+  inline const LoadedArsc* GetLoadedArsc() const {
+    return loaded_arsc_.get();
+  }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ApkAssets);
 
-  static std::unique_ptr<const ApkAssets> LoadImpl(const std::string& path, bool system,
-                                                   bool load_as_shared_library);
+  static std::unique_ptr<const ApkAssets> LoadImpl(const std::string& path,
+                                                   std::unique_ptr<Asset> idmap_asset,
+                                                   std::unique_ptr<const LoadedIdmap> loaded_idmap,
+                                                   bool system, bool load_as_shared_library);
 
-  ApkAssets();
+  // Creates an Asset from any file on the file system.
+  static std::unique_ptr<Asset> CreateAssetFromFile(const std::string& path);
+
+  ApkAssets(void* unmanaged_handle, const std::string& path);
 
   using ZipArchivePtr = std::unique_ptr<void, void(*)(void*)>;
 
   ZipArchivePtr zip_handle_;
-  std::string path_;
+  const std::string path_;
   std::unique_ptr<Asset> resources_asset_;
+  std::unique_ptr<Asset> idmap_asset_;
   std::unique_ptr<const LoadedArsc> loaded_arsc_;
 };
 
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index fd94144..a77c4b9 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -96,24 +96,29 @@
   // new resource IDs.
   bool SetApkAssets(const std::vector<const ApkAssets*>& apk_assets, bool invalidate_caches = true);
 
-  inline const std::vector<const ApkAssets*> GetApkAssets() const { return apk_assets_; }
+  inline const std::vector<const ApkAssets*> GetApkAssets() const {
+    return apk_assets_;
+  }
 
   // Returns the string pool for the given asset cookie.
-  // Use the string pool returned here with a valid Res_value object of
-  // type Res_value::TYPE_STRING.
+  // Use the string pool returned here with a valid Res_value object of type Res_value::TYPE_STRING.
   const ResStringPool* GetStringPoolForCookie(ApkAssetsCookie cookie) const;
 
   // Returns the DynamicRefTable for the given package ID.
+  // This may be nullptr if the APK represented by `cookie` has no resource table.
   const DynamicRefTable* GetDynamicRefTableForPackage(uint32_t package_id) const;
 
   // Returns the DynamicRefTable for the ApkAssets represented by the cookie.
+  // This may be nullptr if the APK represented by `cookie` has no resource table.
   const DynamicRefTable* GetDynamicRefTableForCookie(ApkAssetsCookie cookie) const;
 
   // Sets/resets the configuration for this AssetManager. This will cause all
   // caches that are related to the configuration change to be invalidated.
   void SetConfiguration(const ResTable_config& configuration);
 
-  inline const ResTable_config& GetConfiguration() const { return configuration_; }
+  inline const ResTable_config& GetConfiguration() const {
+    return configuration_;
+  }
 
   // Returns all configurations for which there are resources defined. This includes resource
   // configurations in all the ApkAssets set for this AssetManager.
@@ -227,26 +232,35 @@
   // Creates a new Theme from this AssetManager.
   std::unique_ptr<Theme> NewTheme();
 
+  template <typename Func>
+  void ForEachPackage(Func func) {
+    for (const PackageGroup& package_group : package_groups_) {
+      func(package_group.packages_.front()->GetPackageName(),
+           package_group.dynamic_ref_table.mAssignedPackageId);
+    }
+  }
+
   void DumpToLog() const;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(AssetManager2);
 
-  // Finds the best entry for `resid` amongst all the ApkAssets. The entry can be a simple
-  // Res_value, or a complex map/bag type.
+  // Finds the best entry for `resid` from the set of ApkAssets. The entry can be a simple
+  // Res_value, or a complex map/bag type. If successful, it is available in `out_entry`.
+  // Returns kInvalidCookie on failure. Otherwise, the return value is the cookie associated with
+  // the ApkAssets in which the entry was found.
   //
   // `density_override` overrides the density of the current configuration when doing a search.
   //
   // When `stop_at_first_match` is true, the first match found is selected and the search
   // terminates. This is useful for methods that just look up the name of a resource and don't
-  // care about the value. In this case, the value of `out_flags` is incomplete and should not
-  // be used.
+  // care about the value. In this case, the value of `FindEntryResult::type_flags` is incomplete
+  // and should not be used.
   //
-  // `out_flags` stores the resulting bitmask of configuration axis with which the resource
-  // value varies.
+  // NOTE: FindEntry takes care of ensuring that structs within FindEntryResult have been properly
+  // bounds-checked. Callers of FindEntry are free to trust the data if this method succeeds.
   ApkAssetsCookie FindEntry(uint32_t resid, uint16_t density_override, bool stop_at_first_match,
-                            LoadedArscEntry* out_entry, ResTable_config* out_selected_config,
-                            uint32_t* out_flags);
+                            FindEntryResult* out_entry);
 
   // Assigns package IDs to all shared library ApkAssets.
   // Should be called whenever the ApkAssets are changed.
@@ -289,6 +303,8 @@
   friend class AssetManager2;
 
  public:
+  ~Theme();
+
   // Applies the style identified by `resid` to this theme. This can be called
   // multiple times with different styles. By default, any theme attributes that
   // are already defined before this call are not overridden. If `force` is set
@@ -303,27 +319,31 @@
 
   void Clear();
 
-  inline const AssetManager2* GetAssetManager() const { return asset_manager_; }
+  inline const AssetManager2* GetAssetManager() const {
+    return asset_manager_;
+  }
 
-  inline AssetManager2* GetAssetManager() { return asset_manager_; }
+  inline AssetManager2* GetAssetManager() {
+    return asset_manager_;
+  }
 
   // Returns a bit mask of configuration changes that will impact this
   // theme (and thus require completely reloading it).
-  inline uint32_t GetChangingConfigurations() const { return type_spec_flags_; }
+  inline uint32_t GetChangingConfigurations() const {
+    return type_spec_flags_;
+  }
 
-  // Retrieve a value in the theme. If the theme defines this value,
-  // returns an asset cookie indicating which ApkAssets it came from
-  // and populates `out_value` with the value. If `out_flags` is non-null,
-  // populates it with a bitmask of the configuration axis the resource
-  // varies with.
+  // Retrieve a value in the theme. If the theme defines this value, returns an asset cookie
+  // indicating which ApkAssets it came from and populates `out_value` with the value.
+  // `out_flags` is populated with a bitmask of the configuration axis with which the resource
+  // varies.
   //
   // If the attribute is not found, returns kInvalidCookie.
   //
-  // NOTE: This function does not do reference traversal. If you want
-  // to follow references to other resources to get the "real" value to
-  // use, you need to call ResolveReference() after this function.
-  ApkAssetsCookie GetAttribute(uint32_t resid, Res_value* out_value,
-                               uint32_t* out_flags = nullptr) const;
+  // NOTE: This function does not do reference traversal. If you want to follow references to other
+  // resources to get the "real" value to use, you need to call ResolveReference() after this
+  // function.
+  ApkAssetsCookie GetAttribute(uint32_t resid, Res_value* out_value, uint32_t* out_flags) const;
 
   // This is like AssetManager2::ResolveReference(), but also takes
   // care of resolving attribute references to the theme.
@@ -336,36 +356,21 @@
   DISALLOW_COPY_AND_ASSIGN(Theme);
 
   // Called by AssetManager2.
-  explicit inline Theme(AssetManager2* asset_manager) : asset_manager_(asset_manager) {}
-
-  struct Entry {
-    ApkAssetsCookie cookie;
-    uint32_t type_spec_flags;
-    Res_value value;
-  };
-
-  struct Type {
-    // Use uint32_t for fewer cycles when loading from memory.
-    uint32_t entry_count;
-    uint32_t entry_capacity;
-    Entry entries[0];
-  };
-
-  static constexpr const size_t kPackageCount = std::numeric_limits<uint8_t>::max() + 1;
-  static constexpr const size_t kTypeCount = std::numeric_limits<uint8_t>::max() + 1;
-
-  struct Package {
-    // Each element of Type will be a dynamically sized object
-    // allocated to have the entries stored contiguously with the Type.
-    std::array<util::unique_cptr<Type>, kTypeCount> types;
-  };
+  explicit Theme(AssetManager2* asset_manager);
 
   AssetManager2* asset_manager_;
   uint32_t type_spec_flags_ = 0u;
+
+  // Defined in the cpp.
+  struct Package;
+
+  constexpr static size_t kPackageCount = std::numeric_limits<uint8_t>::max() + 1;
   std::array<std::unique_ptr<Package>, kPackageCount> packages_;
 };
 
-inline const ResolvedBag::Entry* begin(const ResolvedBag* bag) { return bag->entries; }
+inline const ResolvedBag::Entry* begin(const ResolvedBag* bag) {
+  return bag->entries;
+}
 
 inline const ResolvedBag::Entry* end(const ResolvedBag* bag) {
   return bag->entries + bag->entry_count;
diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h
new file mode 100644
index 0000000..fd02e6f
--- /dev/null
+++ b/libs/androidfw/include/androidfw/Idmap.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IDMAP_H_
+#define IDMAP_H_
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include "android-base/macros.h"
+
+#include "androidfw/StringPiece.h"
+
+namespace android {
+
+struct Idmap_header;
+struct IdmapEntry_header;
+
+// Represents a loaded/parsed IDMAP for a Runtime Resource Overlay (RRO).
+// An RRO and its target APK have different resource IDs assigned to their resources. Overlaying
+// a resource is done by resource name. An IDMAP is a generated mapping between the resource IDs
+// of the RRO and the target APK for each resource with the same name.
+// A LoadedIdmap can be set alongside the overlay's LoadedArsc to allow the overlay ApkAssets to
+// masquerade as the target ApkAssets resources.
+class LoadedIdmap {
+ public:
+  // Loads an IDMAP from a chunk of memory. Returns nullptr if the IDMAP data was malformed.
+  static std::unique_ptr<const LoadedIdmap> Load(const StringPiece& idmap_data);
+
+  // Performs a lookup of the expected entry ID for the given IDMAP entry header.
+  // Returns true if the mapping exists and fills `output_entry_id` with the result.
+  static bool Lookup(const IdmapEntry_header* header, uint16_t input_entry_id,
+                     uint16_t* output_entry_id);
+
+  // Returns the package ID for which this overlay should apply.
+  uint8_t TargetPackageId() const;
+
+  // Returns the path to the RRO (Runtime Resource Overlay) APK for which this IDMAP was generated.
+  inline const std::string& OverlayApkPath() const {
+    return overlay_apk_path_;
+  }
+
+  // Returns the mapping of target entry ID to overlay entry ID for the given target type.
+  const IdmapEntry_header* GetEntryMapForType(uint8_t type_id) const;
+
+ protected:
+  // Exposed as protected so that tests can subclass and mock this class out.
+  LoadedIdmap() = default;
+
+  const Idmap_header* header_ = nullptr;
+  std::string overlay_apk_path_;
+  std::unordered_map<uint8_t, const IdmapEntry_header*> type_map_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LoadedIdmap);
+
+  explicit LoadedIdmap(const Idmap_header* header);
+};
+
+}  // namespace android
+
+#endif  // IDMAP_H_
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index f30b158..377735b 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -25,6 +25,7 @@
 
 #include "androidfw/ByteBucketArray.h"
 #include "androidfw/Chunk.h"
+#include "androidfw/Idmap.h"
 #include "androidfw/ResourceTypes.h"
 #include "androidfw/Util.h"
 
@@ -40,12 +41,18 @@
   int package_id = 0;
 };
 
-struct LoadedArscEntry {
+struct FindEntryResult {
   // A pointer to the resource table entry for this resource.
   // If the size of the entry is > sizeof(ResTable_entry), it can be cast to
   // a ResTable_map_entry and processed as a bag/map.
   const ResTable_entry* entry = nullptr;
 
+  // The configuration for which the resulting entry was defined.
+  const ResTable_config* config = nullptr;
+
+  // Stores the resulting bitmask of configuration axis with which the resource value varies.
+  uint32_t type_flags = 0u;
+
   // The dynamic package ID map for the package from which this resource came from.
   const DynamicRefTable* dynamic_ref_table = nullptr;
 
@@ -62,28 +69,60 @@
 class LoadedArsc;
 
 class LoadedPackage {
-  friend class LoadedArsc;
-
  public:
+  static std::unique_ptr<const LoadedPackage> Load(const Chunk& chunk,
+                                                   const LoadedIdmap* loaded_idmap, bool system,
+                                                   bool load_as_shared_library);
+
+  ~LoadedPackage();
+
   bool FindEntry(uint8_t type_idx, uint16_t entry_idx, const ResTable_config& config,
-                 LoadedArscEntry* out_entry, ResTable_config* out_selected_config,
-                 uint32_t* out_flags) const;
+                 FindEntryResult* out_entry) const;
+
+  // Finds the entry with the specified type name and entry name. The names are in UTF-16 because
+  // the underlying ResStringPool API expects this. For now this is acceptable, but since
+  // the default policy in AAPT2 is to build UTF-8 string pools, this needs to change.
+  // Returns a partial resource ID, with the package ID left as 0x00. The caller is responsible
+  // for patching the correct package ID to the resource ID.
+  uint32_t FindEntryByName(const std::u16string& type_name, const std::u16string& entry_name) const;
 
   // Returns the string pool where type names are stored.
-  inline const ResStringPool* GetTypeStringPool() const { return &type_string_pool_; }
+  inline const ResStringPool* GetTypeStringPool() const {
+    return &type_string_pool_;
+  }
 
   // Returns the string pool where the names of resource entries are stored.
-  inline const ResStringPool* GetKeyStringPool() const { return &key_string_pool_; }
+  inline const ResStringPool* GetKeyStringPool() const {
+    return &key_string_pool_;
+  }
 
-  inline const std::string& GetPackageName() const { return package_name_; }
+  inline const std::string& GetPackageName() const {
+    return package_name_;
+  }
 
-  inline int GetPackageId() const { return package_id_; }
+  inline int GetPackageId() const {
+    return package_id_;
+  }
 
   // Returns true if this package is dynamic (shared library) and needs to have an ID assigned.
-  inline bool IsDynamic() const { return dynamic_; }
+  inline bool IsDynamic() const {
+    return dynamic_;
+  }
 
   // Returns true if this package originates from a system provided resource.
-  inline bool IsSystem() const { return system_; }
+  inline bool IsSystem() const {
+    return system_;
+  }
+
+  // Returns true if this package is from an overlay ApkAssets.
+  inline bool IsOverlay() const {
+    return overlay_;
+  }
+
+  // Returns true if this package is verified to be valid.
+  inline bool IsVerified() const {
+    return verified_;
+  }
 
   // Returns the map of package name to package ID used in this LoadedPackage. At runtime, a
   // package could have been assigned a different package ID than what this LoadedPackage was
@@ -101,19 +140,14 @@
   // before being inserted into the set. This may cause some equivalent locales to de-dupe.
   void CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const;
 
-  // Finds the entry with the specified type name and entry name. The names are in UTF-16 because
-  // the underlying ResStringPool API expects this. For now this is acceptable, but since
-  // the default policy in AAPT2 is to build UTF-8 string pools, this needs to change.
-  // Returns a partial resource ID, with the package ID left as 0x00. The caller is responsible
-  // for patching the correct package ID to the resource ID.
-  uint32_t FindEntryByName(const std::u16string& type_name, const std::u16string& entry_name) const;
-
  private:
   DISALLOW_COPY_AND_ASSIGN(LoadedPackage);
 
-  static std::unique_ptr<LoadedPackage> Load(const Chunk& chunk);
+  LoadedPackage();
 
-  LoadedPackage() = default;
+  template <bool Verified>
+  bool FindEntry(const util::unique_cptr<TypeSpec>& type_spec_ptr, uint16_t entry_idx,
+                 const ResTable_config& config, FindEntryResult* out_entry) const;
 
   ResStringPool type_string_pool_;
   ResStringPool key_string_pool_;
@@ -122,6 +156,8 @@
   int type_id_offset_ = 0;
   bool dynamic_ = false;
   bool system_ = false;
+  bool overlay_ = false;
+  bool verified_ = true;
 
   ByteBucketArray<util::unique_cptr<TypeSpec>> type_specs_;
   std::vector<DynamicPackageEntry> dynamic_package_map_;
@@ -137,27 +173,33 @@
   // If `load_as_shared_library` is set to true, the application package (0x7f) is treated
   // as a shared library (0x00). When loaded into an AssetManager, the package will be assigned an
   // ID.
-  static std::unique_ptr<const LoadedArsc> Load(const void* data, size_t len, bool system = false,
+  static std::unique_ptr<const LoadedArsc> Load(const StringPiece& data,
+                                                const LoadedIdmap* loaded_idmap = nullptr,
+                                                bool system = false,
                                                 bool load_as_shared_library = false);
 
-  ~LoadedArsc();
+  // Create an empty LoadedArsc. This is used when an APK has no resources.arsc.
+  static std::unique_ptr<const LoadedArsc> CreateEmpty();
 
   // Returns the string pool where all string resource values
   // (Res_value::dataType == Res_value::TYPE_STRING) are indexed.
-  inline const ResStringPool* GetStringPool() const { return &global_string_pool_; }
+  inline const ResStringPool* GetStringPool() const {
+    return &global_string_pool_;
+  }
 
   // Finds the resource with ID `resid` with the best value for configuration `config`.
   // The parameter `out_entry` will be filled with the resulting resource entry.
   // The resource entry can be a simple entry (ResTable_entry) or a complex bag
   // (ResTable_entry_map).
-  bool FindEntry(uint32_t resid, const ResTable_config& config, LoadedArscEntry* out_entry,
-                 ResTable_config* selected_config, uint32_t* out_flags) const;
+  bool FindEntry(uint32_t resid, const ResTable_config& config, FindEntryResult* out_entry) const;
 
   // Gets a pointer to the name of the package in `resid`, or nullptr if the package doesn't exist.
   const LoadedPackage* GetPackageForId(uint32_t resid) const;
 
   // Returns true if this is a system provided resource.
-  inline bool IsSystem() const { return system_; }
+  inline bool IsSystem() const {
+    return system_;
+  }
 
   // Returns a vector of LoadedPackage pointers, representing the packages in this LoadedArsc.
   inline const std::vector<std::unique_ptr<const LoadedPackage>>& GetPackages() const {
@@ -168,7 +210,7 @@
   DISALLOW_COPY_AND_ASSIGN(LoadedArsc);
 
   LoadedArsc() = default;
-  bool LoadTable(const Chunk& chunk, bool load_as_shared_library);
+  bool LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap, bool load_as_shared_library);
 
   ResStringPool global_string_pool_;
   std::vector<std::unique_ptr<const LoadedPackage>> packages_;
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 66c66c2..8547955 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -38,6 +38,9 @@
 
 namespace android {
 
+constexpr const static uint32_t kIdmapMagic = 0x504D4449u;
+constexpr const static uint32_t kIdmapCurrentVersion = 0x00000001u;
+
 /**
  * In C++11, char16_t is defined as *at least* 16 bits. We do a lot of
  * casting on raw data and expect char16_t to be exactly 16 bits.
@@ -543,15 +546,15 @@
  */
 class StringPoolRef {
 public:
-    StringPoolRef();
-    StringPoolRef(const ResStringPool* pool, uint32_t index);
+ StringPoolRef() = default;
+ StringPoolRef(const ResStringPool* pool, uint32_t index);
 
-    const char* string8(size_t* outLen) const;
-    const char16_t* string16(size_t* outLen) const;
+ const char* string8(size_t* outLen) const;
+ const char16_t* string16(size_t* outLen) const;
 
 private:
-    const ResStringPool*        mPool;
-    uint32_t                    mIndex;
+ const ResStringPool* mPool = nullptr;
+ uint32_t mIndex = 0u;
 };
 
 /** ********************************************************************
@@ -1583,6 +1586,30 @@
     uint16_t packageName[128];
 };
 
+struct alignas(uint32_t) Idmap_header {
+  // Always 0x504D4449 ('IDMP')
+  uint32_t magic;
+
+  uint32_t version;
+
+  uint32_t target_crc32;
+  uint32_t overlay_crc32;
+
+  uint8_t target_path[256];
+  uint8_t overlay_path[256];
+
+  uint16_t target_package_id;
+  uint16_t type_count;
+} __attribute__((packed));
+
+struct alignas(uint32_t) IdmapEntry_header {
+  uint16_t target_type_id;
+  uint16_t overlay_type_id;
+  uint16_t entry_count;
+  uint16_t entry_id_offset;
+  uint32_t entries[0];
+} __attribute__((packed));
+
 class AssetManager2;
 
 /**
diff --git a/libs/androidfw/include/androidfw/ResourceUtils.h b/libs/androidfw/include/androidfw/ResourceUtils.h
index 6bf7c24..c2eae85 100644
--- a/libs/androidfw/include/androidfw/ResourceUtils.h
+++ b/libs/androidfw/include/androidfw/ResourceUtils.h
@@ -40,7 +40,9 @@
   return static_cast<uint8_t>((resid >> 16) & 0x000000ffu);
 }
 
-inline uint16_t get_entry_id(uint32_t resid) { return static_cast<uint16_t>(resid & 0x0000ffffu); }
+inline uint16_t get_entry_id(uint32_t resid) {
+  return static_cast<uint16_t>(resid & 0x0000ffffu);
+}
 
 inline bool is_internal_resid(uint32_t resid) {
   return (resid & 0xffff0000u) != 0 && (resid & 0x00ff0000u) == 0;
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
deleted file mode 100644
index 921fd14..0000000
--- a/libs/androidfw/tests/Android.mk
+++ /dev/null
@@ -1,126 +0,0 @@
-#
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# ==========================================================
-# Setup some common variables for the different build
-# targets here.
-# ==========================================================
-LOCAL_PATH:= $(call my-dir)
-
-testFiles := \
-    ApkAssets_test.cpp \
-    AppAsLib_test.cpp \
-    Asset_test.cpp \
-    AssetManager2_test.cpp \
-    AttributeFinder_test.cpp \
-    AttributeResolution_test.cpp \
-    ByteBucketArray_test.cpp \
-    Config_test.cpp \
-    ConfigLocale_test.cpp \
-    Idmap_test.cpp \
-    LoadedArsc_test.cpp \
-    ResourceUtils_test.cpp \
-    ResTable_test.cpp \
-    Split_test.cpp \
-    StringPiece_test.cpp \
-    TestHelpers.cpp \
-    TestMain.cpp \
-    Theme_test.cpp \
-    TypeWrappers_test.cpp \
-    ZipUtils_test.cpp
-
-benchmarkFiles := \
-    AssetManager2_bench.cpp \
-    BenchMain.cpp \
-    BenchmarkHelpers.cpp \
-    SparseEntry_bench.cpp \
-    TestHelpers.cpp \
-    Theme_bench.cpp
-
-androidfw_test_cflags := \
-    -Wall \
-    -Werror \
-    -Wunused \
-    -Wunreachable-code \
-    -Wno-missing-field-initializers
-
-# gtest is broken.
-androidfw_test_cflags += -Wno-unnamed-type-template-args
-
-# ==========================================================
-# Build the host tests: libandroidfw_tests
-# ==========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libandroidfw_tests
-LOCAL_CFLAGS := $(androidfw_test_cflags)
-LOCAL_SRC_FILES := $(testFiles)
-LOCAL_STATIC_LIBRARIES := \
-    libandroidfw \
-    libbase \
-    libutils \
-    libcutils \
-    liblog \
-    libz \
-    libziparchive
-LOCAL_PICKUP_FILES := $(LOCAL_PATH)/data
-
-include $(BUILD_HOST_NATIVE_TEST)
-
-# ==========================================================
-# Build the device tests: libandroidfw_tests
-# ==========================================================
-ifneq ($(SDK_ONLY),true)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libandroidfw_tests
-LOCAL_CFLAGS := $(androidfw_test_cflags)
-LOCAL_SRC_FILES := $(testFiles) \
-    BackupData_test.cpp \
-    ObbFile_test.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-    libandroidfw \
-    libbase \
-    libcutils \
-    libutils \
-    libui \
-    libziparchive 
-LOCAL_PICKUP_FILES := $(LOCAL_PATH)/data
-
-include $(BUILD_NATIVE_TEST)
-
-# ==========================================================
-# Build the device benchmarks: libandroidfw_benchmarks
-# ==========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libandroidfw_benchmarks
-LOCAL_CFLAGS := $(androidfw_test_cflags)
-LOCAL_SRC_FILES := $(benchmarkFiles)
-LOCAL_STATIC_LIBRARIES := \
-    libgoogle-benchmark
-LOCAL_SHARED_LIBRARIES := \
-    libandroidfw \
-    libbase \
-    libcutils \
-    libutils \
-    libziparchive
-LOCAL_PICKUP_FILES := $(LOCAL_PATH)/data
-
-include $(BUILD_NATIVE_TEST)
-endif # Not SDK_ONLY
-
diff --git a/libs/androidfw/tests/ApkAssets_test.cpp b/libs/androidfw/tests/ApkAssets_test.cpp
index c85b0b9..d65d93f 100644
--- a/libs/androidfw/tests/ApkAssets_test.cpp
+++ b/libs/androidfw/tests/ApkAssets_test.cpp
@@ -17,12 +17,14 @@
 #include "androidfw/ApkAssets.h"
 
 #include "android-base/file.h"
+#include "android-base/test_utils.h"
 #include "android-base/unique_fd.h"
+#include "androidfw/Util.h"
 
 #include "TestHelpers.h"
 #include "data/basic/R.h"
 
-using com::android::basic::R;
+using ::com::android::basic::R;
 
 namespace android {
 
@@ -30,7 +32,13 @@
   std::unique_ptr<const ApkAssets> loaded_apk =
       ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
   ASSERT_NE(nullptr, loaded_apk);
-  EXPECT_NE(nullptr, loaded_apk->GetLoadedArsc());
+
+  const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
+  ASSERT_NE(nullptr, loaded_arsc);
+
+  const LoadedPackage* loaded_package = loaded_arsc->GetPackageForId(0x7f010000);
+  ASSERT_NE(nullptr, loaded_package);
+  EXPECT_TRUE(loaded_package->IsVerified());
 
   std::unique_ptr<Asset> asset = loaded_apk->Open("res/layout/main.xml");
   ASSERT_NE(nullptr, asset);
@@ -54,6 +62,51 @@
   EXPECT_TRUE(loaded_arsc->GetPackages()[0]->IsDynamic());
 }
 
+TEST(ApkAssetsTest, LoadApkWithIdmap) {
+  std::string contents;
+  ResTable target_table;
+  const std::string target_path = GetTestDataPath() + "/basic/basic.apk";
+  ASSERT_TRUE(ReadFileFromZipToString(target_path, "resources.arsc", &contents));
+  ASSERT_EQ(NO_ERROR, target_table.add(contents.data(), contents.size(), 0, true /*copyData*/));
+
+  ResTable overlay_table;
+  const std::string overlay_path = GetTestDataPath() + "/overlay/overlay.apk";
+  ASSERT_TRUE(ReadFileFromZipToString(overlay_path, "resources.arsc", &contents));
+  ASSERT_EQ(NO_ERROR, overlay_table.add(contents.data(), contents.size(), 0, true /*copyData*/));
+
+  util::unique_cptr<void> idmap_data;
+  void* temp_data;
+  size_t idmap_len;
+
+  ASSERT_EQ(NO_ERROR, target_table.createIdmap(overlay_table, 0u, 0u, target_path.c_str(),
+                                               overlay_path.c_str(), &temp_data, &idmap_len));
+  idmap_data.reset(temp_data);
+
+  TemporaryFile tf;
+  ASSERT_TRUE(base::WriteFully(tf.fd, idmap_data.get(), idmap_len));
+  close(tf.fd);
+
+  // Open something so that the destructor of TemporaryFile closes a valid fd.
+  tf.fd = open("/dev/null", O_WRONLY);
+
+  std::unique_ptr<const ApkAssets> loaded_overlay_apk = ApkAssets::LoadOverlay(tf.path);
+  ASSERT_NE(nullptr, loaded_overlay_apk);
+}
+
+TEST(ApkAssetsTest, LoadUnverifiableApk) {
+  std::unique_ptr<const ApkAssets> loaded_apk =
+      ApkAssets::Load(GetTestDataPath() + "/unverified/unverified.apk");
+  ASSERT_NE(nullptr, loaded_apk);
+
+  const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
+  ASSERT_NE(nullptr, loaded_arsc);
+
+  const LoadedPackage* loaded_package = loaded_arsc->GetPackageForId(0x7f010000);
+  ASSERT_NE(nullptr, loaded_package);
+
+  EXPECT_FALSE(loaded_package->IsVerified());
+}
+
 TEST(ApkAssetsTest, CreateAndDestroyAssetKeepsApkAssetsOpen) {
   std::unique_ptr<const ApkAssets> loaded_apk =
       ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
diff --git a/libs/androidfw/tests/AssetManager2_bench.cpp b/libs/androidfw/tests/AssetManager2_bench.cpp
index 67de741..739e733 100644
--- a/libs/androidfw/tests/AssetManager2_bench.cpp
+++ b/libs/androidfw/tests/AssetManager2_bench.cpp
@@ -23,14 +23,15 @@
 #include "androidfw/ResourceTypes.h"
 
 #include "BenchmarkHelpers.h"
-#include "TestHelpers.h"
 #include "data/basic/R.h"
 #include "data/libclient/R.h"
 #include "data/styles/R.h"
+#include "data/unverified/R.h"
 
 namespace app = com::android::app;
 namespace basic = com::android::basic;
 namespace libclient = com::android::libclient;
+namespace unverified = com::android::unverified;
 
 namespace android {
 
@@ -125,6 +126,12 @@
 }
 BENCHMARK(BM_AssetManagerGetResourceOld);
 
+static void BM_AssetManagerGetResourceUnverified(benchmark::State& state) {
+  GetResourceBenchmark({GetTestDataPath() + "/unverified/unverified.apk"}, nullptr /*config*/,
+                       unverified::R::integer::number1, state);
+}
+BENCHMARK(BM_AssetManagerGetResourceUnverified);
+
 static void BM_AssetManagerGetLibraryResource(benchmark::State& state) {
   GetResourceBenchmark(
       {GetTestDataPath() + "/lib_two/lib_two.apk", GetTestDataPath() + "/lib_one/lib_one.apk",
@@ -207,6 +214,30 @@
 }
 BENCHMARK(BM_AssetManagerGetBagOld);
 
+static void BM_AssetManagerGetBagUnverified(benchmark::State& state) {
+  std::unique_ptr<const ApkAssets> apk =
+      ApkAssets::Load(GetTestDataPath() + "/unverified/unverified.apk");
+  if (apk == nullptr) {
+    state.SkipWithError("Failed to load assets");
+    return;
+  }
+
+  AssetManager2 assets;
+  assets.SetApkAssets({apk.get()});
+
+  while (state.KeepRunning()) {
+    const ResolvedBag* bag = assets.GetBag(unverified::R::array::integerArray1);
+    const auto bag_end = end(bag);
+    for (auto iter = begin(bag); iter != bag_end; ++iter) {
+      uint32_t key = iter->key;
+      Res_value value = iter->value;
+      benchmark::DoNotOptimize(key);
+      benchmark::DoNotOptimize(value);
+    }
+  }
+}
+BENCHMARK(BM_AssetManagerGetBagUnverified);
+
 static void BM_AssetManagerGetResourceLocales(benchmark::State& state) {
   std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
   if (apk == nullptr) {
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index fcae53b..ab1a22e 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -28,6 +28,7 @@
 #include "data/libclient/R.h"
 #include "data/styles/R.h"
 #include "data/system/R.h"
+#include "data/unverified/R.h"
 
 namespace app = com::android::app;
 namespace appaslib = com::android::appaslib::app;
@@ -35,6 +36,7 @@
 namespace lib_one = com::android::lib_one;
 namespace lib_two = com::android::lib_two;
 namespace libclient = com::android::libclient;
+namespace unverified = com::android::unverified;
 
 namespace android {
 
@@ -431,4 +433,30 @@
 
 TEST_F(AssetManager2Test, OpensFileFromMultipleApkAssets) {}
 
+TEST_F(AssetManager2Test, OperateOnUnverifiedApkAssets) {
+  std::unique_ptr<const ApkAssets> unverified_assets =
+      ApkAssets::Load(GetTestDataPath() + "/unverified/unverified.apk");
+  ASSERT_NE(nullptr, unverified_assets);
+
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({unverified_assets.get()});
+
+  Res_value value;
+  ResTable_config config;
+  uint32_t flags;
+
+  EXPECT_EQ(kInvalidCookie,
+            assetmanager.GetResource(unverified::R::string::test1, false /*may_be_bag*/, 0u, &value,
+                                     &config, &flags));
+  EXPECT_EQ(kInvalidCookie,
+            assetmanager.GetResource(unverified::R::string::test2, false /*may_be_bag*/, 0u, &value,
+                                     &config, &flags));
+  EXPECT_NE(kInvalidCookie,
+            assetmanager.GetResource(unverified::R::integer::number1, false /*may_be_bag*/, 0u,
+                                     &value, &config, &flags));
+
+  EXPECT_EQ(nullptr, assetmanager.GetBag(unverified::R::style::Theme1));
+  EXPECT_NE(nullptr, assetmanager.GetBag(unverified::R::array::integerArray1));
+}
+
 }  // namespace android
diff --git a/libs/androidfw/tests/BenchMain.cpp b/libs/androidfw/tests/BenchMain.cpp
index 105c5f9..58fc54a 100644
--- a/libs/androidfw/tests/BenchMain.cpp
+++ b/libs/androidfw/tests/BenchMain.cpp
@@ -18,7 +18,7 @@
 
 #include "benchmark/benchmark.h"
 
-#include "TestHelpers.h"
+#include "BenchmarkHelpers.h"
 
 int main(int argc, char** argv) {
   ::benchmark::Initialize(&argc, argv);
diff --git a/libs/androidfw/tests/BenchmarkHelpers.h b/libs/androidfw/tests/BenchmarkHelpers.h
index fc36664..0bb96b5 100644
--- a/libs/androidfw/tests/BenchmarkHelpers.h
+++ b/libs/androidfw/tests/BenchmarkHelpers.h
@@ -14,21 +14,22 @@
  * limitations under the License.
  */
 
-#ifndef TESTS_BENCHMARKHELPERS_H_
-#define TESTS_BENCHMARKHELPERS_H_
+#ifndef ANDROIDFW_TESTS_BENCHMARKHELPERS_H
+#define ANDROIDFW_TESTS_BENCHMARKHELPERS_H
 
 #include <string>
 #include <vector>
 
+#include "androidfw/ResourceTypes.h"
 #include "benchmark/benchmark.h"
 
-#include "androidfw/ResourceTypes.h"
+#include "CommonHelpers.h"
 
 namespace android {
 
 void GetResourceBenchmarkOld(const std::vector<std::string>& paths, const ResTable_config* config,
-                             uint32_t resid, benchmark::State& state);
+                             uint32_t resid, ::benchmark::State& state);
 
 }  // namespace android
 
-#endif /* TESTS_BENCHMARKHELPERS_H_ */
+#endif  // ANDROIDFW_TESTS_BENCHMARKHELPERS_H
diff --git a/libs/androidfw/tests/CommonHelpers.cpp b/libs/androidfw/tests/CommonHelpers.cpp
new file mode 100644
index 0000000..faa5350
--- /dev/null
+++ b/libs/androidfw/tests/CommonHelpers.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CommonHelpers.h"
+
+#include <iostream>
+
+#include "android-base/file.h"
+#include "android-base/logging.h"
+#include "android-base/strings.h"
+
+namespace android {
+
+static std::string sTestDataPath;
+
+void InitializeTest(int* argc, char** argv) {
+  // Set the default test data path to be the executable path directory + data.
+  SetTestDataPath(base::GetExecutableDirectory() + "/tests/data");
+
+  for (int i = 1; i < *argc; i++) {
+    const std::string arg = argv[i];
+    if (base::StartsWith(arg, "--testdata=")) {
+      SetTestDataPath(arg.substr(strlen("--testdata=")));
+      for (int j = i; j != *argc; j++) {
+        argv[j] = argv[j + 1];
+      }
+      --(*argc);
+      --i;
+    } else if (arg == "-h" || arg == "--help") {
+      std::cerr << "\nAdditional options specific to this test:\n"
+                   "  --testdata=[PATH]\n"
+                   "      Specify the location of test data used within the tests.\n";
+      exit(1);
+    }
+  }
+}
+
+void SetTestDataPath(const std::string& path) {
+  sTestDataPath = path;
+}
+
+const std::string& GetTestDataPath() {
+  CHECK(!sTestDataPath.empty()) << "no test data path set.";
+  return sTestDataPath;
+}
+
+std::string GetStringFromPool(const ResStringPool* pool, uint32_t idx) {
+  String8 str = pool->string8ObjectAt(idx);
+  return std::string(str.string(), str.length());
+}
+
+}  // namespace android
diff --git a/libs/androidfw/tests/CommonHelpers.h b/libs/androidfw/tests/CommonHelpers.h
new file mode 100644
index 0000000..c160fbb
--- /dev/null
+++ b/libs/androidfw/tests/CommonHelpers.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROIDFW_TEST_COMMON_HELPERS_H
+#define ANDROIDFW_TEST_COMMON_HELPERS_H
+
+#include <ostream>
+#include <string>
+
+#include "androidfw/ResourceTypes.h"
+#include "utils/String16.h"
+#include "utils/String8.h"
+
+namespace android {
+
+void InitializeTest(int* argc, char** argv);
+
+enum { MAY_NOT_BE_BAG = false };
+
+void SetTestDataPath(const std::string& path);
+
+const std::string& GetTestDataPath();
+
+std::string GetStringFromPool(const ResStringPool* pool, uint32_t idx);
+
+static inline bool operator==(const ResTable_config& a, const ResTable_config& b) {
+  return a.compare(b) == 0;
+}
+
+static inline ::std::ostream& operator<<(::std::ostream& out, const String8& str) {
+  return out << str.string();
+}
+
+static inline ::std::ostream& operator<<(::std::ostream& out, const String16& str) {
+  return out << String8(str).string();
+}
+
+static inline ::std::ostream& operator<<(::std::ostream& out, const ResTable_config& c) {
+  return out << c.toString();
+}
+
+}  // namespace android
+
+#endif  // ANDROIDFW_TEST_COMMON_HELPERS_H
diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp
index d12be18..9eb4a13f3 100644
--- a/libs/androidfw/tests/Idmap_test.cpp
+++ b/libs/androidfw/tests/Idmap_test.cpp
@@ -22,7 +22,7 @@
 #include "TestHelpers.h"
 #include "data/basic/R.h"
 
-using com::android::basic::R;
+using ::com::android::basic::R;
 
 namespace android {
 
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index 756869f..954a54d 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -32,8 +32,7 @@
   ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/styles/styles.apk", "resources.arsc",
                                       &contents));
 
-  std::unique_ptr<const LoadedArsc> loaded_arsc =
-      LoadedArsc::Load(contents.data(), contents.size());
+  std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
   ASSERT_NE(nullptr, loaded_arsc);
 
   const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
@@ -45,12 +44,9 @@
   memset(&config, 0, sizeof(config));
   config.sdkVersion = 24;
 
-  LoadedArscEntry entry;
-  ResTable_config selected_config;
-  uint32_t flags;
+  FindEntryResult entry;
 
-  ASSERT_TRUE(
-      loaded_arsc->FindEntry(app::R::string::string_one, config, &entry, &selected_config, &flags));
+  ASSERT_TRUE(loaded_arsc->FindEntry(app::R::string::string_one, config, &entry));
   ASSERT_NE(nullptr, entry.entry);
 }
 
@@ -59,8 +55,7 @@
   ASSERT_TRUE(
       ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));
 
-  std::unique_ptr<const LoadedArsc> loaded_arsc =
-      LoadedArsc::Load(contents.data(), contents.size());
+  std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
   ASSERT_NE(nullptr, loaded_arsc);
 
   ResTable_config desired_config;
@@ -68,12 +63,8 @@
   desired_config.language[0] = 'd';
   desired_config.language[1] = 'e';
 
-  LoadedArscEntry entry;
-  ResTable_config selected_config;
-  uint32_t flags;
-
-  ASSERT_TRUE(loaded_arsc->FindEntry(basic::R::string::test1, desired_config, &entry,
-                                     &selected_config, &flags));
+  FindEntryResult entry;
+  ASSERT_TRUE(loaded_arsc->FindEntry(basic::R::string::test1, desired_config, &entry));
   ASSERT_NE(nullptr, entry.entry);
 }
 
@@ -82,8 +73,7 @@
   ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/lib_one/lib_one.apk", "resources.arsc",
                                       &contents));
 
-  std::unique_ptr<const LoadedArsc> loaded_arsc =
-      LoadedArsc::Load(contents.data(), contents.size());
+  std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
   ASSERT_NE(nullptr, loaded_arsc);
 
   const auto& packages = loaded_arsc->GetPackages();
@@ -104,8 +94,7 @@
   ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/libclient/libclient.apk",
                                       "resources.arsc", &contents));
 
-  std::unique_ptr<const LoadedArsc> loaded_arsc =
-      LoadedArsc::Load(contents.data(), contents.size());
+  std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
   ASSERT_NE(nullptr, loaded_arsc);
 
   const auto& packages = loaded_arsc->GetPackages();
@@ -132,8 +121,9 @@
   ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/appaslib/appaslib.apk",
                                       "resources.arsc", &contents));
 
-  std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(
-      contents.data(), contents.size(), false /*system*/, true /*load_as_shared_library*/);
+  std::unique_ptr<const LoadedArsc> loaded_arsc =
+      LoadedArsc::Load(StringPiece(contents), nullptr /*loaded_idmap*/, false /*system*/,
+                       true /*load_as_shared_library*/);
   ASSERT_NE(nullptr, loaded_arsc);
 
   const auto& packages = loaded_arsc->GetPackages();
@@ -147,33 +137,68 @@
   std::string contents;
   ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/feature/feature.apk", "resources.arsc",
                                       &contents));
-  std::unique_ptr<const LoadedArsc> loaded_arsc =
-      LoadedArsc::Load(contents.data(), contents.size());
+  std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
   ASSERT_NE(nullptr, loaded_arsc);
 
   ResTable_config desired_config;
   memset(&desired_config, 0, sizeof(desired_config));
 
-  LoadedArscEntry entry;
-  ResTable_config selected_config;
-  uint32_t flags;
-
-  ASSERT_TRUE(loaded_arsc->FindEntry(basic::R::string::test3, desired_config, &entry,
-                                     &selected_config, &flags));
+  FindEntryResult entry;
+  ASSERT_TRUE(loaded_arsc->FindEntry(basic::R::string::test3, desired_config, &entry));
 
   size_t len;
   const char16_t* type_name16 = entry.type_string_ref.string16(&len);
   ASSERT_NE(nullptr, type_name16);
   ASSERT_NE(0u, len);
 
-  size_t utf8_len = utf16_to_utf8_length(type_name16, len);
-  std::string type_name;
-  type_name.resize(utf8_len);
-  utf16_to_utf8(type_name16, len, &*type_name.begin(), utf8_len + 1);
-
+  std::string type_name = util::Utf16ToUtf8(StringPiece16(type_name16, len));
   EXPECT_EQ(std::string("string"), type_name);
 }
 
+class MockLoadedIdmap : public LoadedIdmap {
+ public:
+  MockLoadedIdmap() : LoadedIdmap() {
+    local_header_.magic = kIdmapMagic;
+    local_header_.version = kIdmapCurrentVersion;
+    local_header_.target_package_id = 0x08;
+    local_header_.type_count = 1;
+    header_ = &local_header_;
+
+    entry_header = util::unique_cptr<IdmapEntry_header>(
+        (IdmapEntry_header*)::malloc(sizeof(IdmapEntry_header) + sizeof(uint32_t)));
+    entry_header->target_type_id = 0x03;
+    entry_header->overlay_type_id = 0x02;
+    entry_header->entry_id_offset = 1;
+    entry_header->entry_count = 1;
+    entry_header->entries[0] = 0x00000000u;
+    type_map_[entry_header->overlay_type_id] = entry_header.get();
+  }
+
+ private:
+  Idmap_header local_header_;
+  util::unique_cptr<IdmapEntry_header> entry_header;
+};
+
+TEST(LoadedArscTest, LoadOverlay) {
+  std::string contents, overlay_contents;
+  ASSERT_TRUE(
+      ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));
+  ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlay/overlay.apk", "resources.arsc",
+                                      &overlay_contents));
+
+  MockLoadedIdmap loaded_idmap;
+
+  std::unique_ptr<const LoadedArsc> loaded_arsc =
+      LoadedArsc::Load(StringPiece(overlay_contents), &loaded_idmap);
+  ASSERT_NE(nullptr, loaded_arsc);
+
+  ResTable_config desired_config;
+  memset(&desired_config, 0, sizeof(desired_config));
+
+  FindEntryResult entry;
+  ASSERT_TRUE(loaded_arsc->FindEntry(0x08030001u, desired_config, &entry));
+}
+
 // structs with size fields (like Res_value, ResTable_entry) should be
 // backwards and forwards compatible (aka checking the size field against
 // sizeof(Res_value) might not be backwards compatible.
diff --git a/libs/androidfw/tests/SparseEntry_bench.cpp b/libs/androidfw/tests/SparseEntry_bench.cpp
index 1ebf7ce..d6dc07d 100644
--- a/libs/androidfw/tests/SparseEntry_bench.cpp
+++ b/libs/androidfw/tests/SparseEntry_bench.cpp
@@ -18,7 +18,6 @@
 #include "androidfw/ResourceTypes.h"
 
 #include "BenchmarkHelpers.h"
-#include "TestHelpers.h"
 #include "data/sparse/R.h"
 
 namespace sparse = com::android::sparse;
diff --git a/libs/androidfw/tests/TestHelpers.cpp b/libs/androidfw/tests/TestHelpers.cpp
index 1e763a5..9e320a2 100644
--- a/libs/androidfw/tests/TestHelpers.cpp
+++ b/libs/androidfw/tests/TestHelpers.cpp
@@ -16,67 +16,22 @@
 
 #include "TestHelpers.h"
 
-#include <libgen.h>
-#include <unistd.h>
-
-#include <memory>
-#include <string>
-
-#include "android-base/file.h"
-#include "android-base/logging.h"
-#include "android-base/strings.h"
 #include "ziparchive/zip_archive.h"
 
+using ::testing::AssertionFailure;
+using ::testing::AssertionResult;
+using ::testing::AssertionSuccess;
+
 namespace android {
 
-static std::string sTestDataPath;
-
-// Extract the directory of the current executable path.
-static std::string GetExecutableDir() {
-  const std::string path = base::GetExecutablePath();
-  std::unique_ptr<char, decltype(&std::free)> mutable_path = {strdup(path.c_str()), std::free};
-  std::string executable_dir = dirname(mutable_path.get());
-  return executable_dir;
-}
-
-void InitializeTest(int* argc, char** argv) {
-  // Set the default test data path to be the executable path directory.
-  SetTestDataPath(GetExecutableDir());
-
-  for (int i = 1; i < *argc; i++) {
-    const std::string arg = argv[i];
-    if (base::StartsWith(arg, "--testdata=")) {
-      SetTestDataPath(arg.substr(strlen("--testdata=")));
-      for (int j = i; j != *argc; j++) {
-        argv[j] = argv[j + 1];
-      }
-      --(*argc);
-      --i;
-    } else if (arg == "-h" || arg == "--help") {
-      std::cerr << "\nAdditional options specific to this test:\n"
-                   "  --testdata=[PATH]\n"
-                   "      Specify the location of test data used within the tests.\n";
-      exit(1);
-    }
-  }
-}
-
-void SetTestDataPath(const std::string& path) { sTestDataPath = path; }
-
-const std::string& GetTestDataPath() {
-  CHECK(!sTestDataPath.empty()) << "no test data path set.";
-  return sTestDataPath;
-}
-
-::testing::AssertionResult ReadFileFromZipToString(const std::string& zip_path,
-                                                   const std::string& file,
-                                                   std::string* out_contents) {
+AssertionResult ReadFileFromZipToString(const std::string& zip_path, const std::string& file,
+                                        std::string* out_contents) {
   out_contents->clear();
   ::ZipArchiveHandle handle;
   int32_t result = OpenArchive(zip_path.c_str(), &handle);
   if (result != 0) {
-    return ::testing::AssertionFailure() << "Failed to open zip '" << zip_path
-                                         << "': " << ::ErrorCodeString(result);
+    return AssertionFailure() << "Failed to open zip '" << zip_path
+                              << "': " << ::ErrorCodeString(result);
   }
 
   ::ZipString name(file.c_str());
@@ -84,8 +39,8 @@
   result = ::FindEntry(handle, name, &entry);
   if (result != 0) {
     ::CloseArchive(handle);
-    return ::testing::AssertionFailure() << "Could not find file '" << file << "' in zip '"
-                                         << zip_path << "' : " << ::ErrorCodeString(result);
+    return AssertionFailure() << "Could not find file '" << file << "' in zip '" << zip_path
+                              << "' : " << ::ErrorCodeString(result);
   }
 
   out_contents->resize(entry.uncompressed_length);
@@ -94,41 +49,36 @@
       out_contents->size());
   if (result != 0) {
     ::CloseArchive(handle);
-    return ::testing::AssertionFailure() << "Failed to extract file '" << file << "' from zip '"
-                                         << zip_path << "': " << ::ErrorCodeString(result);
+    return AssertionFailure() << "Failed to extract file '" << file << "' from zip '" << zip_path
+                              << "': " << ::ErrorCodeString(result);
   }
 
   ::CloseArchive(handle);
-  return ::testing::AssertionSuccess();
+  return AssertionSuccess();
 }
 
-::testing::AssertionResult IsStringEqual(const ResTable& table, uint32_t resource_id,
-                                         const char* expected_str) {
+AssertionResult IsStringEqual(const ResTable& table, uint32_t resource_id,
+                              const char* expected_str) {
   Res_value val;
   ssize_t block = table.getResource(resource_id, &val, MAY_NOT_BE_BAG);
   if (block < 0) {
-    return ::testing::AssertionFailure() << "could not find resource";
+    return AssertionFailure() << "could not find resource";
   }
 
   if (val.dataType != Res_value::TYPE_STRING) {
-    return ::testing::AssertionFailure() << "resource is not a string";
+    return AssertionFailure() << "resource is not a string";
   }
 
   const ResStringPool* pool = table.getTableStringBlock(block);
   if (pool == NULL) {
-    return ::testing::AssertionFailure() << "table has no string pool for block " << block;
+    return AssertionFailure() << "table has no string pool for block " << block;
   }
 
   const String8 actual_str = pool->string8ObjectAt(val.data);
   if (String8(expected_str) != actual_str) {
-    return ::testing::AssertionFailure() << actual_str.string();
+    return AssertionFailure() << actual_str.string();
   }
-  return ::testing::AssertionSuccess() << actual_str.string();
-}
-
-std::string GetStringFromPool(const ResStringPool* pool, uint32_t idx) {
-  String8 str = pool->string8ObjectAt(idx);
-  return std::string(str.string(), str.length());
+  return AssertionSuccess() << actual_str.string();
 }
 
 }  // namespace android
diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h
index ec78b2a..43a9955 100644
--- a/libs/androidfw/tests/TestHelpers.h
+++ b/libs/androidfw/tests/TestHelpers.h
@@ -14,53 +14,25 @@
  * limitations under the License.
  */
 
-#ifndef TEST_HELPERS_H_
-#define TEST_HELPERS_H_
+#ifndef ANDROIDFW_TEST_TESTHELPERS_H
+#define ANDROIDFW_TEST_TESTHELPERS_H
 
-#include <ostream>
 #include <string>
-#include <vector>
 
 #include "androidfw/ResourceTypes.h"
 #include "gtest/gtest.h"
-#include "utils/String16.h"
-#include "utils/String8.h"
 
-static inline ::std::ostream& operator<<(::std::ostream& out, const android::String8& str) {
-  return out << str.string();
-}
-
-static inline ::std::ostream& operator<<(::std::ostream& out, const android::String16& str) {
-  return out << android::String8(str).string();
-}
+#include "CommonHelpers.h"
 
 namespace android {
 
-void InitializeTest(int* argc, char** argv);
-
-enum { MAY_NOT_BE_BAG = false };
-
-void SetTestDataPath(const std::string& path);
-
-const std::string& GetTestDataPath();
-
 ::testing::AssertionResult ReadFileFromZipToString(const std::string& zip_path,
                                                    const std::string& file,
                                                    std::string* out_contents);
 
-static inline bool operator==(const ResTable_config& a, const ResTable_config& b) {
-  return a.compare(b) == 0;
-}
-
-static inline ::std::ostream& operator<<(::std::ostream& out, const ResTable_config& c) {
-  return out << c.toString().string();
-}
-
 ::testing::AssertionResult IsStringEqual(const ResTable& table, uint32_t resource_id,
                                          const char* expected_str);
 
-std::string GetStringFromPool(const ResStringPool* pool, uint32_t idx);
-
 }  // namespace android
 
-#endif  // TEST_HELPERS_H_
+#endif  // ANDROIDFW_TEST_TESTHELPERS_H
diff --git a/libs/androidfw/tests/Theme_test.cpp b/libs/androidfw/tests/Theme_test.cpp
index feb454e..55d53ed 100644
--- a/libs/androidfw/tests/Theme_test.cpp
+++ b/libs/androidfw/tests/Theme_test.cpp
@@ -128,6 +128,18 @@
   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
 }
 
+TEST_F(ThemeTest, TryToUseBadResourceId) {
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({style_assets_.get()});
+
+  std::unique_ptr<Theme> theme = assetmanager.NewTheme();
+  ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo));
+
+  Res_value value;
+  uint32_t flags;
+  ASSERT_EQ(kInvalidCookie, theme->GetAttribute(0x7f000001, &value, &flags));
+}
+
 TEST_F(ThemeTest, MultipleThemesOverlaidNotForce) {
   AssetManager2 assetmanager;
   assetmanager.SetApkAssets({style_assets_.get()});
diff --git a/libs/androidfw/tests/data/unverified/R.h b/libs/androidfw/tests/data/unverified/R.h
new file mode 100644
index 0000000..b734b49
--- /dev/null
+++ b/libs/androidfw/tests/data/unverified/R.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TESTS_DATA_UNVERIFIED_R_H_
+#define TESTS_DATA_UNVERIFIED_R_H_
+
+#include <cstdint>
+
+#include "tests/data/basic/R.h"
+
+namespace com {
+namespace android {
+
+namespace unverified = basic;
+
+}  // namespace android
+}  // namespace com
+
+#endif /* TESTS_DATA_UNVERIFIED_R_H_ */
diff --git a/libs/androidfw/tests/data/unverified/unverified.apk b/libs/androidfw/tests/data/unverified/unverified.apk
new file mode 100644
index 0000000..234b390
--- /dev/null
+++ b/libs/androidfw/tests/data/unverified/unverified.apk
Binary files differ
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 124182f..40aecac 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -250,7 +250,19 @@
         // If enabled, every GLES call is wrapped & error checked
         // Has moderate overhead
         "hwui_enable_opengl_validation",
-],
+    ],
+
+    // Build libhwui with PGO by default.
+    // Location of PGO profile data is defined in build/soong/cc/pgo.go
+    // and is separate from hwui.
+    // To turn it off, set ANDROID_PGO_NO_PROFILE_USE environment variable
+    // or set enable_profile_use property to false.
+    pgo: {
+        instrumentation: true,
+        profile_file: "hwui/hwui.profdata",
+        benchmarks: ["hwui"],
+        enable_profile_use: false,
+    },
 }
 
 // ------------------------
diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp
index 1e71cb0..6b8006c 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -31,6 +31,12 @@
 namespace uirenderer {
 
 Extensions::Extensions() {
+    if (Properties::getRenderPipelineType() != RenderPipelineType::OpenGL) {
+        //Extensions class is used only by OpenGL pipeline
+        //The code below will crash for SkiaVulkan, because OpenGL is not initialized
+        //TODO: instantiate Extensions class only for OpenGL pipeline
+        return;
+    }
     const char* version = (const char*) glGetString(GL_VERSION);
 
     // Section 6.1.5 of the OpenGL ES specification indicates the GL version
diff --git a/libs/hwui/ProfileDataContainer.cpp b/libs/hwui/ProfileDataContainer.cpp
index cbf3eb3..70a77ed5 100644
--- a/libs/hwui/ProfileDataContainer.cpp
+++ b/libs/hwui/ProfileDataContainer.cpp
@@ -16,6 +16,8 @@
 
 #include "ProfileDataContainer.h"
 
+#include <errno.h>
+
 #include <log/log.h>
 #include <cutils/ashmem.h>
 
@@ -75,4 +77,4 @@
 }
 
 } /* namespace uirenderer */
-} /* namespace android */
\ No newline at end of file
+} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
index 9982a0cf..75967e9 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
@@ -73,7 +73,7 @@
      * for reading back float buffers (skbug.com/6945).
      */
     if (pixelConfig == kRGBA_half_GrPixelConfig &&
-            !DeviceInfo::get()->extensions().hasFloatTextures()) {
+            !grContext->caps()->isConfigTexturable(kRGBA_half_GrPixelConfig)) {
         ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported");
         return CopyResult::DestinationInvalid;
     }
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index c4bd1e1..cdf4aee 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -75,6 +75,12 @@
     mPinnedImages.clear();
 }
 
+void SkiaPipeline::onPrepareTree() {
+    // The only time mVectorDrawables is not empty is if prepare tree was called 2 times without
+    // a renderFrame in the middle.
+    mVectorDrawables.clear();
+}
+
 void SkiaPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
         LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
         const BakedOpRenderer::LightInfo& lightInfo) {
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 3e6ae30..dc0b8f6d 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -37,6 +37,7 @@
     bool pinImages(std::vector<SkImage*>& mutableImages) override;
     bool pinImages(LsaVector<sk_sp<Bitmap>>& images) override { return false; }
     void unpinImages() override;
+    void onPrepareTree() override;
 
     void renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
             LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 5d7f594..ad684db 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -331,6 +331,7 @@
     info.layerUpdateQueue = &mLayerUpdateQueue;
 
     mAnimationContext->startFrame(info.mode);
+    mRenderPipeline->onPrepareTree();
     for (const sp<RenderNode>& node : mRenderNodes) {
         // Only the primary target node will be drawn full - all other nodes would get drawn in
         // real time mode. In case of a window, the primary node is the window content and the other
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index f9b6e38..0bb3889 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -81,6 +81,7 @@
     virtual bool pinImages(std::vector<SkImage*>& mutableImages) = 0;
     virtual bool pinImages(LsaVector<sk_sp<Bitmap>>& images) = 0;
     virtual void unpinImages() = 0;
+    virtual void onPrepareTree() = 0;
 
     virtual ~IRenderPipeline() {}
 };
diff --git a/libs/hwui/renderthread/OpenGLPipeline.h b/libs/hwui/renderthread/OpenGLPipeline.h
index 4ca19fb..1f467c1 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.h
+++ b/libs/hwui/renderthread/OpenGLPipeline.h
@@ -58,6 +58,7 @@
     bool pinImages(std::vector<SkImage*>& mutableImages) override { return false; }
     bool pinImages(LsaVector<sk_sp<Bitmap>>& images) override;
     void unpinImages() override;
+    void onPrepareTree() override {}
     static void destroyLayer(RenderNode* node);
     static void prepareToDraw(const RenderThread& thread, Bitmap* bitmap);
     static void invokeFunctor(const RenderThread& thread, Functor* functor);
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index afb1193..f7a90b0 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -22,10 +22,11 @@
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 #include <log/log.h>
 
-#include <inttypes.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+#include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 #include <sys/mman.h>
 
@@ -366,4 +367,4 @@
 }
 
 } /* namespace uirenderer */
-} /* namespace android */
\ No newline at end of file
+} /* namespace android */
diff --git a/libs/hwui/tests/common/TestContext.cpp b/libs/hwui/tests/common/TestContext.cpp
index c1ca1e7..1e30d23 100644
--- a/libs/hwui/tests/common/TestContext.cpp
+++ b/libs/hwui/tests/common/TestContext.cpp
@@ -81,10 +81,10 @@
     mSurfaceControl = mSurfaceComposerClient->createSurface(String8("HwuiTest"),
             gDisplay.w, gDisplay.h, PIXEL_FORMAT_RGBX_8888);
 
-    SurfaceComposerClient::openGlobalTransaction();
-    mSurfaceControl->setLayer(0x7FFFFFF);
-    mSurfaceControl->show();
-    SurfaceComposerClient::closeGlobalTransaction();
+    SurfaceComposerClient::Transaction t;
+    t.setLayer(mSurfaceControl, 0x7FFFFFF)
+            .show(mSurfaceControl)
+            .apply();
     mSurface = mSurfaceControl->getSurface();
 }
 
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index b397b15..f430ce6 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -56,6 +56,40 @@
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
 }
 
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, testOnPrepareTree) {
+
+    auto redNode = TestUtils::createSkiaNode(0, 0, 1, 1,
+        [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
+            redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
+        });
+
+    LayerUpdateQueue layerUpdateQueue;
+    SkRect dirty = SkRect::MakeLargest();
+    std::vector<sp<RenderNode>> renderNodes;
+    renderNodes.push_back(redNode);
+    bool opaque = true;
+    android::uirenderer::Rect contentDrawBounds(0, 0, 1, 1);
+    auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
+    {
+        //add a pointer to a deleted vector drawable object in the pipeline
+        sp<VectorDrawableRoot> dirtyVD(new VectorDrawableRoot(new VectorDrawable::Group()));
+        dirtyVD->mutateProperties()->setScaledSize(5,5);
+        pipeline->getVectorDrawables()->push_back(dirtyVD.get());
+    }
+
+    //pipeline should clean list of dirty vector drawables before prepare tree
+    pipeline->onPrepareTree();
+
+    auto surface = SkSurface::MakeRasterN32Premul(1, 1);
+    surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
+
+    //drawFrame will crash if "SkiaPipeline::onPrepareTree" did not clean invalid VD pointer
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes,
+            opaque, false, contentDrawBounds, surface);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
+}
+
 RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckOpaque) {
     auto halfGreenNode = TestUtils::createSkiaNode(0, 0, 2, 2,
         [](RenderProperties& props, SkiaRecordingCanvas& bottomHalfGreenCanvas) {
diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp
index ed31b12..173cd50 100644
--- a/libs/input/SpriteController.cpp
+++ b/libs/input/SpriteController.cpp
@@ -148,8 +148,9 @@
         }
     }
 
-    // Resize sprites if needed, inside a global transaction.
-    bool haveGlobalTransaction = false;
+    // Resize sprites if needed.
+    SurfaceComposerClient::Transaction t;
+    bool needApplyTransaction = false;
     for (size_t i = 0; i < numSprites; i++) {
         SpriteUpdate& update = updates.editItemAt(i);
 
@@ -158,36 +159,24 @@
             int32_t desiredHeight = update.state.icon.bitmap.height();
             if (update.state.surfaceWidth < desiredWidth
                     || update.state.surfaceHeight < desiredHeight) {
-                if (!haveGlobalTransaction) {
-                    SurfaceComposerClient::openGlobalTransaction();
-                    haveGlobalTransaction = true;
-                }
+                needApplyTransaction = true;
 
-                status_t status = update.state.surfaceControl->setSize(desiredWidth, desiredHeight);
-                if (status) {
-                    ALOGE("Error %d resizing sprite surface from %dx%d to %dx%d",
-                            status, update.state.surfaceWidth, update.state.surfaceHeight,
-                            desiredWidth, desiredHeight);
-                } else {
-                    update.state.surfaceWidth = desiredWidth;
-                    update.state.surfaceHeight = desiredHeight;
-                    update.state.surfaceDrawn = false;
-                    update.surfaceChanged = surfaceChanged = true;
+                t.setSize(update.state.surfaceControl,
+                        desiredWidth, desiredHeight);
+                update.state.surfaceWidth = desiredWidth;
+                update.state.surfaceHeight = desiredHeight;
+                update.state.surfaceDrawn = false;
+                update.surfaceChanged = surfaceChanged = true;
 
-                    if (update.state.surfaceVisible) {
-                        status = update.state.surfaceControl->hide();
-                        if (status) {
-                            ALOGE("Error %d hiding sprite surface after resize.", status);
-                        } else {
-                            update.state.surfaceVisible = false;
-                        }
-                    }
+                if (update.state.surfaceVisible) {
+                    t.hide(update.state.surfaceControl);
+                    update.state.surfaceVisible = false;
                 }
             }
         }
     }
-    if (haveGlobalTransaction) {
-        SurfaceComposerClient::closeGlobalTransaction();
+    if (needApplyTransaction) {
+        t.apply();
     }
 
     // Redraw sprites if needed.
@@ -240,8 +229,7 @@
         }
     }
 
-    // Set sprite surface properties and make them visible.
-    bool haveTransaction = false;
+    needApplyTransaction = false;
     for (size_t i = 0; i < numSprites; i++) {
         SpriteUpdate& update = updates.editItemAt(i);
 
@@ -253,75 +241,59 @@
                 || (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA
                         | DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER
                         | DIRTY_VISIBILITY | DIRTY_HOTSPOT))))) {
-            status_t status;
-            if (!haveTransaction) {
-                SurfaceComposerClient::openGlobalTransaction();
-                haveTransaction = true;
-            }
+            needApplyTransaction = true;
 
             if (wantSurfaceVisibleAndDrawn
                     && (becomingVisible || (update.state.dirty & DIRTY_ALPHA))) {
-                status = update.state.surfaceControl->setAlpha(update.state.alpha);
-                if (status) {
-                    ALOGE("Error %d setting sprite surface alpha.", status);
-                }
+                t.setAlpha(update.state.surfaceControl,
+                        update.state.alpha);
             }
 
             if (wantSurfaceVisibleAndDrawn
                     && (becomingVisible || (update.state.dirty & (DIRTY_POSITION
                             | DIRTY_HOTSPOT)))) {
-                status = update.state.surfaceControl->setPosition(
+                t.setPosition(
+                        update.state.surfaceControl,
                         update.state.positionX - update.state.icon.hotSpotX,
                         update.state.positionY - update.state.icon.hotSpotY);
-                if (status) {
-                    ALOGE("Error %d setting sprite surface position.", status);
-                }
             }
 
             if (wantSurfaceVisibleAndDrawn
                     && (becomingVisible
                             || (update.state.dirty & DIRTY_TRANSFORMATION_MATRIX))) {
-                status = update.state.surfaceControl->setMatrix(
+                t.setMatrix(
+                        update.state.surfaceControl,
                         update.state.transformationMatrix.dsdx,
                         update.state.transformationMatrix.dtdx,
                         update.state.transformationMatrix.dsdy,
                         update.state.transformationMatrix.dtdy);
-                if (status) {
-                    ALOGE("Error %d setting sprite surface transformation matrix.", status);
-                }
             }
 
             int32_t surfaceLayer = mOverlayLayer + update.state.layer;
             if (wantSurfaceVisibleAndDrawn
                     && (becomingVisible || (update.state.dirty & DIRTY_LAYER))) {
-                status = update.state.surfaceControl->setLayer(surfaceLayer);
-                if (status) {
-                    ALOGE("Error %d setting sprite surface layer.", status);
-                }
+                t.setLayer(update.state.surfaceControl, surfaceLayer);
             }
 
             if (becomingVisible) {
-                status = update.state.surfaceControl->show();
-                if (status) {
-                    ALOGE("Error %d showing sprite surface.", status);
-                } else {
-                    update.state.surfaceVisible = true;
-                    update.surfaceChanged = surfaceChanged = true;
-                }
+                t.show(update.state.surfaceControl);
+
+                update.state.surfaceVisible = true;
+                update.surfaceChanged = surfaceChanged = true;
             } else if (becomingHidden) {
-                status = update.state.surfaceControl->hide();
-                if (status) {
-                    ALOGE("Error %d hiding sprite surface.", status);
-                } else {
-                    update.state.surfaceVisible = false;
-                    update.surfaceChanged = surfaceChanged = true;
-                }
+                t.hide(update.state.surfaceControl);
+
+                update.state.surfaceVisible = false;
+                update.surfaceChanged = surfaceChanged = true;
             }
         }
     }
 
-    if (haveTransaction) {
-        SurfaceComposerClient::closeGlobalTransaction();
+    if (needApplyTransaction) {
+        status_t status = t.apply();
+        if (status) {
+            ALOGE("Error applying Surface transaction");
+        }
     }
 
     // If any surfaces were changed, write back the new surface properties to the sprites.
diff --git a/libs/protoutil/include/android/util/ProtoOutputStream.h b/libs/protoutil/include/android/util/ProtoOutputStream.h
index 49ec169..0f1cced 100644
--- a/libs/protoutil/include/android/util/ProtoOutputStream.h
+++ b/libs/protoutil/include/android/util/ProtoOutputStream.h
@@ -37,7 +37,7 @@
 class ProtoOutputStream
 {
 public:
-    ProtoOutputStream(int fd);
+    ProtoOutputStream();
     ~ProtoOutputStream();
 
     /**
@@ -60,13 +60,19 @@
     void end(long long token);
 
     /**
-     * Flushes the protobuf data out.
+     * Flushes the protobuf data out to given fd.
      */
-    bool flush();
+    size_t size();
+    EncodedBuffer::iterator data();
+    bool flush(int fd);
+
+    // Please don't use the following functions to dump protos unless you are sure about it.
+    void writeRawVarint(uint64_t varint);
+    void writeLengthDelimitedHeader(uint32_t id, size_t size);
+    void writeRawByte(uint8_t byte);
 
 private:
     EncodedBuffer mBuffer;
-    int mFd;
     size_t mCopyBegin;
     bool mCompact;
     int mDepth;
diff --git a/libs/protoutil/src/ProtoOutputStream.cpp b/libs/protoutil/src/ProtoOutputStream.cpp
index e9ca0dc..15144ac 100644
--- a/libs/protoutil/src/ProtoOutputStream.cpp
+++ b/libs/protoutil/src/ProtoOutputStream.cpp
@@ -70,9 +70,8 @@
 const uint64_t FIELD_COUNT_REPEATED = 2ULL << FIELD_COUNT_SHIFT;
 const uint64_t FIELD_COUNT_PACKED = 4ULL << FIELD_COUNT_SHIFT;
 
-ProtoOutputStream::ProtoOutputStream(int fd)
+ProtoOutputStream::ProtoOutputStream()
         :mBuffer(),
-         mFd(fd),
          mCopyBegin(0),
          mCompact(false),
          mDepth(0),
@@ -483,6 +482,13 @@
     return true;
 }
 
+size_t
+ProtoOutputStream::size()
+{
+    compact();
+    return mBuffer.size();
+}
+
 static bool write_all(int fd, uint8_t const* buf, size_t size)
 {
     while (size > 0) {
@@ -497,19 +503,47 @@
 }
 
 bool
-ProtoOutputStream::flush()
+ProtoOutputStream::flush(int fd)
 {
-    if (mFd < 0) return false;
+    if (fd < 0) return false;
     if (!compact()) return false;
 
     EncodedBuffer::iterator it = mBuffer.begin();
     while (it.readBuffer() != NULL) {
-        if (!write_all(mFd, it.readBuffer(), it.currentToRead())) return false;
+        if (!write_all(fd, it.readBuffer(), it.currentToRead())) return false;
         it.rp()->move(it.currentToRead());
     }
     return true;
 }
 
+EncodedBuffer::iterator
+ProtoOutputStream::data()
+{
+    compact();
+    return mBuffer.begin();
+}
+
+void
+ProtoOutputStream::writeRawVarint(uint64_t varint)
+{
+    mBuffer.writeRawVarint64(varint);
+}
+
+void
+ProtoOutputStream::writeLengthDelimitedHeader(uint32_t id, size_t size)
+{
+    mBuffer.writeHeader(id, WIRE_TYPE_LENGTH_DELIMITED);
+    // reserves 64 bits for length delimited fields, if first field is negative, compact it.
+    mBuffer.writeRawFixed32(size);
+    mBuffer.writeRawFixed32(size);
+}
+
+void
+ProtoOutputStream::writeRawByte(uint8_t byte)
+{
+    mBuffer.writeRawByte(byte);
+}
+
 
 // =========================================================================
 // Private functions
@@ -639,9 +673,7 @@
 ProtoOutputStream::writeUtf8StringImpl(uint32_t id, const char* val, size_t size)
 {
     if (val == NULL || size == 0) return;
-    mBuffer.writeHeader(id, WIRE_TYPE_LENGTH_DELIMITED);
-    mBuffer.writeRawFixed32(size);
-    mBuffer.writeRawFixed32(size);
+    writeLengthDelimitedHeader(id, size);
     for (size_t i=0; i<size; i++) {
         mBuffer.writeRawByte((uint8_t)val[i]);
     }
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index d24a477..412cc291 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -612,6 +612,16 @@
      *
      * <pre>
      *          accumulated delta range = -k * carrier phase    (where k is a constant)</pre>
+     *
+     * <p>Similar to the concept of an RTCM "Phaserange", when the accumulated delta range is
+     * initially chosen, and whenever it is reset, it will retain the integer nature
+     * of the relative carrier phase offset between satellites observed by this receiver, such that
+     * the double difference of this value between receivers and satellites may be used, together
+     * with integer ambiguity resolution, to determine highly precise relative location between
+     * receivers.
+     *
+     * <p>This includes ensuring that all half-cycle ambiguities are resolved before this value is
+     * reported as {@link #ADR_STATE_VALID}.
      */
     public double getAccumulatedDeltaRangeMeters() {
         return mAccumulatedDeltaRangeMeters;
@@ -861,7 +871,7 @@
     }
 
     /**
-     * Gets the Signal-to-Noise ratio (SNR) in dB.
+     * Gets the (post-correlation & integration) Signal-to-Noise ratio (SNR) in dB.
      *
      * <p>The value is only available if {@link #hasSnrInDb()} is {@code true}.
      */
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index e8eaa59..e7f903e 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -813,15 +813,16 @@
     /**
      * Get the estimated vertical accuracy of this location, in meters.
      *
-     * <p>We define vertical accuracy as the radius of 68% confidence. In other
-     * words, if you draw a circle centered at this location's altitude, and with a radius
-     * equal to the vertical accuracy, then there is a 68% probability that the true altitude is
-     * inside the circle.
+     * <p>We define vertical accuracy at 68% confidence.  Specifically, as 1-side of the
+     * 2-sided range above and below the estimated altitude reported by {@link #getAltitude()},
+     * within which there is a 68% probability of finding the true altitude.
      *
-     * <p>In statistical terms, it is assumed that location errors
-     * are random with a normal distribution, so the 68% confidence circle
-     * represents one standard deviation. Note that in practice, location
-     * errors do not always follow such a simple distribution.
+     * <p>In the case where the underlying distribution is assumed Gaussian normal, this would be
+     * considered 1 standard deviation.
+     *
+     * <p>For example, if {@link #getAltitude()} returns 150, and
+     * {@link #getVerticalAccuracyMeters()} ()} returns 20 then there is a 68% probability
+     * of the true altitude being between 130 and 170 meters.
      *
      * <p>If this location does not have a vertical accuracy, then 0.0 is returned.
      */
@@ -866,14 +867,16 @@
     /**
      * Get the estimated speed accuracy of this location, in meters per second.
      *
-     * <p>We define speed accuracy as a 1-standard-deviation value, i.e. as 1-side of the
-     * 2-sided range above and below the estimated
-     * speed reported by {@link #getSpeed()}, within which there is a 68% probability of
-     * finding the true speed.
+     * <p>We define speed accuracy at 68% confidence.  Specifically, as 1-side of the
+     * 2-sided range above and below the estimated speed reported by {@link #getSpeed()},
+     * within which there is a 68% probability of finding the true speed.
      *
-     * <p>For example, if {@link #getSpeed()} returns 5.0, and
-     * {@link #getSpeedAccuracyMetersPerSecond()} returns 1.0, then there is a 68% probably of the
-     * true speed being between 4.0 and 6.0 meters per second.
+     * <p>In the case where the underlying
+     * distribution is assumed Gaussian normal, this would be considered 1 standard deviation.
+     *
+     * <p>For example, if {@link #getSpeed()} returns 5, and
+     * {@link #getSpeedAccuracyMetersPerSecond()} returns 1, then there is a 68% probability of
+     * the true speed being between 4 and 6 meters per second.
      *
      * <p>Note that the speed and speed accuracy is often better than would be obtained simply from
      * differencing sequential positions, such as when the Doppler measurements from GNSS satellites
@@ -922,13 +925,16 @@
     /**
      * Get the estimated bearing accuracy of this location, in degrees.
      *
-     * <p>We define bearing accuracy as a 1-standard-deviation value, i.e. as 1-side of the
+     * <p>We define bearing accuracy at 68% confidence.  Specifically, as 1-side of the
      * 2-sided range on each side of the estimated bearing reported by {@link #getBearing()},
      * within which there is a 68% probability of finding the true bearing.
      *
-     * <p>For example, if {@link #getBearing()} returns 60., and
-     * {@link #getBearingAccuracyDegrees()} ()} returns 10., then there is a 68% probably of the
-     * true bearing being between 50. and 70. degrees.
+     * <p>In the case where the underlying distribution is assumed Gaussian normal, this would be
+     * considered 1 standard deviation.
+     *
+     * <p>For example, if {@link #getBearing()} returns 60, and
+     * {@link #getBearingAccuracyDegrees()} ()} returns 10, then there is a 68% probability of the
+     * true bearing being between 50 and 70 degrees.
      *
      * <p>If this location does not have a bearing accuracy, then 0.0 is returned.
      */
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 26ead3d..20405d3 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -202,6 +202,22 @@
      * @see #SUPPRESSIBLE_USAGES
      */
     public final static int SUPPRESSIBLE_NEVER = 3;
+    /**
+     * @hide
+     * Denotes a usage for alarms,
+     * will be muted when the Zen mode doesn't allow alarms
+     * @see #SUPPRESSIBLE_USAGES
+     */
+    public final static int SUPPRESSIBLE_ALARM = 4;
+    /**
+     * @hide
+     * Denotes a usage for all other sounds not caught in SUPPRESSIBLE_NOTIFICATION,
+     * SUPPRESSIBLE_CALL,SUPPRESSIBLE_NEVER or SUPPRESSIBLE_ALARM.
+     * This includes media, system, game, navigation, the assistant, and more.
+     * These will be muted when the Zen mode doesn't allow media/system/other.
+     * @see #SUPPRESSIBLE_USAGES
+     */
+    public final static int SUPPRESSIBLE_MEDIA_SYSTEM_OTHER = 5;
 
     /**
      * @hide
@@ -221,6 +237,13 @@
         SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_EVENT,                SUPPRESSIBLE_NOTIFICATION);
         SUPPRESSIBLE_USAGES.put(USAGE_ASSISTANCE_ACCESSIBILITY,          SUPPRESSIBLE_NEVER);
         SUPPRESSIBLE_USAGES.put(USAGE_VOICE_COMMUNICATION,               SUPPRESSIBLE_NEVER);
+        SUPPRESSIBLE_USAGES.put(USAGE_ALARM,                             SUPPRESSIBLE_ALARM);
+        SUPPRESSIBLE_USAGES.put(USAGE_MEDIA,                             SUPPRESSIBLE_MEDIA_SYSTEM_OTHER);
+        SUPPRESSIBLE_USAGES.put(USAGE_ASSISTANCE_SONIFICATION,           SUPPRESSIBLE_MEDIA_SYSTEM_OTHER);
+        SUPPRESSIBLE_USAGES.put(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,    SUPPRESSIBLE_MEDIA_SYSTEM_OTHER);
+        SUPPRESSIBLE_USAGES.put(USAGE_GAME,                              SUPPRESSIBLE_MEDIA_SYSTEM_OTHER);
+        SUPPRESSIBLE_USAGES.put(USAGE_VOICE_COMMUNICATION_SIGNALLING,    SUPPRESSIBLE_MEDIA_SYSTEM_OTHER);
+        SUPPRESSIBLE_USAGES.put(USAGE_ASSISTANT,                         SUPPRESSIBLE_MEDIA_SYSTEM_OTHER);
     }
 
     /**
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 4ea4e381..760cc49 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -395,7 +395,7 @@
      * @see #getFrameAtTime(long, int)
      */
     /* Do not change these option values without updating their counterparts
-     * in include/media/stagefright/MediaSource.h!
+     * in include/media/MediaSource.h!
      */
     /**
      * This option is used with {@link #getFrameAtTime(long, int)} to retrieve
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 7787d4b..62757e2 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -39,6 +39,7 @@
 import android.os.SystemProperties;
 import android.provider.Settings;
 import android.system.ErrnoException;
+import android.system.Os;
 import android.system.OsConstants;
 import android.util.Log;
 import android.util.Pair;
@@ -60,7 +61,6 @@
 import com.android.internal.util.Preconditions;
 
 import libcore.io.IoBridge;
-import libcore.io.Libcore;
 import libcore.io.Streams;
 
 import java.io.ByteArrayOutputStream;
@@ -2843,7 +2843,7 @@
 
         final FileDescriptor dupedFd;
         try {
-            dupedFd = Libcore.os.dup(fd);
+            dupedFd = Os.dup(fd);
         } catch (ErrnoException ex) {
             Log.e(TAG, ex.getMessage(), ex);
             throw new RuntimeException(ex);
@@ -2881,7 +2881,7 @@
             private int addTrack() {
                 final ByteArrayOutputStream bos = new ByteArrayOutputStream();
                 try {
-                    Libcore.os.lseek(dupedFd, offset2, OsConstants.SEEK_SET);
+                    Os.lseek(dupedFd, offset2, OsConstants.SEEK_SET);
                     byte[] buffer = new byte[4096];
                     for (long total = 0; total < length2;) {
                         int bytesToRead = (int) Math.min(buffer.length, length2 - total);
@@ -2905,7 +2905,7 @@
                     return MEDIA_INFO_TIMED_TEXT_ERROR;
                 } finally {
                     try {
-                        Libcore.os.close(dupedFd);
+                        Os.close(dupedFd);
                     } catch (ErrnoException e) {
                         Log.e(TAG, e.getMessage(), e);
                     }
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 59a124f..7678490 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -917,7 +917,7 @@
      */
     public void setNextOutputFile(File file) throws IOException
     {
-        RandomAccessFile f = new RandomAccessFile(file, "rws");
+        RandomAccessFile f = new RandomAccessFile(file, "rw");
         try {
             _setNextOutputFile(f.getFD());
         } finally {
@@ -942,7 +942,7 @@
     public void prepare() throws IllegalStateException, IOException
     {
         if (mPath != null) {
-            RandomAccessFile file = new RandomAccessFile(mPath, "rws");
+            RandomAccessFile file = new RandomAccessFile(mPath, "rw");
             try {
                 _setOutputFile(file.getFD());
             } finally {
@@ -951,7 +951,7 @@
         } else if (mFd != null) {
             _setOutputFile(mFd);
         } else if (mFile != null) {
-            RandomAccessFile file = new RandomAccessFile(mFile, "rws");
+            RandomAccessFile file = new RandomAccessFile(mFile, "rw");
             try {
                 _setOutputFile(file.getFD());
             } finally {
diff --git a/media/java/android/media/midi/package.html b/media/java/android/media/midi/package.html
index 8c1010d..33c5490 100644
--- a/media/java/android/media/midi/package.html
+++ b/media/java/android/media/midi/package.html
@@ -138,9 +138,10 @@
 </pre>
 
 
-<p>Note that &ldquo;input&rdquo; and &ldquo;output&rdquo; are from the standpoint of the device. So a
-synthesizer will have an &ldquo;input&rdquo; port that receives messages. A keyboard will
-have an &ldquo;output&rdquo; port that sends messages.</p>
+<p>Note that &ldquo;input&rdquo; and &ldquo;output&rdquo; directions reflect the point of view
+of the MIDI device itself, not your app.
+For example, to send MIDI notes to a synthesizer, open the synth's INPUT port.
+To receive notes from a keyboard, open the keyboard's OUTPUT port.</p>
 
 <p>The MidiDeviceInfo has a bundle of properties.</p>
 
@@ -359,8 +360,10 @@
 <p>MIDI devices can be connected to Android using Bluetooth LE.</p>
 
 <p>Before using the device, the app must scan for available BTLE devices and then allow
-the user to connect. An example program
-will be provided so look for it on the Android developer website.</p>
+the user to connect.
+See the Android developer website for an
+<a href="https://source.android.com/devices/audio/midi_test#apps" target="_blank">example
+program</a>.</p>
 
 <h2 id=btle_location_permissions>Request Location Permission for BTLE</h2>
 
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 17b2326..aaf18e7 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -471,10 +471,14 @@
                     if (parent == 0xFFFFFFFF) {
                         // all objects in root of store
                         parent = 0;
+                        where = STORAGE_PARENT_WHERE;
+                        whereArgs = new String[]{Integer.toString(storageID),
+                                Integer.toString(parent)};
+                    }  else {
+                        // If a parent is specified, the storage is redundant
+                        where = PARENT_WHERE;
+                        whereArgs = new String[]{Integer.toString(parent)};
                     }
-                    where = STORAGE_PARENT_WHERE;
-                    whereArgs = new String[] { Integer.toString(storageID),
-                                               Integer.toString(parent) };
                 }
             } else {
                 // query specific format
@@ -487,11 +491,16 @@
                     if (parent == 0xFFFFFFFF) {
                         // all objects in root of store
                         parent = 0;
+                        where = STORAGE_FORMAT_PARENT_WHERE;
+                        whereArgs = new String[]{Integer.toString(storageID),
+                                Integer.toString(format),
+                                Integer.toString(parent)};
+                    } else {
+                        // If a parent is specified, the storage is redundant
+                        where = FORMAT_PARENT_WHERE;
+                        whereArgs = new String[]{Integer.toString(format),
+                                Integer.toString(parent)};
                     }
-                    where = STORAGE_FORMAT_PARENT_WHERE;
-                    whereArgs = new String[] { Integer.toString(storageID),
-                                               Integer.toString(format),
-                                               Integer.toString(parent) };
                 }
             }
         }
@@ -845,7 +854,7 @@
         return MtpConstants.RESPONSE_OK;
     }
 
-    private int moveObject(int handle, int newParent, String newPath) {
+    private int moveObject(int handle, int newParent, int newStorage, String newPath) {
         String[] whereArgs = new String[] {  Integer.toString(handle) };
 
         // do not allow renaming any of the special subdirectories
@@ -857,6 +866,7 @@
         ContentValues values = new ContentValues();
         values.put(Files.FileColumns.DATA, newPath);
         values.put(Files.FileColumns.PARENT, newParent);
+        values.put(Files.FileColumns.STORAGE_ID, newStorage);
         int updated = 0;
         try {
             // note - we are relying on a special case in MediaProvider.update() to update
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index d2fa8f5..5c90d00 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -37,7 +37,8 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSource.h>
+#include <media/DataSource.h>
+#include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/NuMediaExtractor.h>
@@ -744,7 +745,7 @@
     }
 
     sp<DataSource> bridge =
-        DataSource::CreateFromIDataSource(new JMediaDataSource(env, callbackObj));
+        CreateDataSourceFromIDataSource(new JMediaDataSource(env, callbackObj));
     status_t err = extractor->setDataSource(bridge);
 
     if (err != OK) {
diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h
index 94d36f25..a4638ac 100644
--- a/media/jni/android_media_MediaExtractor.h
+++ b/media/jni/android_media_MediaExtractor.h
@@ -18,8 +18,8 @@
 #define _ANDROID_MEDIA_MEDIAEXTRACTOR_H_
 
 #include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/DataSource.h>
+#include <media/MediaSource.h>
+#include <media/DataSource.h>
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 7225f10..0da6289 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -180,7 +180,7 @@
     virtual MtpProperty*            getDevicePropertyDesc(MtpDeviceProperty property);
 
     virtual MtpResponseCode         moveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
-                                            MtpString& newPath);
+                                            MtpStorageID newStorage, MtpString& newPath);
 
     virtual void                    sessionStarted();
 
@@ -1000,11 +1000,11 @@
 }
 
 MtpResponseCode MyMtpDatabase::moveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
-        MtpString &newPath) {
+        MtpStorageID newStorage, MtpString &newPath) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     jstring stringValue = env->NewStringUTF((const char *) newPath);
     MtpResponseCode result = env->CallIntMethod(mDatabase, method_moveObject,
-                (jint)handle, (jint)newParent, stringValue);
+                (jint)handle, (jint)newParent, (jint) newStorage, stringValue);
 
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
     env->DeleteLocalRef(stringValue);
@@ -1376,7 +1376,7 @@
         ALOGE("Can't find deleteFile");
         return -1;
     }
-    method_moveObject = env->GetMethodID(clazz, "moveObject", "(IILjava/lang/String;)I");
+    method_moveObject = env->GetMethodID(clazz, "moveObject", "(IIILjava/lang/String;)I");
     if (method_moveObject == NULL) {
         ALOGE("Can't find moveObject");
         return -1;
diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp
index e9e9309..6ce104d 100644
--- a/media/jni/android_mtp_MtpServer.cpp
+++ b/media/jni/android_mtp_MtpServer.cpp
@@ -72,7 +72,7 @@
     const char *deviceInfoDeviceVersionStr = env->GetStringUTFChars(deviceInfoDeviceVersion, NULL);
     const char *deviceInfoSerialNumberStr = env->GetStringUTFChars(deviceInfoSerialNumber, NULL);
     MtpServer* server = new MtpServer(getMtpDatabase(env, javaDatabase),
-            usePtp, AID_MEDIA_RW, 0664, 0775,
+            usePtp,
             MtpString((deviceInfoManufacturerStr != NULL) ? deviceInfoManufacturerStr : ""),
             MtpString((deviceInfoModelStr != NULL) ? deviceInfoModelStr : ""),
             MtpString((deviceInfoDeviceVersionStr != NULL) ? deviceInfoDeviceVersionStr : ""),
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 5f1cf16..ab0da07 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -26,7 +26,6 @@
 #include <media/AudioTrack.h>
 #include <media/IMediaHTTPService.h>
 #include <media/mediaplayer.h>
-#include <media/stagefright/MediaExtractor.h>
 #include "SoundPool.h"
 #include "SoundPoolThread.h"
 #include <media/AudioPolicyHelper.h>
diff --git a/packages/CtsShim/Android.mk b/packages/CtsShim/Android.mk
index fa6423e..88b85e0 100644
--- a/packages/CtsShim/Android.mk
+++ b/packages/CtsShim/Android.mk
@@ -30,8 +30,11 @@
 # Make sure the build system doesn't try to resign the APK
 LOCAL_CERTIFICATE := PRESIGNED
 LOCAL_DEX_PREOPT := false
+LOCAL_MODULE_TARGET_ARCH := arm arm64 x86 x86_64
 
-LOCAL_SRC_FILES := CtsShimPriv.apk
+my_archs := arm x86
+my_src_arch := $(call get-prebuilt-src-arch, $(my_archs))
+LOCAL_SRC_FILES := apk/$(my_src_arch)/CtsShimPriv.apk
 
 include $(BUILD_PREBUILT)
 
@@ -48,8 +51,11 @@
 # Make sure the build system doesn't try to resign the APK
 LOCAL_CERTIFICATE := PRESIGNED
 LOCAL_DEX_PREOPT := false
+LOCAL_MODULE_TARGET_ARCH := arm arm64 x86 x86_64
 
-LOCAL_SRC_FILES := CtsShim.apk
+my_archs := arm x86
+my_src_arch := $(call get-prebuilt-src-arch, $(my_archs))
+LOCAL_SRC_FILES := apk/$(my_src_arch)/CtsShim.apk
 
 include $(BUILD_PREBUILT)
 
diff --git a/packages/CtsShim/CtsShim.apk b/packages/CtsShim/CtsShim.apk
deleted file mode 100644
index 2728903..0000000
--- a/packages/CtsShim/CtsShim.apk
+++ /dev/null
Binary files differ
diff --git a/packages/CtsShim/CtsShimPriv.apk b/packages/CtsShim/CtsShimPriv.apk
deleted file mode 100644
index 9a8e75c..0000000
--- a/packages/CtsShim/CtsShimPriv.apk
+++ /dev/null
Binary files differ
diff --git a/packages/CtsShim/apk/arm/CtsShim.apk b/packages/CtsShim/apk/arm/CtsShim.apk
new file mode 100644
index 0000000..a911603
--- /dev/null
+++ b/packages/CtsShim/apk/arm/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/arm/CtsShimPriv.apk b/packages/CtsShim/apk/arm/CtsShimPriv.apk
new file mode 100644
index 0000000..845d781
--- /dev/null
+++ b/packages/CtsShim/apk/arm/CtsShimPriv.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShim.apk b/packages/CtsShim/apk/x86/CtsShim.apk
new file mode 100644
index 0000000..a911603
--- /dev/null
+++ b/packages/CtsShim/apk/x86/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShimPriv.apk b/packages/CtsShim/apk/x86/CtsShimPriv.apk
new file mode 100644
index 0000000..2fc9a94
--- /dev/null
+++ b/packages/CtsShim/apk/x86/CtsShimPriv.apk
Binary files differ
diff --git a/packages/CtsShim/build/Android.mk b/packages/CtsShim/build/Android.mk
index 21f0afe..ec14d50 100644
--- a/packages/CtsShim/build/Android.mk
+++ b/packages/CtsShim/build/Android.mk
@@ -32,6 +32,9 @@
 
 LOCAL_MANIFEST_FILE := shim_priv_upgrade/AndroidManifest.xml
 
+LOCAL_MULTILIB := both
+LOCAL_JNI_SHARED_LIBRARIES := libshim_jni
+
 include $(BUILD_PACKAGE)
 my_shim_priv_upgrade_apk := $(LOCAL_BUILT_MODULE)
 
@@ -60,6 +63,9 @@
 
 LOCAL_FULL_MANIFEST_FILE := $(gen)
 
+LOCAL_MULTILIB := both
+LOCAL_JNI_SHARED_LIBRARIES := libshim_jni
+
 include $(BUILD_PACKAGE)
 
 ###########################################################
@@ -80,6 +86,9 @@
 
 LOCAL_MANIFEST_FILE := shim_priv_upgrade/AndroidManifest.xml
 
+LOCAL_MULTILIB := both
+LOCAL_JNI_SHARED_LIBRARIES := libshim_jni
+
 include $(BUILD_PACKAGE)
 
 
@@ -99,3 +108,5 @@
 
 include $(BUILD_PACKAGE)
 
+###########################################################
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/CtsShim/build/README b/packages/CtsShim/build/README
index 9869377..59af068 100644
--- a/packages/CtsShim/build/README
+++ b/packages/CtsShim/build/README
@@ -6,19 +6,34 @@
 NOTE: The need to include a binary on the system image may be deprecated if a
 solution involving a temporarily writable /system partition is implemented.
 
-build:
-    $ tapas CtsShim CtsShimPriv CtsShimPrivUpgrade CtsShimPrivUpgradeWrongSHA
+For local testing, build the apk and put them in the following folders.
+This is for arm:
+    $ tapas CtsShim CtsShimPriv CtsShimPrivUpgrade CtsShimPrivUpgradeWrongSHA arm64
     $ m
-
-local testing:
     $ cp $OUT/system/priv-app/CtsShimPrivUpgrade/CtsShimPrivUpgrade.apk \
-        cts/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp
+        cts/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm
+    $ cp $OUT/system/priv-app/CtsShimPrivUpgrade/CtsShimPrivUpgrade.apk \
+        vendor/xts/gts-tests/hostsidetests/packagemanager/app/apk/arm/GtsShimPrivUpgrade.apk
     $ cp $OUT/system/priv-app/CtsShimPrivUpgradeWrongSHA/CtsShimPrivUpgradeWrongSHA.apk \
-        cts/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp
+        cts/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm
     $ cp $OUT/system/priv-app/CtsShimPriv/CtsShimPriv.apk \
-        frameworks/base/packages/CtsShim
+        frameworks/base/packages/CtsShim/apk/arm
     $ cp $OUT/system/app/CtsShim/CtsShim.apk \
-        frameworks/base/packages/CtsShim
+        frameworks/base/packages/CtsShim/apk/arm
+
+This is for x86:
+    $ tapas CtsShim CtsShimPriv CtsShimPrivUpgrade CtsShimPrivUpgradeWrongSHA x86_64
+    $ m
+    $ cp $OUT/system/priv-app/CtsShimPrivUpgrade/CtsShimPrivUpgrade.apk \
+        cts/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86
+    $ cp $OUT/system/priv-app/CtsShimPrivUpgrade/CtsShimPrivUpgrade.apk \
+        vendor/xts/gts-tests/hostsidetests/packagemanager/app/apk/x86/GtsShimPrivUpgrade.apk
+    $ cp $OUT/system/priv-app/CtsShimPrivUpgradeWrongSHA/CtsShimPrivUpgradeWrongSHA.apk \
+        cts/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86
+    $ cp $OUT/system/priv-app/CtsShimPriv/CtsShimPriv.apk \
+        frameworks/base/packages/CtsShim/apk/x86
+    $ cp $OUT/system/app/CtsShim/CtsShim.apk \
+        frameworks/base/packages/CtsShim/apk/x86
 
 For final submission, the APKs should be downloaded from the build server, then
 submitted to the cts/ and frameworks/base/ repos.
diff --git a/packages/CtsShim/build/jni/Android.mk b/packages/CtsShim/build/jni/Android.mk
new file mode 100644
index 0000000..968fc0b
--- /dev/null
+++ b/packages/CtsShim/build/jni/Android.mk
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libshim_jni
+
+LOCAL_SRC_FILES := Shim.c
+
+LOCAL_SDK_VERSION := 24
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/packages/CtsShim/build/jni/Shim.c b/packages/CtsShim/build/jni/Shim.c
new file mode 100644
index 0000000..44eb316
--- /dev/null
+++ b/packages/CtsShim/build/jni/Shim.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <jni.h>
\ No newline at end of file
diff --git a/packages/CtsShim/build/shim_priv/AndroidManifest.xml b/packages/CtsShim/build/shim_priv/AndroidManifest.xml
index 5195ef7..9bf454c 100644
--- a/packages/CtsShim/build/shim_priv/AndroidManifest.xml
+++ b/packages/CtsShim/build/shim_priv/AndroidManifest.xml
@@ -27,6 +27,7 @@
 
     <application
         android:hasCode="false"
+        android:multiArch="true"
         tools:ignore="AllowBackup,MissingApplicationIcon" >
 
         <!-- These activities don't actually exist; define them just to test the filters !-->
diff --git a/packages/CtsShim/build/shim_priv_upgrade/AndroidManifest.xml b/packages/CtsShim/build/shim_priv_upgrade/AndroidManifest.xml
index b938e3e..023e93e 100644
--- a/packages/CtsShim/build/shim_priv_upgrade/AndroidManifest.xml
+++ b/packages/CtsShim/build/shim_priv_upgrade/AndroidManifest.xml
@@ -24,6 +24,7 @@
 
     <application
         android:hasCode="false"
+        android:multiArch="true"
         tools:ignore="AllowBackup,MissingApplicationIcon" >
 
         <!-- These activities don't actually exist; define them just to test the filters !-->
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 3d083b1..a404759 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -525,6 +525,12 @@
     <!-- [CHAR LIMIT=NONE] Label for displaying Bluetooth Audio Codec Parameters while streaming -->
     <string name="bluetooth_select_a2dp_codec_streaming_label">Streaming: <xliff:g id="streaming_parameter">%1$s</xliff:g></string>
 
+    <!-- Title of the developer option for DNS over TLS. -->
+    <string name="dns_tls">DNS over TLS</string>
+    <!-- Summary to explain the developer option for DNS over TLS.  This allows the user to
+    request that the system attempt TLS with all DNS servers, or none. -->
+    <string name="dns_tls_summary">If enabled, attempt DNS over TLS on port 853.</string>
+
     <!-- setting Checkbox summary whether to show options for wireless display certification  -->
     <string name="wifi_display_certification_summary">Show options for wireless display certification</string>
     <!-- Setting Checkbox summary whether to enable Wifi verbose Logging [CHAR LIMIT=80] -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java b/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java
index 253ca11..90124f1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.os.Bundle;
+import android.support.annotation.CallSuper;
 import android.support.v14.preference.EditTextPreferenceDialogFragment;
 import android.support.v7.preference.EditTextPreference;
 import android.util.AttributeSet;
@@ -30,7 +31,8 @@
 
     private CustomPreferenceDialogFragment mFragment;
 
-    public CustomEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public CustomEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
     }
 
@@ -69,7 +71,12 @@
     protected void onClick(DialogInterface dialog, int which) {
     }
 
+    @CallSuper
     protected void onBindDialogView(View view) {
+        final EditText editText = view.findViewById(android.R.id.edit);
+        if (editText != null) {
+            editText.requestFocus();
+        }
     }
 
     private void setFragment(CustomPreferenceDialogFragment fragment) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 28105e2..f57d02b 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -107,14 +107,16 @@
         addHandler(Intent.ACTION_DOCK_EVENT, new DockEventHandler());
 
         mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter, null, mReceiverHandler);
+        mContext.registerReceiver(mProfileBroadcastReceiver, mProfileIntentFilter, null, mReceiverHandler);
     }
 
     void registerProfileIntentReceiver() {
-        mContext.registerReceiver(mBroadcastReceiver, mProfileIntentFilter, null, mReceiverHandler);
+        mContext.registerReceiver(mProfileBroadcastReceiver, mProfileIntentFilter, null, mReceiverHandler);
     }
 
     public void setReceiverHandler(android.os.Handler handler) {
         mContext.unregisterReceiver(mBroadcastReceiver);
+        mContext.unregisterReceiver(mProfileBroadcastReceiver);
         mReceiverHandler = handler;
         mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter, null, mReceiverHandler);
         registerProfileIntentReceiver();
@@ -148,11 +150,31 @@
         }
     };
 
+    private final BroadcastReceiver mProfileBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            BluetoothDevice device = intent
+                    .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+
+            Handler handler = mHandlerMap.get(action);
+            if (handler != null) {
+                handler.onReceive(context, intent, device);
+            }
+        }
+    };
+
     private class AdapterStateChangedHandler implements Handler {
         public void onReceive(Context context, Intent intent,
                 BluetoothDevice device) {
             int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
                                     BluetoothAdapter.ERROR);
+            // Reregister Profile Broadcast Receiver as part of TURN OFF
+            if (state == BluetoothAdapter.STATE_OFF)
+            {
+                context.unregisterReceiver(mProfileBroadcastReceiver);
+                registerProfileIntentReceiver();
+            }
             // update local profiles and get paired devices
             mLocalAdapter.setBluetoothStateInt(state);
             // send callback to update UI and possibly start scanning
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS
new file mode 100644
index 0000000..71621213
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS
@@ -0,0 +1,8 @@
+# Default reviewers for this and subdirectories.
+asapperstein@google.com
+asargent@google.com
+eisenbach@google.com
+jackqdyulei@google.com
+siyuanh@google.com
+
+# Emergency approvers in case the above are not available
\ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/development/AbstractLogpersistPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/development/AbstractLogpersistPreferenceController.java
index 67553adc..77b2d86 100644
--- a/packages/SettingsLib/src/com/android/settingslib/development/AbstractLogpersistPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/development/AbstractLogpersistPreferenceController.java
@@ -68,7 +68,7 @@
 
     public AbstractLogpersistPreferenceController(Context context, Lifecycle lifecycle) {
         super(context);
-        if (isAvailable()) {
+        if (isAvailable() && lifecycle != null) {
             lifecycle.addObserver(this);
         }
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS b/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS
new file mode 100644
index 0000000..d5d2e9e
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS
@@ -0,0 +1,7 @@
+# Default reviewers for this and subdirectories.
+asapperstein@google.com
+asargent@google.com
+dling@google.com
+zhfan@google.com
+
+# Emergency approvers in case the above are not available
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/android/net/wifi/WifiNetworkScoreCache.java b/packages/SettingsLib/tests/robotests/src/android/net/wifi/WifiNetworkScoreCache.java
deleted file mode 100644
index abccd8d..0000000
--- a/packages/SettingsLib/tests/robotests/src/android/net/wifi/WifiNetworkScoreCache.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2017 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-import android.content.Context;
-import android.os.Handler;
-
-import java.util.List;
-
-/**
- * Will be removed once robolectric is updated to O
- */
-public class WifiNetworkScoreCache {
-
-    public WifiNetworkScoreCache(Context context, WifiNetworkScoreCache.CacheListener listener) {
-    }
-
-    public abstract static class CacheListener {
-        public CacheListener(Handler handler) {
-        }
-
-        void post(List updatedNetworks) {
-        }
-
-        public abstract void networkCacheUpdated(List updatedNetworks);
-    }
-}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java
new file mode 100644
index 0000000..17c7d13
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.EditText;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class CustomEditTextPreferenceTest {
+
+    @Mock
+    private View mView;
+
+    private TestPreference mPreference;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mPreference = new TestPreference(RuntimeEnvironment.application);
+    }
+
+    @Test
+    public void bindDialogView_shouldRequestFocus() {
+        final String testText = "";
+        final EditText editText = spy(new EditText(RuntimeEnvironment.application));
+        editText.setText(testText);
+        when(mView.findViewById(android.R.id.edit)).thenReturn(editText);
+
+        mPreference.onBindDialogView(mView);
+
+        verify(editText).requestFocus();
+    }
+
+    private static class TestPreference extends CustomEditTextPreference {
+        public TestPreference(Context context) {
+            super(context);
+        }
+    }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 06d00be..1557d91 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -2319,8 +2319,6 @@
             loadBooleanSetting(stmt, Settings.System.SCREEN_BRIGHTNESS_MODE,
                     R.bool.def_screen_brightness_automatic_mode);
 
-            loadDefaultAnimationSettings(stmt);
-
             loadBooleanSetting(stmt, Settings.System.ACCELEROMETER_ROTATION,
                     R.bool.def_accelerometer_rotation);
 
@@ -2514,6 +2512,8 @@
             loadSetting(stmt, Settings.Global.MODE_RINGER,
                     AudioManager.RINGER_MODE_NORMAL);
 
+            loadDefaultAnimationSettings(stmt);
+
             // --- Previously in 'secure'
             loadBooleanSetting(stmt, Settings.Global.PACKAGE_VERIFIER_ENABLE,
                     R.bool.def_package_verifier_enable);
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 2fd7e87..2c5eb27 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -31,6 +31,7 @@
 
 LOCAL_STATIC_ANDROID_LIBRARIES := \
     SystemUIPluginLib \
+    SystemUISharedLib \
     android-support-v4 \
     android-support-v7-recyclerview \
     android-support-v7-preference \
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index b4b4e19..c52c0aa 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -26,6 +26,7 @@
 import com.android.systemui.plugins.qs.QSTile.State;
 
 import java.util.Objects;
+import java.util.function.Supplier;
 
 @ProvidesInterface(version = QSTile.VERSION)
 @DependsOn(target = QSIconView.class)
@@ -104,6 +105,7 @@
     public static class State {
         public static final int VERSION = 1;
         public Icon icon;
+        public Supplier<Icon> iconSupplier;
         public int state = Tile.STATE_ACTIVE;
         public CharSequence label;
         public CharSequence contentDescription;
@@ -118,6 +120,7 @@
             if (other == null) throw new IllegalArgumentException();
             if (!other.getClass().equals(getClass())) throw new IllegalArgumentException();
             final boolean changed = !Objects.equals(other.icon, icon)
+                    || !Objects.equals(other.iconSupplier, iconSupplier)
                     || !Objects.equals(other.label, label)
                     || !Objects.equals(other.contentDescription, contentDescription)
                     || !Objects.equals(other.dualLabelContentDescription,
@@ -130,6 +133,7 @@
                     || !Objects.equals(other.dualTarget, dualTarget)
                     || !Objects.equals(other.slash, slash);
             other.icon = icon;
+            other.iconSupplier = iconSupplier;
             other.label = label;
             other.contentDescription = contentDescription;
             other.dualLabelContentDescription = dualLabelContentDescription;
@@ -150,6 +154,7 @@
         protected StringBuilder toStringBuilder() {
             final StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('[');
             sb.append(",icon=").append(icon);
+            sb.append(",iconSupplier=").append(iconSupplier);
             sb.append(",label=").append(label);
             sb.append(",contentDescription=").append(contentDescription);
             sb.append(",dualLabelContentDescription=").append(dualLabelContentDescription);
diff --git a/packages/SystemUI/res-keyguard/values-af/strings.xml b/packages/SystemUI/res-keyguard/values-af/strings.xml
index b68566f..eac0455 100644
--- a/packages/SystemUI/res-keyguard/values-af/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-af/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Voer wagwoord in om te ontsluit"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Tik PIN in om te ontsluit"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Verkeerde PIN-kode."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Gelaai"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Laai"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Laai tans vinnig"</string>
diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml
index 21815e1..8fb0539 100644
--- a/packages/SystemUI/res-keyguard/values-am/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-am/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"ለመክፈት የይለፍ ቃል ይተይቡ"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"ለመክፈት ፒን ይተይቡ"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"ትክክል ያልሆነ ፒን  ኮድ።"</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"ባትሪ ሞልቷል"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"ኃይል በመሙላት ላይ"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"ኃይል በፍጥነት በመሙላት ላይ"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml
index f33fa9a..e9d4c37 100644
--- a/packages/SystemUI/res-keyguard/values-ar/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"اكتب كلمة المرور لإلغاء التأمين"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"اكتب رمز رقم التعريف الشخصي لإلغاء التأمين"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"رمز رقم التعريف الشخصي غير صحيح."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"تم الشحن"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"جارٍ الشحن"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"الشحن سريعًا"</string>
diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml
index 1b802fb..ab0e8ea 100644
--- a/packages/SystemUI/res-keyguard/values-az/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-az/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Kilidi açmaq üçün parol daxil edin"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Kilidi açmaq üçün PIN daxil edin"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Yanlış PIN kod."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Enerji yığdı"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Enerji yığır"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Sürətlə enerji yığır"</string>
diff --git a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
index efd5631..8af89c3 100644
--- a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Unesite lozinku da biste otključali"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Unesite PIN za otključavanje"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN kôd je netačan."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Napunjena je"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Puni se"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Brzo se puni"</string>
diff --git a/packages/SystemUI/res-keyguard/values-be/strings.xml b/packages/SystemUI/res-keyguard/values-be/strings.xml
index 3288971..b33c523 100644
--- a/packages/SystemUI/res-keyguard/values-be/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-be/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Увядзіце пароль для разблакіравання"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Каб разблакіраваць, увядзіце PIN-код"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Няправільны PIN-код."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Зараджаны"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Ідзе зарадка"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Зараджаецца хутка"</string>
diff --git a/packages/SystemUI/res-keyguard/values-bg/strings.xml b/packages/SystemUI/res-keyguard/values-bg/strings.xml
index f12967f..8dbdd5c 100644
--- a/packages/SystemUI/res-keyguard/values-bg/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bg/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Въведете парола, за да отключите"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Въведете ПИН кода, за да отключите"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Неправилен ПИН код."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Заредена"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Зарежда се"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Зарежда се бързо"</string>
diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml
index 06175eb..917effb 100644
--- a/packages/SystemUI/res-keyguard/values-bn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"আনলক করতে পাসওয়ার্ড লিখুন"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"আনলক করতে পিন লিখুন"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"ভুল পিন কোড দেওয়া হয়েছে।"</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"চার্জ হয়েছে"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"চার্জ হচ্ছে"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"দ্রুত চার্জ হচ্ছে"</string>
diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml
index 29e862d..d311ba8 100644
--- a/packages/SystemUI/res-keyguard/values-bs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Upišite lozinku za otključavanje"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Upišite PIN za otključavanje"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Pogrešan PIN."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Napunjeno"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Punjenje"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Brzo punjenje"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml
index 6eaa1b9..9f219ef 100644
--- a/packages/SystemUI/res-keyguard/values-ca/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Escriu la contrasenya per desbloquejar"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Escriu el PIN per desbloquejar"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"El codi PIN no és correcte."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Bateria carregada"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"S\'està carregant"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"S\'està carregant ràpidament"</string>
diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml
index 92e4e824..0665ac0 100644
--- a/packages/SystemUI/res-keyguard/values-cs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Zadejte heslo pro odemknutí"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Zadejte kód PIN pro odemknutí"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Nesprávný kód PIN."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Nabito"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Nabíjení"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Rychlé nabíjení"</string>
diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml
index 2f9b9a8..354aa96 100644
--- a/packages/SystemUI/res-keyguard/values-da/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-da/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Indtast adgangskoden for at låse op"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Indtast pinkoden for at låse op"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Forkert pinkode."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Opladet"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Oplader"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Oplader hurtigt"</string>
diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml
index f350671..9a5ad0e 100644
--- a/packages/SystemUI/res-keyguard/values-de/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-de/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Bitte gib das Passwort zum Entsperren ein"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Bitte gib die PIN zum Entsperren ein"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Falscher PIN-Code."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Aufgeladen"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Wird aufgeladen"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Schnelles Aufladen"</string>
diff --git a/packages/SystemUI/res-keyguard/values-el/strings.xml b/packages/SystemUI/res-keyguard/values-el/strings.xml
index 5a21c2e..6ec3e57 100644
--- a/packages/SystemUI/res-keyguard/values-el/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-el/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Πληκτρολογήστε τον κωδικό πρόσβασης για ξεκλείδωμα"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Πληκτρολογήστε τον αριθμό PIN για ξεκλείδωμα"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Λανθασμένος κωδικός PIN."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Φορτίστηκε"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Φόρτιση σε εξέλιξη"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Ταχεία φόρτιση"</string>
diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
index 66e3507..0c5989b 100644
--- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Ingresa la contraseña para desbloquearlo"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Ingresa el PIN para desbloquearlo"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Código PIN incorrecto"</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Cargada"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Cargando"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Carga rápida"</string>
diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml
index bc52f66..523eb4c 100644
--- a/packages/SystemUI/res-keyguard/values-es/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Escribe la contraseña para desbloquear"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Escribe el código PIN para desbloquear"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"El código PIN es incorrecto."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Cargada"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Cargando"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Cargando rápidamente"</string>
diff --git a/packages/SystemUI/res-keyguard/values-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml
index 44691b6..4c3cf6f 100644
--- a/packages/SystemUI/res-keyguard/values-et/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-et/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Avamiseks sisestage parool"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Avamiseks sisestage PIN-kood"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Vale PIN-kood."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Laetud"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Laadimine"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Kiiresti laadimine"</string>
diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml
index 985006d..f7f3d58 100644
--- a/packages/SystemUI/res-keyguard/values-eu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Idatzi desblokeatzeko pasahitza"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Idatzi desblokeatzeko PIN kodea"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN kode hori ez da zuzena."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Kargatuta"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Kargatzen"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Bizkor kargatzen"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml
index ffb3621..43f8197 100644
--- a/packages/SystemUI/res-keyguard/values-fa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"برای بازکردن قفل، گذرواژه را وارد کنید"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"برای بازکردن قفل، پین را تایپ کنید"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"کد پین اشتباه است."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"شارژ کامل شد"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"درحال شارژ شدن"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"شارژ سریع"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml
index b9e280a..b8689ee 100644
--- a/packages/SystemUI/res-keyguard/values-fi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Poista lukitus antamalla salasana."</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Poista lukitus antamalla PIN-koodi."</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Väärä PIN-koodi"</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Ladattu"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Ladataan"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Nopea lataus käynnissä"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
index 53fb15c..e70dca3 100644
--- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Entrez le mot de passe pour déverrouiller le clavier."</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Entrez le NIP pour déverrouiller le clavier."</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"NIP erroné."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Chargé"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Pile en cours de charge"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Charge rapide"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml
index c8ace66..1e7548e1 100644
--- a/packages/SystemUI/res-keyguard/values-fr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Saisissez le mot de passe pour déverrouiller le clavier"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Saisissez le code pour déverrouiller le clavier"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Le code est incorrect."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Chargé"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"En charge…"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Chargement rapide…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml
index 25ed7bf..4fe50ed 100644
--- a/packages/SystemUI/res-keyguard/values-gl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Escribe o contrasinal para desbloquear"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Escribe o PIN para desbloquear"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Código PIN incorrecto"</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Cargada"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Cargando"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Cargando rapidamente"</string>
diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml
index dbbd57a..72d9b75 100644
--- a/packages/SystemUI/res-keyguard/values-gu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"અનલૉક કરવા માટે પાસવર્ડ લખો"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"અનલૉક કરવા માટે પિન લખો"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"ખોટો પિન કોડ."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"ચાર્જ થઈ ગયું"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"ચાર્જ થઈ રહ્યું છે"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"ઝડપથી ચાર્જ થઈ રહ્યું છે"</string>
diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml
index c5a31d8..08f31da 100644
--- a/packages/SystemUI/res-keyguard/values-hi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"अनलॉक करने के लिए पासवर्ड लिखें"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"अनलॉक करने के लिए पिन लिखें"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"गलत पिन कोड."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"चार्ज हो गई है"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"चार्ज हो रही है"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"तेज़ी से चार्ज हो रही है"</string>
diff --git a/packages/SystemUI/res-keyguard/values-hr/strings.xml b/packages/SystemUI/res-keyguard/values-hr/strings.xml
index d4ec34c..34c3a5a 100644
--- a/packages/SystemUI/res-keyguard/values-hr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hr/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Unesite zaporku da biste otključali"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Unesite PIN da biste otključali"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN kôd nije točan."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Napunjeno"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Punjenje"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Brzo punjenje"</string>
diff --git a/packages/SystemUI/res-keyguard/values-hu/strings.xml b/packages/SystemUI/res-keyguard/values-hu/strings.xml
index 9246510..a1922ee 100644
--- a/packages/SystemUI/res-keyguard/values-hu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hu/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"A feloldáshoz írja be a jelszót"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"A feloldáshoz írja be a PIN-kódot"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Helytelen PIN-kód."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Feltöltve"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Töltés folyamatban"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Gyors töltés folyamatban"</string>
diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml
index b9536c0..8118d07 100644
--- a/packages/SystemUI/res-keyguard/values-hy/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Ապակողպելու համար մուտքագրեք գաղտնաբառը"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Ապակողպելու համար մուտքագրեք PIN կոդը"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN կոդը սխալ է։"</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Լիցքավորված է"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Լիցքավորում"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Արագ լիցքավորում"</string>
diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml
index 586cd7e..fbbb4be 100644
--- a/packages/SystemUI/res-keyguard/values-in/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-in/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Ketik sandi untuk membuka kunci"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Ketik PIN untuk membuka kunci"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Kode PIN salah."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Terisi"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Mengisi daya"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Mengisi daya dengan cepat"</string>
diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml
index d3760ff..191c66e 100644
--- a/packages/SystemUI/res-keyguard/values-is/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-is/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Sláðu inn aðgangsorðið til að opna"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Sláðu inn PIN-númer til að opna"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Rangt PIN-númer."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Fullhlaðin"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Í hleðslu"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Hröð hleðsla"</string>
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index 5392220..9ea32df 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Inserisci password per sbloccare"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Inserisci PIN per sbloccare"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Codice PIN errato."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Carico"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"In carica"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Ricarica veloce"</string>
diff --git a/packages/SystemUI/res-keyguard/values-iw/strings.xml b/packages/SystemUI/res-keyguard/values-iw/strings.xml
index 518c1c2..8b4e790 100644
--- a/packages/SystemUI/res-keyguard/values-iw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-iw/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"הזן סיסמה לביטול הנעילה"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"הזן את קוד הגישה לביטול הנעילה"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"קוד הגישה שגוי"</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"הסוללה טעונה"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"הסוללה נטענת"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"הסוללה נטענת מהר"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ja/strings.xml b/packages/SystemUI/res-keyguard/values-ja/strings.xml
index 3c76c2f..4b5be4f 100644
--- a/packages/SystemUI/res-keyguard/values-ja/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ja/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"ロックを解除するにはパスワードを入力してください"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"ロックを解除するには PIN を入力してください"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN コードが無効です。"</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"充電が完了しました"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"充電しています"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"急速充電しています"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ka/strings.xml b/packages/SystemUI/res-keyguard/values-ka/strings.xml
index e342fcc..5da8122 100644
--- a/packages/SystemUI/res-keyguard/values-ka/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ka/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"განსაბლოკად აკრიფეთ პაროლი"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"განსაბლოკად აკრიფეთ PIN-კოდი"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN-კოდი არასწორია."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"დატენილია"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"მიმდინარეობს დატენა"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"მიმდინარეობს სწრაფი დატენა"</string>
diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml
index e1dda1b..a99f2ec 100644
--- a/packages/SystemUI/res-keyguard/values-kk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Құлпын ашу үшін құпия сөзді теріңіз"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Құлпын ашу үшін PIN кодын енгізіңіз"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN коды қате"</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Зарядталды"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Зарядталуда"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Жылдам зарядталуда"</string>
diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml
index 400edbe8..7241ac3 100644
--- a/packages/SystemUI/res-keyguard/values-km/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-km/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"វាយ​បញ្ចូល​ពាក្យ​សម្ងាត់​ ដើម្បី​ដោះ​សោ"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"វាយ​បញ្ចូល​កូដ PIN ដើម្បី​ដោះ​សោ"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"កូដ PIN មិន​ត្រឹមត្រូវ​ទេ។"</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"បាន​សាក​ថ្ម"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"កំពុង​សាក​ថ្ម"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"សាកយ៉ាងឆាប់រហ័ស"</string>
diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml
index 8c69b48..5b94468 100644
--- a/packages/SystemUI/res-keyguard/values-kn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"ಅನ್‌ಲಾಕ್‌ ಮಾಡಲು ಪಾಸ್‌ವರ್ಡ್‌ ಟೈಪ್‌ ಮಾಡಿ"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"ಅನ್‌ಲಾಕ್‌ ಮಾಡಲು ಪಿನ್‌ ಟೈಪ್‌ ಮಾಡಿ"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"ತಪ್ಪಾದ ಪಿನ್‌ ಕೋಡ್."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"ಚಾರ್ಜ್ ಆಗಿದೆ"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"ವೇಗವಾಗಿ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml
index 0d3603b..c706900 100644
--- a/packages/SystemUI/res-keyguard/values-ko/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"잠금 해제하려면 비밀번호 입력"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"잠금 해제하려면 PIN 입력"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"잘못된 PIN 코드입니다."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"충전됨"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"충전 중"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"고속 충전 중"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml
index c61945c..ff27639 100644
--- a/packages/SystemUI/res-keyguard/values-ky/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Кулпуну ачуу үчүн сырсөздү териңиз"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Кулпуну ачуу үчүн PIN-кодду териңиз"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN-код туура эмес."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Кубатталды"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Кубатталууда"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Ыкчам кубатталууда"</string>
diff --git a/packages/SystemUI/res-keyguard/values-lt/strings.xml b/packages/SystemUI/res-keyguard/values-lt/strings.xml
index 993a6b7..9e59fb1 100644
--- a/packages/SystemUI/res-keyguard/values-lt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lt/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Įveskite slaptažodį, kad atrakintumėte"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Įveskite PIN kodą, kad atrakintumėte"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Netinkamas PIN kodas."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Įkrauta"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Įkraunama"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Greitai įkraunama"</string>
diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml
index 7bd1cfd..3447973 100644
--- a/packages/SystemUI/res-keyguard/values-lv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lv/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Ievadiet paroli, lai atbloķētu."</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Ievadiet PIN kodu, lai atbloķētu."</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN kods nav pareizs."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Akumulators uzlādēts"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Notiek uzlāde"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Notiek ātrā uzlāde"</string>
diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml
index c4405e0..263b3c9 100644
--- a/packages/SystemUI/res-keyguard/values-mk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mk/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Напишете ја лозинката за да отклучите"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Напишете PIN-код за да отклучите"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Погрешен PIN-код."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Полна"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Се полни"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Брзо полнење"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml
index bf72bcc..b00584f 100644
--- a/packages/SystemUI/res-keyguard/values-ml/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"അൺലോക്കുചെയ്യുന്നതിന് പാസ്‌വേഡ് ടൈപ്പുചെയ്യുക"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"അൺലോക്കുചെയ്യുന്നതിന് പിൻ ടൈപ്പുചെയ്യുക"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"പിൻ കോഡ് തെറ്റാണ്."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"ചാർജായി"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"ചാർജ്ജുചെയ്യുന്നു"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"വേഗത്തിൽ ചാർജുചെയ്യുന്നു"</string>
diff --git a/packages/SystemUI/res-keyguard/values-mn/strings.xml b/packages/SystemUI/res-keyguard/values-mn/strings.xml
index d440124..44c186f 100644
--- a/packages/SystemUI/res-keyguard/values-mn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mn/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Түгжээг тайлахын тулд нууц үгийг оруулна уу"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Түгжээг тайлахын тулд ПИН кодыг оруулна уу"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"ПИН код буруу байна."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Цэнэглэсэн"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Цэнэглэж байна"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Хурдан цэнэглэж байна"</string>
diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml
index ecee06b..8ab95f9 100644
--- a/packages/SystemUI/res-keyguard/values-mr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"अनलॉक करण्यासाठी संकेतशब्द टाइप करा"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"अनलॉक करण्यासाठी पिन टाइप करा"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"चुकीचा पिन कोड."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"चार्ज झाली"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"चार्ज होत आहे"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"द्रुतपणे चार्ज होत आहे"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ms/strings.xml b/packages/SystemUI/res-keyguard/values-ms/strings.xml
index 23295d3..efffa8c 100644
--- a/packages/SystemUI/res-keyguard/values-ms/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ms/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Taip kata laluan untuk membuka kunci"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Taip PIN untuk membuka kunci"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Kod PIN salah."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Sudah dicas"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Mengecas"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Mengecas dengan cepat"</string>
diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml
index 4789688..7b598e1 100644
--- a/packages/SystemUI/res-keyguard/values-my/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-my/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"လော့ခ်ဖွင့်ရန် စကားဝှက်ကို ထည့်ပါ"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"လော့ခ်ဖွင့်ရန် ပင်နံပါတ်ထည့်ပါ"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"ပင်နံပါတ် မှားနေသည်။"</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"အားသွင်းပြီးပါပြီ"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"အားသွင်းနေပါသည်"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"လျှင်မြန်စွာ အားသွင်းနေသည်"</string>
diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml
index d3187f3..1fef576 100644
--- a/packages/SystemUI/res-keyguard/values-nb/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nb/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Skriv inn passordet for å låse opp"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Skriv inn PIN-koden for å låse opp"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Feil PIN-kode."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Oppladet"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Lader"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Lader raskt"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index b8dc313..32e46f8 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"अनलक गर्न पासवर्ड टाइप गर्नुहोस्"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"अनलक गर्न PIN कोड टाइप गर्नुहोस्"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN कोड गलत छ।"</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"चार्ज भयो"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"चार्ज हुँदै"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"छिटो चार्ज हुँदै"</string>
diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml
index d1615aa..411ee6e 100644
--- a/packages/SystemUI/res-keyguard/values-nl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Typ het wachtwoord om te ontgrendelen"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Typ pincode om te ontgrendelen"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Onjuiste pincode."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Opgeladen"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Opladen"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Snel opladen"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml
index 92c8b9e..bedcf17 100644
--- a/packages/SystemUI/res-keyguard/values-pa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਪਾਸਵਰਡ ਟਾਈਪ ਕਰੋ"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਪਿੰਨ ਟਾਈਪ ਕਰੋ"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"ਗਲਤ ਪਿੰਨ ਕੋਡ।"</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"ਚਾਰਜ ਹੋ ਗਿਆ"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"ਤੇਜ਼ੀ ਨਾਲ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml
index 7597802..2c33c98 100644
--- a/packages/SystemUI/res-keyguard/values-pl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Wpisz hasło, aby odblokować"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Wpisz kod PIN, aby odblokować"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Nieprawidłowy kod PIN."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Naładowana"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Ładowanie"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Szybkie ładowanie"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
index 8d5e097..60c6f49 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Digite a senha para desbloquear"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Insira o PIN para desbloquear"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Código PIN incorreto."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Carregada"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Carregando"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Carregando rapidamente"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index 4d1a721..bd0bdaa 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Introduza a palavra-passe para desbloquear"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Introduza o PIN para desbloquear"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Código PIN incorreto."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Carregada"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"A carregar…"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"A carregar rapidamente…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml
index 8d5e097..60c6f49 100644
--- a/packages/SystemUI/res-keyguard/values-pt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Digite a senha para desbloquear"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Insira o PIN para desbloquear"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Código PIN incorreto."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Carregada"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Carregando"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Carregando rapidamente"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml
index c772a86..743bbc1 100644
--- a/packages/SystemUI/res-keyguard/values-ro/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Introduceți parola pentru a debloca"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Introduceți codul PIN pentru a debloca"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Cod PIN incorect."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Încărcată"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Se încarcă"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Se încarcă rapid"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml
index 25691d3..3f27010 100644
--- a/packages/SystemUI/res-keyguard/values-ru/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ru/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Введите пароль"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Введите PIN-код для разблокировки"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Неверный PIN-код."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Батарея заряжена"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Зарядка батареи"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Быстрая зарядка"</string>
diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml
index 807d54f..e48d81d 100644
--- a/packages/SystemUI/res-keyguard/values-si/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-si/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"අගුළු ඇරීමට මුරපදය ටයිප් කරන්න"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"අගුළු හැරීමට PIN එක ටයිප් කරන්න"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"වැරදි PIN කේතයකි."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"අරෝපිතයි"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"ආරෝපණය වෙමින්"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"වේගයෙන් ආරෝපණය වෙමින්"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml
index 5b433ce..9f397e6 100644
--- a/packages/SystemUI/res-keyguard/values-sk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sk/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Zadajte heslo na odomknutie"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Zadajte kód PIN na odomknutie"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Nesprávny kód PIN."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Nabité"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Nabíja sa"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Rýchle nabíjanie"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml
index 243b0be..9004a1e 100644
--- a/packages/SystemUI/res-keyguard/values-sl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Vnesite geslo za odklepanje"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Vnesite kodo PIN za odklepanje"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Napačna koda PIN."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Akumulator napolnjen"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Polnjenje"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Hitro polnjenje"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml
index 74f822b..2521b99 100644
--- a/packages/SystemUI/res-keyguard/values-sq/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Shkruaj fjalëkalimin për të shkyçur"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Shkruaj kodin PIN për ta shkyçur"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Kodi PIN është i pasaktë."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"I ngarkuar"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Po ngarkon"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Po ngarkon me shpejtësi"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sr/strings.xml b/packages/SystemUI/res-keyguard/values-sr/strings.xml
index c1cf1d2..6c40bd0 100644
--- a/packages/SystemUI/res-keyguard/values-sr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sr/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Унесите лозинку да бисте откључали"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Унесите PIN за откључавање"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN кôд је нетачан."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Напуњена је"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Пуни се"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Брзо се пуни"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml
index 1d6dcbdd..03f2086 100644
--- a/packages/SystemUI/res-keyguard/values-sv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Lås upp med lösenordet"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Lås upp med pinkoden"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Fel pinkod."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Laddat"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Laddas"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Laddas snabbt"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml
index 0ba106d..7ee0902 100644
--- a/packages/SystemUI/res-keyguard/values-sw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Andika nenosiri ili ufungue"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Andika PIN ili ufungue"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Nambari ya PIN si sahihi."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Betri imejaa"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Inachaji"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Inachaji kwa kasi"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml
index 2c403f0..4855161 100644
--- a/packages/SystemUI/res-keyguard/values-ta/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"திறக்க, கடவுச்சொல்லை உள்ளிடவும்"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"திறக்க, பின்னை உள்ளிடவும்"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"தவறான பின் குறியீடு."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"சார்ஜ் செய்யப்பட்டது"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"சார்ஜ் ஆகிறது"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"வேகமாகச் சார்ஜாகிறது"</string>
diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml
index 23349ae..bbcc57e 100644
--- a/packages/SystemUI/res-keyguard/values-te/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-te/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"అన్‌లాక్ చేయడానికి పాస్‌వర్డ్‌ను టైప్ చేయండి"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"అన్‌లాక్ చేయడానికి పిన్ టైప్ చేయండి"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"పిన్ కోడ్ తప్పు."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"ఛార్జ్ చేయబడింది"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"ఛార్జ్ అవుతోంది"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"వేగంగా ఛార్జ్ అవుతోంది"</string>
diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml
index b4a54ce..46d6ba8 100644
--- a/packages/SystemUI/res-keyguard/values-th/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-th/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"พิมพ์รหัสผ่านเพื่อปลดล็อก"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"พิมพ์ PIN เพื่อปลดล็อก"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"รหัส PIN ไม่ถูกต้อง"</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"ชาร์จแล้ว"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"กำลังชาร์จ"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"กำลังชาร์จเร็ว"</string>
diff --git a/packages/SystemUI/res-keyguard/values-tl/strings.xml b/packages/SystemUI/res-keyguard/values-tl/strings.xml
index 18e12ee..29989040 100644
--- a/packages/SystemUI/res-keyguard/values-tl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tl/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"I-type ang password upang i-unlock"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"I-type ang PIN upang i-unlock"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Mali ang PIN code."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Tapos nang mag-charge"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Nagcha-charge"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Mabilis na nagcha-charge"</string>
diff --git a/packages/SystemUI/res-keyguard/values-tr/strings.xml b/packages/SystemUI/res-keyguard/values-tr/strings.xml
index 7cc7650..5f526c3 100644
--- a/packages/SystemUI/res-keyguard/values-tr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tr/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Kilidi açmak için şifreyi yazın"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Kilidi açmak için PIN kodunu yazın"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Yanlış PIN kodu."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Ödeme alındı"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Şarj oluyor"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Hızlı şarj oluyor"</string>
diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml
index fa56d3b..43d01b5 100644
--- a/packages/SystemUI/res-keyguard/values-uk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Введіть пароль, щоб розблокувати"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Введіть PIN-код, щоб розблокувати"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Неправильний PIN-код."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Заряджено"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Заряджається"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Швидке заряджання"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml
index 320e545..4f09c98 100644
--- a/packages/SystemUI/res-keyguard/values-ur/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"غیر مقفل کرنے کیلئے پاس ورڈ ٹائپ کریں"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"‏غیر مقفل کرنے کیلئے PIN ٹائپ کریں"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"‏غلط PIN کوڈ۔"</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"چارج ہوگئی"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"چارج ہو رہا ہے"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"تیزی سے چارج ہو رہا ہے"</string>
diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml
index 062eb82..88bd095 100644
--- a/packages/SystemUI/res-keyguard/values-uz/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Qulfni ochish uchun parolni kiriting"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Qulfni ochish uchun PIN kodni kiriting"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN kodi xato."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Batareya quvvati to‘ldi"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Quvvatlash"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Tezkor quvvat olmoqda"</string>
diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml
index 348f77e..6b32d3a 100644
--- a/packages/SystemUI/res-keyguard/values-vi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Nhập mật khẩu để mở khóa"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Nhập mã PIN để mở khóa"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Mã PIN không chính xác."</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Đã sạc đầy"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Đang sạc"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Đang sạc nhanh"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
index 3dd328e..30737cc 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"输入密码即可解锁"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"输入 PIN 码即可解锁"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN 码有误。"</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"已充满电"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"正在充电"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"正在快速充电"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
index 9d7b7ce..1c159ca 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"輸入密碼即可解鎖"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"輸入 PIN 碼即可解鎖"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN 碼不正確。"</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"已完成充電"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"正在充電"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"正在快速充電"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
index db97648..a1d072a 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"輸入密碼即可解鎖"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"輸入 PIN 碼即可解鎖"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN 碼不正確。"</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"充電完成"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"充電中"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"快速充電中"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zu/strings.xml b/packages/SystemUI/res-keyguard/values-zu/strings.xml
index 6156e8a..4602237 100644
--- a/packages/SystemUI/res-keyguard/values-zu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zu/strings.xml
@@ -29,6 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Bhala iphasiwedi ukuze kuvuleke"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Faka i-PIN ukuvula"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Ikhodi ye-PIN engalungile!"</string>
+    <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
+    <skip />
     <string name="keyguard_charged" msgid="2222329688813033109">"Kushajiwe"</string>
     <string name="keyguard_plugged_in" msgid="89308975354638682">"Iyashaja"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Ishaja ngokushesha"</string>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index b0f7d28..3dd0e6c 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -48,6 +48,9 @@
          to unlock the keyguard.  Displayed in one line in a large font.  -->
     <string name="keyguard_password_wrong_pin_code">Incorrect PIN code.</string>
 
+    <!-- Shown in the lock screen when there is SIM card IO error. -->
+    <string name="keyguard_sim_error_message_short">Invalid Card.</string>
+
     <!-- When the lock screen is showing, the phone is plugged in and the battery is fully
          charged, say that it is charged. -->
     <string name="keyguard_charged">Charged</string>
diff --git a/packages/SystemUI/res/drawable/recents_dismiss_all_history.xml b/packages/SystemUI/res/drawable/recents_dismiss_all_history.xml
deleted file mode 100644
index 6a417e6..0000000
--- a/packages/SystemUI/res/drawable/recents_dismiss_all_history.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="16dp"
-    android:width="28dp"
-    android:viewportHeight="48"
-    android:viewportWidth="72" >
-    <group
-        android:name="dismiss_all"
-        android:translateX="48"
-        android:translateY="6" >
-        <group
-            android:name="3"
-            android:translateX="-24"
-            android:translateY="36" >
-            <path
-                android:name="rectangle_path_1_2"
-                android:pathData="M -24.0,-6.0 l 48.0,0 l 0,12.0 l -48.0,0 Z"
-                android:fillColor="#FFFFFFFF"
-                android:fillAlpha="1" />
-        </group>
-        <group
-            android:name="2"
-            android:translateX="-12"
-            android:translateY="18" >
-            <path
-                android:name="rectangle_path_1_1"
-                android:pathData="M -24.0,-6.0 l 48.0,0 l 0,12.0 l -48.0,0 Z"
-                android:fillColor="#FFFFFFFF"
-                android:fillAlpha="1" />
-        </group>
-        <group
-            android:name="1" >
-            <path
-                android:name="rectangle_path_1"
-                android:pathData="M -24.0,-6.0 l 48.0,0 l 0,12.0 l -48.0,0 Z"
-                android:fillColor="#FFFFFFFF"
-                android:fillAlpha="1" />
-        </group>
-    </group>
-</vector>
diff --git a/packages/SystemUI/res/layout/recents_task_view_header.xml b/packages/SystemUI/res/layout/recents_task_view_header.xml
index 5ee242d..1734506 100644
--- a/packages/SystemUI/res/layout/recents_task_view_header.xml
+++ b/packages/SystemUI/res/layout/recents_task_view_header.xml
@@ -66,14 +66,6 @@
         android:alpha="0"
         android:visibility="gone" />
 
-    <!-- The progress indicator shows if auto-paging is enabled -->
-    <ViewStub android:id="@+id/focus_timer_indicator_stub"
-               android:inflatedId="@+id/focus_timer_indicator"
-               android:layout="@layout/recents_task_view_header_progress_bar"
-               android:layout_width="match_parent"
-               android:layout_height="5dp"
-               android:layout_gravity="bottom" />
-
     <!-- The app overlay shows as the user long-presses on the app icon -->
     <ViewStub android:id="@+id/app_overlay_stub"
                android:inflatedId="@+id/app_overlay"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 8296a1c..b8c4029 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle onlangse programme is toegemaak."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Maak <xliff:g id="APP">%s</xliff:g>-programinligting oop."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Begin tans <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Kennisgewing is toegemaak."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Kennisgewingskerm."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Vinnige instellings."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Verdeel skerm na bo"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Verdeel skerm na links"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Verdeel skerm na regs"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Gelaai"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Laai tans"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> tot vol"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 324c9ff..1ad6367 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ሁሉም የቅርብ ጊዜ ማመልከቻዎች ተሰናብተዋል።"</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"የ<xliff:g id="APP">%s</xliff:g> መተግበሪያ መረጃውን ይክፈቱ።"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> በመጀመር ላይ።"</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"ማሳወቂያ ተወግዷል።"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"የማሳወቂያ ጥላ።"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"ፈጣን ቅንብሮች።"</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"ማያ ገጽ ወደ ላይ ክፈል"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"ማያ ገጽ ወደ ግራ ክፈል"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"ማያ ገጽ ወደ ቀኝ ክፈል"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ባትሪ ሞልቷል"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"ኃይል በመሙላት ላይ"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> እስኪሞላ ድረስ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 116a061..bff8d86 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -184,7 +184,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"تم تجاهل كل التطبيقات المستخدمة مؤخرًا."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"فتح معلومات تطبيق <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"جارٍ بدء <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"تم تجاهل الإشعار."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"مركز الإشعارات."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"الإعدادات السريعة."</string>
@@ -351,8 +350,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"تقسيم الشاشة بمحاذاة الجزء العلوي"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"تقسيم الشاشة بمحاذاة اليسار"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"تقسيم الشاشة بمحاذاة اليمين"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"تم الشحن"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"جارٍ الشحن"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> حتى الاكتمال"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 9e49466..82fc76a 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Bütün son tətbiqlər kənarlaşdırıldı."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> tətbiqi haqqında məlumatı açın."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> başlanır."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Bildiriş uzaqlaşdırıldı."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Bildiriş kölgəsi."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Tez ayarlar."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Ekranı yuxarıdan ayırın"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Ekranı soldan ayırın"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Ekranı sağdan ayırın"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Dolub"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Enerji doldurulur"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> dolana kimi"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index bf2ff90..ce0c51f 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -181,7 +181,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Sve nedavno korišćene aplikacije su odbačene."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Otvorite informacije o aplikaciji <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Pokrećemo <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obaveštenje je odbačeno."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Prozor sa obaveštenjima."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Brza podešavanja."</string>
@@ -345,8 +344,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Podeli ekran nagore"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Podeli ekran nalevo"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Podeli ekran nadesno"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Napunjena je"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Punjenje"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> dok se ne napuni"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 9006a5e..6de7852 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -184,7 +184,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Усе апошнія праграмы адхілены."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Адкрыць інфармацыю пра праграму \"<xliff:g id="APP">%s</xliff:g>\"."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Запускаецца <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Апавяшчэнне прапушчана."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Цень апавяшчэння.."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Хуткія налады."</string>
@@ -349,8 +348,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Падзяліць экран зверху"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Падзяліць экран злева"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Падзяліць экран справа"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Зараджаны"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Зарадка"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> да поўнай зарадкі"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index c79b527..35b5177 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Всички скорошни приложения са отхвърлени."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Отворете информацията за приложението <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> се стартира."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Известието е отхвърлено."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Падащ панел с известия."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Бързи настройки."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Разделяне на екрана нагоре"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Разделяне на екрана наляво"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Разделяне на екрана надясно"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Заредена"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Зарежда се"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> до пълно зареждане"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 44b01e8..ab1b0a1 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"সমস্ত সাম্প্রতিক অ্যাপ্লিকেশন খারিজ করা হয়েছে।"</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> অ্যাপ্লিকেশানের তথ্য খুলবে৷"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> তারাঙ্কিত করা হচ্ছে।"</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"বিজ্ঞপ্তি খারিজ করা হয়েছে৷"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"বিজ্ঞপ্তি শেড৷"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"দ্রুত সেটিংস৷"</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"স্ক্রিনটি উপরের দিকে বিভক্ত করুন"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"স্ক্রিনটি বাঁদিকে বিভক্ত করুন"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"স্ক্রিনটি ডানদিকে বিভক্ত করুন"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"চার্জ হয়েছে"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"চার্জ হচ্ছে"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"পূর্ণ হতে <xliff:g id="CHARGING_TIME">%s</xliff:g> সময় লাগবে"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 6c6eb36..f9a4235 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -181,7 +181,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Sve nedavno korištene aplikacije su odbačene."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Otvaranje informacija o aplikaciji <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Pokrećem aplikaciju <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obavještenje je uklonjeno."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Obavještenja sa sjenčenjem."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Brze postavke."</string>
@@ -345,8 +344,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Podijeli ekran nagore"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Podijeli ekran nalijevo"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Podijeli ekran nadesno"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Napunjeno"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Punjenje"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Do kraja punjenja preostalo <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 4bae85f..eea0e63 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"S\'han descartat totes les aplicacions recents."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Obre la informació sobre l\'aplicació <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"S\'està iniciant <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificació omesa."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Àrea de notificacions"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Configuració ràpida"</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Divideix la pantalla cap amunt"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Divideix la pantalla cap a l\'esquerra"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Divideix la pantalla cap a la dreta"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"S\'està carregant"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> per completar la càrrega"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index d3a15df..e014af6 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -184,7 +184,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Všechny naposledy použité aplikace byly odstraněny."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Otevře informace o aplikaci <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Spouštění aplikace <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Oznámení je zavřeno."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Panel oznámení."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Rychlé nastavení."</string>
@@ -349,8 +348,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Rozdělit obrazovku nahoru"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Rozdělit obrazovku vlevo"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Rozdělit obrazovku vpravo"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Nabito"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Nabíjení"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do plného nabití"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 24d2976..58e9a2f 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle de seneste applikationer er lukket."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Åbn appoplysningerne for <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> startes."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Underretningen er annulleret."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Underretningspanel."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Hurtige indstillinger."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Delt skærm øverst"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Delt skærm til venstre"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Delt skærm til højre"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Opladet"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Oplader"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> indtil fuld opladet"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 46dcf3e..2f615fe 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -184,7 +184,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle kürzlich verwendeten Apps wurden entfernt."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Infos zur App \"<xliff:g id="APP">%s</xliff:g>\" öffnen."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> wird gestartet."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Benachrichtigung geschlossen"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Benachrichtigungsleiste"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Schnelleinstellungen"</string>
@@ -347,8 +346,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Geteilten Bildschirm oben anzeigen"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Geteilten Bildschirm auf linker Seite anzeigen"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Geteilten Bildschirm auf der rechten Seite anzeigen"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Aufgeladen"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Wird aufgeladen"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Voll in <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 92a0976..ef47851 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -180,11 +180,10 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Έγινε παράβλεψη όλων των πρόσφατων εφαρμογών."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Άνοιγμα πληροφοριών εφαρμογής <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Έναρξη <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Η ειδοποίηση έχει απορριφθεί."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Πλαίσιο σκίασης ειδοποιήσεων."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Γρήγορες ρυθμίσεις."</string>
-    <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Κλείδωμα οθόνης."</string>
+    <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Οθόνη κλειδώματος"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Ρυθμίσεις"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Επισκόπηση."</string>
     <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Οθόνη κλειδωμένης εργασίας"</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Διαχωρισμός οθόνης στην κορυφή"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Διαχωρισμός οθόνης στα αριστερά"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Διαχωρισμός οθόνης στα δεξιά"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Φορτίστηκε"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Φόρτιση"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> για πλήρη φόρτιση"</string>
@@ -721,7 +718,7 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Άνοιγμα ρυθμίσεων <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Επεξεργασία σειράς ρυθμίσεων."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Σελίδα <xliff:g id="ID_1">%1$d</xliff:g> από <xliff:g id="ID_2">%2$d</xliff:g>"</string>
-    <string name="tuner_lock_screen" msgid="5755818559638850294">"Κλείδωμα οθόνης"</string>
+    <string name="tuner_lock_screen" msgid="5755818559638850294">"Οθόνη κλειδώματος"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Ανάπτυξη"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Ελαχιστοποίηση"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Κλείσιμο"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 8db0a99..9dd1b01 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -182,7 +182,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Se descartaron todas las aplicaciones recientes."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Abre la información de la aplicación de <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificación ignorada"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Pantalla de notificaciones"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Configuración rápida"</string>
@@ -345,8 +344,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Dividir pantalla en la parte superior"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Dividir pantalla a la izquierda"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Dividir pantalla a la derecha"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Cargada"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Cargando"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> para completarse"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 6eabfc0..52e7c51 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -182,7 +182,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Se han ignorado todas las aplicaciones recientes."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Abre la información de la aplicación <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificación ignorada"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Pantalla de notificaciones"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Ajustes rápidos"</string>
@@ -345,8 +344,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Dividir la pantalla en la parte superior"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Dividir la pantalla a la izquierda"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Dividir la pantalla a la derecha"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Cargada"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Cargando"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> para completarse"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 2fc49ff..2b37558 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -182,7 +182,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Kõikidest hiljutistest rakendustest on loobutud"</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Rakenduse <xliff:g id="APP">%s</xliff:g> teabe avamine."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Rakenduse <xliff:g id="APP">%s</xliff:g> käivitamine."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g>, <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Märguandest on loobutud."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Märguande vari."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Kiirseaded."</string>
@@ -345,8 +344,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Poolita ekraan üles"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Poolita ekraan vasakule"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Poolita ekraan paremale"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Laetud"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Laadimine"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Täislaadimiseks kulub <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index cd0e9a8..a7b5938 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -182,7 +182,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Azken aplikazio guztiak baztertu da."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Ireki <xliff:g id="APP">%s</xliff:g> aplikazioari buruzko informazioa."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> hasten."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Jakinarazpena baztertu da."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Jakinarazpenen panela."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Ezarpen bizkorrak."</string>
@@ -345,8 +344,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Zatitu pantaila eta ezarri goian"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Zatitu pantaila eta ezarri ezkerrean"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Zatitu pantaila eta ezarri eskuinean"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Kargatuta"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Kargatzen"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> falta zaizkio guztiz kargatzeko"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index b3e1b4e..64e34a9 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"همه برنامه‌های اخیر رد شدند."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"باز کردن اطلاعات برنامه <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> در حال شروع به کار است."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"اعلان ردشد."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"مجموعه اعلان."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"تنظیمات سریع."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"تقسیم کردن صفحه به بالا"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"تقسیم کردن صفحه به چپ"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"تقسیم کردن صفحه به راست"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"شارژ کامل شد"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"در حال شارژ شدن"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> مانده تا شارژ کامل شود"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 2dc96d6..7b6dc54 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Kaikki viimeisimmät sovellukset on hylätty."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Avaa sovelluksen <xliff:g id="APP">%s</xliff:g> tiedot."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Käynnistetään <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Ilmoitus hylätty."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Ilmoitusalue."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Pika-asetukset."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Jaa näyttö ylös"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Jaa näyttö vasemmalle"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Jaa näyttö oikealle"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Ladattu"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Ladataan"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> kunnes täynnä"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index f43a048..2344c00 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -182,7 +182,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Toutes les applications récentes ont été supprimées."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Ouvre les détails de l\'application <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Lancement de <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification masquée"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Volet des notifications"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Paramètres rapides"</string>
@@ -345,8 +344,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Écran partagé dans le haut"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Écran partagé à la gauche"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Écran partagé à la droite"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Chargée"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Charge en cours..."</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Chargée dans <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index e14f8be..4b4e5b7 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -182,7 +182,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Toutes les applications récentes ont été supprimées."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Ouvre les informations sur l\'application <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Lancement de <xliff:g id="APP">%s</xliff:g>"</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> : <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification masquée"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Volet des notifications"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Paramètres rapides"</string>
@@ -345,8 +344,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Partager l\'écran en haut"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Partager l\'écran sur la gauche"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Partager l\'écran sur la droite"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Chargé"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"En charge"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Chargé dans <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 62d668c..7f11ba2 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -182,7 +182,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Rexeitáronse todas as aplicacións recentes."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Abre a información da aplicación <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificación rexeitada"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Sombra de notificación"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Configuración rápida"</string>
@@ -345,8 +344,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Dividir pantalla na parte superior"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Dividir pantalla á esquerda"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Dividir pantalla á dereita"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Cargada"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Cargando"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> para completar a carga"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index c04da24..2dbd57b 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"તમામ તાજેતરની ઍપ્લિકેશનો કાઢી નાખી."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> ઍપ્લિકેશન માહિતી ખોલો."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> પ્રારંભ કરી રહ્યું છે."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"સૂચના કાઢી નાખી."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"નોટિફિકેશન શેડ."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"ઝડપી સેટિંગ્સ."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"સ્ક્રીનને ઉપરની તરફ વિભાજિત કરો"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"સ્ક્રીનને ડાબી તરફ વિભાજિત કરો"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"સ્ક્રીનને જમણી તરફ વિભાજિત કરો"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ચાર્જ થઈ ગયું"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"ચાર્જ થઈ રહ્યું છે"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"પૂર્ણ થવામાં <xliff:g id="CHARGING_TIME">%s</xliff:g> બાકી"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 0a5c736..93dadd2 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"हाल ही के सभी ऐप्लिकेशन ख़ारिज कर दिए गए."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> ऐप्लिकेशन की जानकारी खोलें."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> प्रारंभ हो रहा है."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"सूचना खारिज की गई."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"सूचना शेड."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"त्वरित सेटिंग."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"ऊपर की ओर दो स्क्रीन बनाएं"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"बाईं ओर दो स्क्रीन बनाएं"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"दाईं ओर दो स्क्रीन बनाएं"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"चार्ज हो गई है"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"चार्ज हो रही है"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"पूर्ण होने में <xliff:g id="CHARGING_TIME">%s</xliff:g> शेष"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index adb41b3..43aa345 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -181,7 +181,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Odbačene su sve nedavne aplikacije."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Otvaranje informacija o aplikaciji <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Pokretanje aplikacije <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obavijest je odbačena."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Zaslon obavijesti."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Brze postavke."</string>
@@ -345,8 +344,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Podijeli zaslon na vrhu"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Podijeli zaslon slijeva"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Podijeli zaslon zdesna"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Napunjeno"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Punjenje"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do napunjenosti"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 609992f..4d8b697 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Az összes alkalmazás eltávolítva a nemrég használtak közül."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"A(z) <xliff:g id="APP">%s</xliff:g> alkalmazás adatainak megnyitása."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"A(z) <xliff:g id="APP">%s</xliff:g> indítása."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Értesítés elvetve."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Értesítési felület."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Gyorsbeállítások."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Osztott képernyő felülre"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Osztott képernyő balra"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Osztott képernyő jobbra"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Feltöltve"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Töltés"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> a teljes töltöttségig"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 0022f7b..923e4ec 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Բոլոր վերջին հավելվածները հեռացվել են ցուցակից:"</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Բացել <xliff:g id="APP">%s</xliff:g> հավելվածի մասին տեղեկությունները"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Մեկնարկել <xliff:g id="APP">%s</xliff:g>-ը:"</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Ծանուցումը անտեսվեց:"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Ծանուցումների վահանակ:"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Արագ կարգավորումներ:"</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Տրոհել էկրանը վերևից"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Տրոհել էկրանը ձախից"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Տրոհել էկրանն աջից"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Լիցքավորված է"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Լիցքավորվում է"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Լրիվ լիցքավորմանը մնաց <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 0411fa9..296842f 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Semua aplikasi terbaru telah ditutup."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Buka info aplikasi <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Memulai <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notifikasi disingkirkan."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Bayangan pemberitahuan."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Setelan cepat."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Pisahkan layar ke atas"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Pisahkan layar ke kiri"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Pisahkan layar ke kanan"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Terisi"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Mengisi daya"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> sampai penuh"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index eefb363..58bdc3b 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Öll nýleg forrit fjarlægð."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Opna forritsupplýsingar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Ræsir <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Tilkynningu lokað."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Tilkynningasvæði."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Flýtistillingar."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Skipta skjá að ofanverðu"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Skipta skjá til vinstri"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Skipta skjá til hægri"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Fullhlaðin"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Í hleðslu"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> þar til fullri hleðslu er náð"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 915f40a..56d5348 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -182,7 +182,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Tutte le applicazioni recenti sono state rimosse."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Mostra informazioni sull\'applicazione <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Avvio di <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notifica eliminata."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Area notifiche."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Impostazioni rapide."</string>
@@ -345,8 +344,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Schermo diviso in alto"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Schermo diviso a sinistra"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Schermo diviso a destra"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carica"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"In carica"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> al termine della carica"</string>
@@ -506,7 +503,7 @@
     <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Tocca per disattivare l\'audio."</string>
     <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"%s comandi del volume mostrati. Fai scorrere verso l\'alto per ignorare."</string>
     <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Comandi del volume nascosti"</string>
-    <string name="system_ui_tuner" msgid="708224127392452018">"Sintetizzatore interfaccia utente di sistema"</string>
+    <string name="system_ui_tuner" msgid="708224127392452018">"Ottimizzatore UI di sistema"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Mostra percentuale batteria incorporata"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Mostra la percentuale di carica della batteria nell\'icona della barra di stato quando non è in carica"</string>
     <string name="quick_settings" msgid="10042998191725428">"Impostazioni rapide"</string>
@@ -529,12 +526,12 @@
     <string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"Hotspot"</string>
     <string name="accessibility_managed_profile" msgid="6613641363112584120">"Profilo di lavoro"</string>
     <string name="tuner_warning_title" msgid="7094689930793031682">"Il divertimento riservato a pochi eletti"</string>
-    <string name="tuner_warning" msgid="8730648121973575701">"Il sintetizzatore interfaccia utente di sistema mette a disposizione altri metodi per modificare e personalizzare l\'interfaccia utente di Android. Queste funzioni sperimentali potrebbero cambiare, interrompersi o scomparire nelle versioni successive. Procedi con cautela."</string>
+    <string name="tuner_warning" msgid="8730648121973575701">"L\'Ottimizzatore UI di sistema mette a disposizione altri metodi per modificare e personalizzare l\'interfaccia utente di Android. Queste funzioni sperimentali potrebbero cambiare, interrompersi o scomparire nelle versioni successive. Procedi con cautela."</string>
     <string name="tuner_persistent_warning" msgid="8597333795565621795">"Queste funzioni sperimentali potrebbero cambiare, interrompersi o scomparire nelle versioni successive. Procedi con cautela."</string>
     <string name="got_it" msgid="2239653834387972602">"OK"</string>
-    <string name="tuner_toast" msgid="603429811084428439">"Complimenti! Il sintetizzatore interfaccia utente di sistema è stato aggiunto alle impostazioni."</string>
+    <string name="tuner_toast" msgid="603429811084428439">"Complimenti! L\'Ottimizzatore UI di sistema è stato aggiunto alle impostazioni."</string>
     <string name="remove_from_settings" msgid="8389591916603406378">"Rimuovi dalle impostazioni"</string>
-    <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Vuoi rimuovere il sintetizzatore interfaccia utente di sistema dalle impostazioni e smettere di utilizzare tutte le sue funzioni?"</string>
+    <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Vuoi rimuovere l\'Ottimizzatore UI di sistema dalle impostazioni e smettere di utilizzare tutte le sue funzioni?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"Applicazione non installata sul dispositivo"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Mostra i secondi nell\'orologio"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra i secondi nell\'orologio nella barra di stato. Ciò potrebbe ridurre la durata della carica della batteria."</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index c51c025..eb85099 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -182,7 +182,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"כל האפליקציות האחרונות נסגרו."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"פתח מידע על האפליקציה <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"מפעיל את <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"הודעה נדחתה."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"לוח הודעות."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"הגדרות מהירות."</string>
@@ -347,8 +346,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"פיצול מסך למעלה"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"פיצול מסך לשמאל"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"פיצול מסך לימין"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"טעון"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"טוען"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> עד למילוי"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index e400fff..ac29ca7 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -182,7 +182,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"最近のアプリケーションをすべて消去しました。"</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"「<xliff:g id="APP">%s</xliff:g>」のアプリ情報を開きます。"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>を開始しています。"</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"通知が削除されました。"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"通知シェード"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"クイック設定"</string>
@@ -345,8 +344,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"画面を上に分割"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"画面を左に分割"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"画面を右に分割"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"充電が完了しました"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"充電しています"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"充電完了まで<xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 55a0b5f..6750756 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ყველა ბოლო აპლიკაცია გაუქმდა."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> აპლიკაციის ინფორმაციის გახსნა."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> იწყება."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"შეტყობინება წაიშალა."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"შეტყობინებების ფარდა"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"სწრაფი პარამეტრები"</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"ეკრანის გაყოფა ზემოთ"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"ეკრანის გაყოფა მარცხნივ"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"ეკრანის გაყოფა მარჯვნივ"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"დატენილია"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"მიმდინარეობს დატენვა"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> სრულად დატენვამდე"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 8937b7f..38d84c4 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Барлық жақындағы қабылданбаған қолданбалар."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> қолданбасы туралы ақпаратты ашады."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> іске қосылуда."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Хабар алынып тасталды."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Хабарландыру тақтасы"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Жылдам параметрлер."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Экранды жоғарыға қарай бөлу"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Экранды солға қарай бөлу"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Экранды оңға қарай бөлу"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Зарядталды"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Зарядталуда"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Толғанға дейін <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index f50003c..097d21d 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"កម្មវិធីថ្មីៗទាំងអស់ត្រូវបានបោះបង់។"</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"បើកព័ត៌មានកម្មវិធី <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"ចាប់ផ្ដើម <xliff:g id="APP">%s</xliff:g> ។"</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"បាន​បដិសេធ​ការ​ជូនដំណឹង"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"ពណ៌​ការ​ជូន​ដំណឹង"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"ការ​កំណត់​រហ័ស។"</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"បំបែក​អេក្រង់​ទៅ​ខាងលើ"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"បំបែក​អេក្រង់​ទៅ​ខាងឆ្វេង"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"បំបែក​អេក្រង់​ទៅ​ខាងស្តាំ"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"បាន​បញ្ចូល​ថ្ម​​"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"កំពុងសាក​ថ្ម"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> រហូត​ដល់ពេញ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 087da86..ca1a650 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ಇತ್ತೀಚಿನ ಎಲ್ಲಾ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ವಜಾಗೊಳಿಸಲಾಗಿದೆ."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ ತೆರೆಯಿರಿ."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ಪ್ರಾರಂಭಿಸಲಾಗುತ್ತಿದೆ."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"ಅಧಿಸೂಚನೆ ವಜಾಗೊಂಡಿದೆ."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"ಅಧಿಸೂಚನೆಯ ಛಾಯೆ."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‍ಗಳು."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"ಮೇಲ್ಭಾಗಕ್ಕೆ ಪರದೆಯನ್ನು ವಿಭಜಿಸಿ"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"ಎಡಕ್ಕೆ ಪರದೆಯನ್ನು ವಿಭಜಿಸಿ"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"ಬಲಕ್ಕೆ ಪರದೆಯನ್ನು ವಿಭಜಿಸಿ"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ಚಾರ್ಜ್ ಆಗಿದೆ"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> ಪೂರ್ಣಗೊಳ್ಳುವವರೆಗೆ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index ff3100b..ddc201b 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -182,7 +182,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"최근 사용한 애플리케이션을 모두 닫았습니다."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> 애플리케이션 정보를 엽니다."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>을(를) 시작하는 중입니다."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"알림이 제거되었습니다."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"알림 세부정보"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"빠른 설정"</string>
@@ -345,8 +344,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"위쪽으로 화면 분할"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"왼쪽으로 화면 분할"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"오른쪽으로 화면 분할"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"충전됨"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"충전 중"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"완충까지 <xliff:g id="CHARGING_TIME">%s</xliff:g> 남음"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 8a41051..cbd3ec02 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Акыркы колдонмолордун баары көз жаздымда калтырылды."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> колдонмосу жөнүндө маалыматты ачыңыз."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> иштеп баштоодо."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Эскертме жок кылынды."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Эскертмелер көшөгөсү."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Тез тууралоолор."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Экранды өйдө жакка бөлүү"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Экранды сол жакка бөлүү"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Экранды оң жакка бөлүү"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Кубатталды"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Кубатталууда"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> толгонго чейин"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index ee627d7..774a123 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -182,7 +182,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Atsisakyta visų naujausių programų."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Atidaryti programos „<xliff:g id="APP">%s</xliff:g>“ informaciją."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Paleidžiama <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"„<xliff:g id="APP">%1$s</xliff:g>“ <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Pranešimo atsisakyta."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Pranešimų gaubtas."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Spartieji nustatymai."</string>
@@ -347,8 +346,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Skaidyti ekraną į viršų"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Skaidyti ekraną į kairę"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Skaidyti ekraną į dešinę"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Įkrautas"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Kraunamas"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> iki visiško įkrovimo"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index e101ff0..dfbd0d2 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -181,7 +181,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Visas nesen izmantotās lietojumprogrammas tika noņemtas."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Atveriet lietojumprogrammas <xliff:g id="APP">%s</xliff:g> informāciju."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Notiek lietotnes <xliff:g id="APP">%s</xliff:g> palaišana."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Paziņojums netiek rādīts."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Paziņojumu panelis"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Ātrie iestatījumi"</string>
@@ -345,8 +344,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Sadalīt ekrānu augšdaļā"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Sadalīt ekrānu kreisajā pusē"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Sadalīt ekrānu labajā pusē"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Akumulators uzlādēts"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Notiek uzlāde"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> līdz pilnam akumulatoram"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 11673fd..d62775c 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Сите неодамнешни апликации се отфрлени."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Отвори информации за апликацијата <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Се стартува <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Известувањето е отфрлено."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Панел за известување"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Брзи поставки."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Поделен екран во горниот дел"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Поделен екран на левата страна"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Поделен екран на десната страна"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Наполнета"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Се полни"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> додека не се наполни"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index e30dbcb..855ae6a 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"അടുത്തിടെയുള്ള എല്ലാ അപ്ലിക്കേഷനും നിരസിച്ചു."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> ആപ്പ് വിവരങ്ങൾ തുറക്കുക."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ആരംഭിക്കുന്നു."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"അറിയിപ്പ് നിരസിച്ചു."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"അറിയിപ്പ് ഷെയ്‌ഡ്."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"ദ്രുത ക്രമീകരണങ്ങൾ."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"സ്ക്രീൻ മുകളിലേക്ക് സ്പ്ലിറ്റ് ചെയ്യുക"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"സ്ക്രീൻ ഇടതുവശത്തേക്ക് സ്പ്ലിറ്റ് ചെയ്യുക"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"സ്ക്രീൻ വലതുവശത്തേക്ക് പിളർത്തുക"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ചാർജായി"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"ചാർജ്ജുചെയ്യുന്നു"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"ഫുൾ ചാർജാകാൻ, <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 8455c5a..c9d1d31 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -178,7 +178,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Хамгийн сүүлийн бүх програмыг арилгасан байна."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> апп-н мэдээллийг нээнэ үү."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>-г эхлүүлж байна."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Мэдэгдэл хаагдсан."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Мэдэгдлийн хураангуй самбар"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Шуурхай тохиргоо."</string>
@@ -341,8 +340,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Дэлгэцийг дээд хэсэгт хуваах"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Дэлгэцийг зүүн хэсэгт хуваах"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Дэлгэцийг баруун хэсэгт хуваах"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Цэнэглэгдсэн"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Цэнэглэж байна"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"дүүргэхэд <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 0503b48..b5975b1 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"अलीकडील सर्व अॅप्लिकेशन डिसमिस झाले."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> अॅप्लिकेशन माहिती उघडा."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> प्रारंभ करीत आहे."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"सूचना डिसमिस केल्या."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"सूचना शेड."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"द्रुत सेटिंग्ज."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"स्क्रीन शीर्षस्थानी विभाजित करा"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"स्क्रीन डावीकडे विभाजित करा"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"स्क्रीन उजवीकडे विभाजित करा"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"चार्ज झाली"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"चार्ज होत आहे"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> पूर्ण होईपर्यंत"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 1a1d337..fad7563 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Semua aplikasi terbaharu diketepikan."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Buka maklumat aplikasi <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Memulakan <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Pemberitahuan diketepikan."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Bidai pemberitahuan."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Tetapan pantas."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Pisahkan skrin ke atas"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Pisahkan skrin ke kiri"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Pisahkan skrin ke kanan"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Sudah dicas"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Mengecas"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Lagi <xliff:g id="CHARGING_TIME">%s</xliff:g> untuk penuh"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 6b79e33..faa1f1a 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"မကြာသေးမီက အပလီကေးရှင်းများအားလုံး ဖယ်ထုတ်ပြီးပါပြီ။"</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> အပလီကေးရှင်းအချက်အလက်ကို ဖွင့်ပါ။"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>ကို စတင်နေသည်။"</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g><xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"အကြောင်းကြားချက်ကိုဖယ်ရှားပြီး"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"အ​ကြောင်းကြားစာအကွက်"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"အမြန်လုပ် အပြင်အဆင်"</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"မျက်နှာပြင်ကို အပေါ်သို့ ခွဲရန်"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"မျက်နှာပြင်ကို ဘယ်ဘက်သို့ ခွဲရန်"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"မျက်နှာပြင်ကို ညာဘက်သို့ ခွဲရန်"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"အားသွင်းပြီး"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"အားသွင်းနေ"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> ပြည်သည့် အထိ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 87c71bc..77af297 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle nylig brukte apper er avvist."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Åpne appinformasjonen for <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Starter <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Varselet ble skjult."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Varselskygge."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Hurtiginnstillinger."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Delt skjerm øverst"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Delt skjerm til venstre"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Delt skjerm til høyre"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Oppladet"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Lader"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Fulladet om <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 63c1b79..8afef76 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"सबै हालका अनुप्रयोगहरू खारेज गरियो।"</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> अनुप्रयोग सम्बन्धी जानकारी खोल्नुहोस्।"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>सुरु गर्दै।"</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"सूचना खारेज।"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"सूचना कक्ष।"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"द्रुत सेटिङहरू"</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"विभाजित-स्क्रिनलाई शीर्ष स्थानमा राख्नुहोस्‌"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"विभाजित-स्क्रिनलाई बायाँतर्फ राख्नुहोस्‌"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"विभाजित-स्क्रिनलाई दायाँतर्फ राख्नुहोस्‌"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"चार्ज भयो"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"चार्ज हुँदै"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> पूर्ण नभएसम्म"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 3b31b2d..815e5f9 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle recente apps gesloten."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"App-gegevens voor <xliff:g id="APP">%s</xliff:g> openen."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> starten."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Melding verwijderd."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Meldingenpaneel."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Snelle instellingen."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Scherm bovenaan gesplitst"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Scherm links gesplitst"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Scherm rechts gesplitst"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Opgeladen"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Opladen"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> tot volledig opgeladen"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index c2089a6..cec5c96 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ਸਾਰੀਆਂ ਹਾਲੀਆ ਐਪਲੀਕੇਸ਼ਨਾਂ ਰੱਦ ਕੀਤੀਆਂ।"</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> ਐਪਲੀਕੇਸ਼ਨਾਂ ਜਾਣਕਾਰੀ ਖੋਲ੍ਹੋ।"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ਚਾਲੂ ਕਰ ਰਿਹਾ ਹੈ।"</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"ਸੂਚਨਾ ਰੱਦ ਕੀਤੀ।"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"ਸੂਚਨਾ ਸ਼ੇਡ।"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ।"</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"ਸਕ੍ਰੀਨ ਨੂੰ ਉੱਪਰ ਵੱਲ ਵਿਭਾਜਿਤ ਕਰੋ"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"ਸਕ੍ਰੀਨ ਨੂੰ ਖੱਬੇ ਪਾਸੇ ਵਿਭਾਜਿਤ ਕਰੋ"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"ਸਕ੍ਰੀਨ ਨੂੰ ਸੱਜੇ ਪਾਸੇ ਵਿਭਾਜਿਤ ਕਰੋ"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ਚਾਰਜ ਹੋਇਆ"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"ਚਾਰਜ ਕਰ ਰਿਹਾ ਹੈ"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> ਪੂਰਾ ਹੋਣ ਤੱਕ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index a725e53..fdd4c02 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -182,7 +182,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Wszystkie ostatnie aplikacje zostały zamknięte."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Otwórz informacje o aplikacji <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Uruchamiam <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Zamknięto powiadomienie."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Obszar powiadomień."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Szybkie ustawienia."</string>
@@ -347,8 +346,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Podziel ekran u góry"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Podziel ekran z lewej"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Podziel ekran z prawej"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Naładowana"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Ładowanie"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do pełnego naładowania"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 08f5a38..4b72c29 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -182,7 +182,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Todos os apps recentes foram dispensados."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Abre informações do app <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificação dispensada."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Aba de notificações."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Configurações rápidas."</string>
@@ -345,8 +344,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Dividir a tela para a parte superior"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Dividir a tela para a esquerda"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Dividir a tela para a direita"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Carregando"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> até concluir"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 7d3e9d5..962dc49 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Todas as aplicações recentes foram ignoradas."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Abrir as informações da aplicação <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"A iniciar <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificação ignorada."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Painel de notificações."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Definições rápidas."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Ecrã dividido na parte superior"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Ecrã dividido à esquerda"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Ecrã dividido à direita"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"A carregar"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> até ficar completa"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 08f5a38..4b72c29 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -182,7 +182,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Todos os apps recentes foram dispensados."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Abre informações do app <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificação dispensada."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Aba de notificações."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Configurações rápidas."</string>
@@ -345,8 +344,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Dividir a tela para a parte superior"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Dividir a tela para a esquerda"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Dividir a tela para a direita"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Carregando"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> até concluir"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 47771366..4800578 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -183,7 +183,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Toate aplicațiile recente au fost închise."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Deschideți informațiile despre aplicația <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Se inițiază <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificarea a fost închisă."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Fereastră pentru notificări."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Setări rapide."</string>
@@ -347,8 +346,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Divizați ecranul în partea de sus"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Divizați ecranul la stânga"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Divizați ecranul la dreapta"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Încărcată"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Se încarcă"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> până la încărcare completă"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 8465844..f78c3bb 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -184,7 +184,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Все недавние приложения закрыты."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Открыть информацию о приложении \"<xliff:g id="APP">%s</xliff:g>\""</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Запуск приложения <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Уведомление закрыто"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Панель уведомлений"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Быстрые настройки"</string>
@@ -349,8 +348,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Разделить экран по верхнему краю"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Разделить экран по левому краю"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Разделить экран по правому краю"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Батарея заряжена"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Зарядка батареи"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> до полной зарядки"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 5343bb3..bab0c6e 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"සියලුම මෑත යෙඳුම් අස් කරන ලදි."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> යෙදුම් තොරතුරු විවෘත කරයි."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ආරම්භ කරමින්."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"දැනුම්දීම නිෂ්ප්‍රභා කරඇත."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"දැනුම්දීම් ආවරණය."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"ක්ෂණික සැකසීම්."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"තිරය ඉහළට බෙදන්න"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"තිරය වමට බෙදන්න"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"තිරය දකුණට බෙදන්න"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"අරෝපිතයි"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"ආරෝපණය වෙමින්"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> සම්පූර්ණ වන තෙක්"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index db7ea81..4be2941 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -184,7 +184,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Všetky nedávne aplikácie boli odmietnuté."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Otvoriť informácie o aplikácii <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Spúšťa sa aplikácia <xliff:g id="APP">%s</xliff:g>"</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Upozornenie bolo zrušené."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Panel upozornení."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Rýchle nastavenia."</string>
@@ -349,8 +348,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Rozdelená obrazovka hore"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Rozdelená obrazovka naľavo"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Rozdelená obrazovka napravo"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Nabitá"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Nabíja sa"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Úplné nabitie o <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index a50d301..49cbdbf 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -184,7 +184,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Vse nedavne aplikacije so bile opuščene."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Odpiranje podatkov o aplikaciji <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Zaganjanje aplikacije <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obvestilo je bilo odstranjeno."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Zaslon z obvestili."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Hitre nastavitve."</string>
@@ -349,8 +348,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Razdeljen zaslon na vrhu"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Razdeljen zaslon na levi"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Razdeljen zaslon na desni"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Akumulator napolnjen"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Polnjenje"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do napolnjenosti"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index e1f2567..66d692c 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Të gjitha aplikacionet e fundit u larguan."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Hap informacionin e aplikacionit <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Po nis <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Njoftimi është hequr."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Streha e njoftimeve."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Cilësime të shpejta."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Ndaje ekranin lart"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Ndaje ekranin në të majtë"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Ndaje ekranin në të djathtë"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"I ngarkuar"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Po ngarkohet"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> deri sa të mbushet"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index b31eb96..97b9ce4 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -181,7 +181,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Све недавно коришћене апликације су одбачене."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Отворите информације о апликацији <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Покрећемо <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Обавештење је одбачено."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Прозор са обавештењима."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Брза подешавања."</string>
@@ -345,8 +344,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Подели екран нагоре"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Подели екран налево"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Подели екран надесно"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Напуњена је"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Пуњење"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> док се не напуни"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 86b5c0cad..88b93aa 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alla appar har tagits bort från listan Senaste."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Öppna appinformation för <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Startar <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Meddelandet ignorerades."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Meddelandepanel."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Snabbinställningar."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Delad skärm till överkanten"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Delad skärm åt vänster"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Delad skärm åt höger"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Laddat"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Laddar"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> tills batteriet är fulladdat"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index b8878f5..524faea 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Programu za hivi majuzi zimeondolewa."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Fungua maelezo kuhusu programu ya <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Inaanzisha <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Arifa imetupwa."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Kivuli cha arifa."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Mipangilio ya haraka."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Gawa skrini kuelekea juu"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Gawa skrini upande wa kushoto"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Gawa skrini upande wa kulia"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Betri imejaa"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Inachaji"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Imebakisha <xliff:g id="CHARGING_TIME">%s</xliff:g> ijae"</string>
@@ -728,7 +725,7 @@
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Buruta ili uondoe"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menyu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> iko katika hali ya picha ndani ya picha nyingine"</string>
-    <string name="pip_notification_message" msgid="5619512781514343311">"Ikiwa hutaki <xliff:g id="NAME">%s</xliff:g> itumie kipengele hiki, gonga ili ufungue mipangilio na uizime."</string>
+    <string name="pip_notification_message" msgid="5619512781514343311">"Ikiwa hutaki <xliff:g id="NAME">%s</xliff:g> itumie kipengele hiki, gusa ili ufungue mipangilio na uizime."</string>
     <string name="pip_play" msgid="1417176722760265888">"Cheza"</string>
     <string name="pip_pause" msgid="8881063404466476571">"Sitisha"</string>
     <string name="pip_skip_to_next" msgid="1948440006726306284">"Ruka ufikie inayofuata"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index a46facf..ada5d4b 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"எல்லா சமீபத்திய பயன்பாடுகளும் விலக்கப்பட்டன."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> பயன்பாட்டின் தகவலைத் திற."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ஐத் தொடங்குகிறது."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"அறிவிப்பு நிராகரிக்கப்பட்டது."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"அறிவிப்பு விவரம்."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"உடனடி அமைப்பு."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"திரையை மேல்புறமாகப் பிரி"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"திரையை இடப்புறமாகப் பிரி"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"திரையை வலப்புறமாகப் பிரி"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"சார்ஜ் செய்யப்பட்டது"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"சார்ஜ் ஆகிறது"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"முழுவதும் சார்ஜாக <xliff:g id="CHARGING_TIME">%s</xliff:g> ஆகும்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 2c32fab..f23e169 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"అన్ని ఇటీవలి అనువర్తనాలు తీసివేయబడ్డాయి."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> అనువర్తన సమాచారాన్ని తెరుస్తుంది."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>ని ప్రారంభిస్తోంది."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"నోటిఫికేషన్ తీసివేయబడింది."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"నోటిఫికేషన్ షేడ్."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"శీఘ్ర సెట్టింగ్‌లు."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"స్క్రీన్‌ని ఎగువకు విభజించు"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"స్క్రీన్‌ని ఎడమ వైపుకి విభజించు"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"స్క్రీన్‌ని కుడి వైపుకి విభజించు"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ఛార్జ్ చేయబడింది"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"ఛార్జ్ అవుతోంది"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"పూర్తిగా నిండటానికి <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index ad39fea..5f577f6 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ปิดแอปพลิเคชันล่าสุดทั้งหมดแล้ว"</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"เปิดข้อมูลแอปพลิเคชัน <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"กำลังเริ่มต้น <xliff:g id="APP">%s</xliff:g>"</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"ปิดการแจ้งเตือนแล้ว"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"หน้าต่างแจ้งเตือน"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"การตั้งค่าด่วน"</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"แยกหน้าจอไปด้านบน"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"แยกหน้าจอไปทางซ้าย"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"แยกหน้าจอไปทางขวา"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ชาร์จแล้ว"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"กำลังชาร์จ"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"อีก <xliff:g id="CHARGING_TIME">%s</xliff:g> จึงจะเต็ม"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 261bccf..fa79f7c 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Na-dismiss ang lahat ng kamakailang application."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Buksan ang impormasyon ng <xliff:g id="APP">%s</xliff:g> application."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Sinisimulan ang <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Na-dismiss ang notification."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Notification shade."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Mga mabilisang setting."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"I-split ang screen pataas"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"I-split ang screen pakaliwa"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"I-split ang screen pakanan"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Nasingil na"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Nagcha-charge"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> hanggang mapuno"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 450a310..3a5ab8c 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Tüm son uygulamalar kapatıldı."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> uygulaması bilgilerini açın."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> başlatılıyor."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Bildirim kapatıldı."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Bildirim gölgesi."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Hızlı ayarlar."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Ekranı yukarıya doğru böl"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Ekranı sola doğru böl"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Ekranı sağa doğru böl"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Ödeme alındı"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Şarj oluyor"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Tam şarj olmasına <xliff:g id="CHARGING_TIME">%s</xliff:g> kaldı"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index cc14af6..1e3ebb2 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -184,7 +184,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Усі останні додатки закрито."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Відкрити інформацію про додаток <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Запуск додатка <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Сповіщення відхилено."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Панель сповіщень."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Швидке налаштування."</string>
@@ -349,8 +348,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Розділити екран угорі"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Розділити екран ліворуч"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Розділити екран праворуч"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Заряджено"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Заряджається"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"До повного зарядження <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index aa2eee4..7f17182 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"سبھی حالیہ ایپلیکیشنز کو برخاست کر دیا گیا۔"</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> ایپلیکیشن معلومات کھولیں۔"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> شروع ہو رہی ہے۔"</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"اطلاع مسترد ہوگئی۔"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"اطلاعاتی شیڈ۔"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"فوری ترتیبات۔"</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"اسکرین کو اوپر کی جانب تقسیم کریں"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"اسکرین کو بائیں جانب تقسیم کریں"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"اسکرین کو دائیں جانب تقسیم کریں"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"چارج ہوگئی"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"چارج ہو رہی ہے"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> مکمل ہونے تک"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index b8cf046..7e4de64 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -182,7 +182,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Yaqinda ishlatilgan barcha ilovalar olib tashlandi."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> ilovasi haqidagi ma’lumotlarni ochadi."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ishga tushirilmoqda."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Xabarnoma e‘tiborsiz qoldirildi."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Xabarnoma soyasi."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Tezkor sozlamalar."</string>
@@ -345,8 +344,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Ekranni tepaga qadash"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Ekranni chap tomonga qadash"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Ekranni o‘ng tomonga qadash"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Batareya quvvati to‘ldi"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Quvvat olmoqda"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g>da to‘ladi"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 5b5cc61..36e76fe 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Đã bỏ qua tất cả các ứng dụng gần đây."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Mở thông tin ứng dụng <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Bắt đầu <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Đã loại bỏ thông báo."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Bóng thông báo."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Cài đặt nhanh."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Chia đôi màn hình lên trên"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Chia đôi màn hình sang trái"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Chia đôi màn hình sang phải"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Đã sạc đầy"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Đang sạc"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> cho đến khi đầy"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 38c501b..e179c5d 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"已关闭所有最近用过的应用。"</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"打开<xliff:g id="APP">%s</xliff:g>应用信息。"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"正在启动<xliff:g id="APP">%s</xliff:g>。"</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"已关闭通知。"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"通知栏。"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"快捷设置。"</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"将屏幕分隔线移到上方"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"将屏幕分隔线移到左侧"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"将屏幕分隔线移到右侧"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"已充满"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"正在充电"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"还需<xliff:g id="CHARGING_TIME">%s</xliff:g>充满"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 3a42827..b34ff37 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -182,7 +182,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"所有最近使用的應用程式均已關閉。"</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"開啟「<xliff:g id="APP">%s</xliff:g>」應用程式的資料。"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"正在啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g><xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"通知已關閉。"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"通知欄。"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"快速設定。"</string>
@@ -345,8 +344,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"將分割畫面顯示喺頂部"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"將分割畫面顯示喺左邊"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"將分割畫面顯示喺右邊"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"已完成充電"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"充電中"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g>後完成充電"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 2152ae3..13ac5e7 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"最近使用的應用程式已全部關閉。"</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"開啟「<xliff:g id="APP">%s</xliff:g>」應用程式資訊。"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"正在啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"已關閉通知。"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"通知欄。"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"快捷設定。"</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"將分割畫面顯示在頂端"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"將分割畫面顯示在左邊"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"將分割畫面顯示在右邊"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"已充飽"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"充電中"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g>後充飽"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index de61bf5..695adf8 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -180,7 +180,6 @@
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Zonke izinhlelo zokusebenza zakamuva zicashisiwe."</string>
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Vula ulwazi lohlelo lokusebenza le-<xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iqala i-<xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Isaziso sichithiwe."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Umthunzi wesaziso."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Izilingiselelo ezisheshayo."</string>
@@ -343,8 +342,6 @@
     <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Hlukanisela isikrini phezulu"</string>
     <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Hlukanisela isikrini ngakwesokunxele"</string>
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Hlukanisela isikrini ngakwesokudla"</string>
-  <string-array name="recents_blacklist_array">
-  </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Kushajiwe"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Iyashaja"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> ize igcwale"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 8a1e0b9..0fe81d9 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -167,12 +167,6 @@
     <!-- The animation duration for scrolling the stack to a particular item. -->
     <integer name="recents_animate_task_stack_scroll_duration">200</integer>
 
-    <!-- The animation duration for scrolling the stack to a particular item. -->
-    <integer name="recents_auto_advance_duration">750</integer>
-
-    <!-- The animation duration for subsequent scrolling the stack to a particular item. -->
-    <integer name="recents_subsequent_auto_advance_duration">1000</integer>
-
     <!-- The delay to enforce between each alt-tab key press. -->
     <integer name="recents_alt_tab_key_delay">200</integer>
 
@@ -328,7 +322,7 @@
     <integer name="config_showTemperatureWarning">0</integer>
 
     <!-- Temp at which to show a warning notification if config_showTemperatureWarning is true.
-         If < 0, uses the value from
+         If < 0, uses the skin temperature sensor shutdown value from
          HardwarePropertiesManager#getDeviceTemperatures - config_warningTemperatureTolerance. -->
     <integer name="config_warningTemperature">-1</integer>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 7ccb6b0..1536b64 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -451,8 +451,6 @@
     <string name="accessibility_recents_item_open_app_info">Open <xliff:g id="app" example="Calendar">%s</xliff:g> application info.</string>
     <!-- Content description to tell the user an application has been launched from recents -->
     <string name="accessibility_recents_item_launched">Starting <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
-    <!-- Content description of individual recents task. -->
-    <string name="accessibility_recents_task_header"><xliff:g id="app" example="Chrome">%1$s</xliff:g> <xliff:g id="activity_label" example="www.google.com">%2$s</xliff:g></string>
     <!-- Content description to tell the user a notification has been removed from the notification shade -->
     <string name="accessibility_notification_dismissed">Notification dismissed.</string>
 
@@ -810,10 +808,6 @@
     <!-- Recents: Accessibility split to the right -->
     <string name="recents_accessibility_split_screen_right">Split screen to the right</string>
 
-    <!-- Fully qualified activity class names to be blacklisted in Recents, add package names into overlay as needed -->
-    <string-array name="recents_blacklist_array">
-    </string-array>
-
     <!-- Expanded Status Bar Header: Battery Charged [CHAR LIMIT=40] -->
     <string name="expanded_header_battery_charged">Charged</string>
 
diff --git a/packages/SystemUI/shared/Android.mk b/packages/SystemUI/shared/Android.mk
new file mode 100644
index 0000000..88a89bc
--- /dev/null
+++ b/packages/SystemUI/shared/Android.mk
@@ -0,0 +1,42 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_USE_AAPT2 := true
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE := SystemUISharedLib
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_JAR_EXCLUDE_FILES := none
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := SharedDummyLib
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := SystemUISharedLib
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/packages/SystemUI/shared/AndroidManifest.xml b/packages/SystemUI/shared/AndroidManifest.xml
new file mode 100644
index 0000000..43b9c75
--- /dev/null
+++ b/packages/SystemUI/shared/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.systemui.shared">
+
+    <uses-sdk
+        android:minSdkVersion="26" />
+
+</manifest>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/BackgroundTaskLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/BackgroundTaskLoader.java
new file mode 100644
index 0000000..ddd27b0
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/BackgroundTaskLoader.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.shared.recents.model;
+
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.Log;
+
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.PackageManagerWrapper;
+
+/**
+ * Background task resource loader
+ */
+class BackgroundTaskLoader implements Runnable {
+    static String TAG = "BackgroundTaskLoader";
+    static boolean DEBUG = false;
+
+    private Context mContext;
+    private final HandlerThread mLoadThread;
+    private final Handler mLoadThreadHandler;
+    private final Handler mMainThreadHandler;
+
+    private final TaskResourceLoadQueue mLoadQueue;
+    private final TaskKeyLruCache<Drawable> mIconCache;
+    private final BitmapDrawable mDefaultIcon;
+
+    private boolean mStarted;
+    private boolean mCancelled;
+    private boolean mWaitingOnLoadQueue;
+
+    private final OnIdleChangedListener mOnIdleChangedListener;
+
+    /** Constructor, creates a new loading thread that loads task resources in the background */
+    public BackgroundTaskLoader(TaskResourceLoadQueue loadQueue,
+            TaskKeyLruCache<Drawable> iconCache, BitmapDrawable defaultIcon,
+            OnIdleChangedListener onIdleChangedListener) {
+        mLoadQueue = loadQueue;
+        mIconCache = iconCache;
+        mDefaultIcon = defaultIcon;
+        mMainThreadHandler = new Handler();
+        mOnIdleChangedListener = onIdleChangedListener;
+        mLoadThread = new HandlerThread("Recents-TaskResourceLoader",
+                android.os.Process.THREAD_PRIORITY_BACKGROUND);
+        mLoadThread.start();
+        mLoadThreadHandler = new Handler(mLoadThread.getLooper());
+    }
+
+    /** Restarts the loader thread */
+    void start(Context context) {
+        mContext = context;
+        mCancelled = false;
+        if (!mStarted) {
+            // Start loading on the load thread
+            mStarted = true;
+            mLoadThreadHandler.post(this);
+        } else {
+            // Notify the load thread to start loading again
+            synchronized (mLoadThread) {
+                mLoadThread.notifyAll();
+            }
+        }
+    }
+
+    /** Requests the loader thread to stop after the current iteration */
+    void stop() {
+        // Mark as cancelled for the thread to pick up
+        mCancelled = true;
+        // If we are waiting for the load queue for more tasks, then we can just reset the
+        // Context now, since nothing is using it
+        if (mWaitingOnLoadQueue) {
+            mContext = null;
+        }
+    }
+
+    @Override
+    public void run() {
+        while (true) {
+            if (mCancelled) {
+                // We have to unset the context here, since the background thread may be using it
+                // when we call stop()
+                mContext = null;
+                // If we are cancelled, then wait until we are started again
+                synchronized(mLoadThread) {
+                    try {
+                        mLoadThread.wait();
+                    } catch (InterruptedException ie) {
+                        ie.printStackTrace();
+                    }
+                }
+            } else {
+                // If we've stopped the loader, then fall through to the above logic to wait on
+                // the load thread
+                processLoadQueueItem();
+
+                // If there are no other items in the list, then just wait until something is added
+                if (!mCancelled && mLoadQueue.isEmpty()) {
+                    synchronized(mLoadQueue) {
+                        try {
+                            mWaitingOnLoadQueue = true;
+                            mMainThreadHandler.post(
+                                    () -> mOnIdleChangedListener.onIdleChanged(true));
+                            mLoadQueue.wait();
+                            mMainThreadHandler.post(
+                                    () -> mOnIdleChangedListener.onIdleChanged(false));
+                            mWaitingOnLoadQueue = false;
+                        } catch (InterruptedException ie) {
+                            ie.printStackTrace();
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * This needs to be in a separate method to work around an surprising interpreter behavior:
+     * The register will keep the local reference to cachedThumbnailData even if it falls out of
+     * scope. Putting it into a method fixes this issue.
+     */
+    private void processLoadQueueItem() {
+        // Load the next item from the queue
+        final Task t = mLoadQueue.nextTask();
+        if (t != null) {
+            Drawable cachedIcon = mIconCache.get(t.key);
+
+            // Load the icon if it is stale or we haven't cached one yet
+            if (cachedIcon == null) {
+                cachedIcon = ActivityManagerWrapper.getInstance().getBadgedTaskDescriptionIcon(
+                        mContext, t.taskDescription, t.key.userId, mContext.getResources());
+
+                if (cachedIcon == null) {
+                    ActivityInfo info = PackageManagerWrapper.getInstance().getActivityInfo(
+                            t.key.getComponent(), t.key.userId);
+                    if (info != null) {
+                        if (DEBUG) Log.d(TAG, "Loading icon: " + t.key);
+                        cachedIcon = ActivityManagerWrapper.getInstance().getBadgedActivityIcon(
+                                info, t.key.userId);
+                    }
+                }
+
+                if (cachedIcon == null) {
+                    cachedIcon = mDefaultIcon;
+                }
+
+                // At this point, even if we can't load the icon, we will set the
+                // default icon.
+                mIconCache.put(t.key, cachedIcon);
+            }
+
+            if (DEBUG) Log.d(TAG, "Loading thumbnail: " + t.key);
+            final ThumbnailData thumbnailData =
+                    ActivityManagerWrapper.getInstance().getTaskThumbnail(t.key.id,
+                            true /* reducedResolution */);
+
+            if (!mCancelled) {
+                // Notify that the task data has changed
+                final Drawable finalIcon = cachedIcon;
+                mMainThreadHandler.post(
+                        () -> t.notifyTaskDataLoaded(thumbnailData, finalIcon));
+            }
+        }
+    }
+
+    interface OnIdleChangedListener {
+        void onIdleChanged(boolean idle);
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/FilteredTaskList.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/FilteredTaskList.java
new file mode 100644
index 0000000..898d64a
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/FilteredTaskList.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.shared.recents.model;
+
+import android.util.ArrayMap;
+import android.util.SparseArray;
+
+import com.android.systemui.shared.recents.model.Task.TaskKey;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A list of filtered tasks.
+ */
+class FilteredTaskList {
+
+    private final ArrayList<Task> mTasks = new ArrayList<>();
+    private final ArrayList<Task> mFilteredTasks = new ArrayList<>();
+    private final ArrayMap<TaskKey, Integer> mFilteredTaskIndices = new ArrayMap<>();
+    private TaskFilter mFilter;
+
+    /** Sets the task filter, and returns whether the set of filtered tasks have changed. */
+    boolean setFilter(TaskFilter filter) {
+        ArrayList<Task> prevFilteredTasks = new ArrayList<>(mFilteredTasks);
+        mFilter = filter;
+        updateFilteredTasks();
+        return !prevFilteredTasks.equals(mFilteredTasks);
+    }
+
+    /** Adds a new task to the task list */
+    void add(Task t) {
+        mTasks.add(t);
+        updateFilteredTasks();
+    }
+
+    /** Sets the list of tasks */
+    void set(List<Task> tasks) {
+        mTasks.clear();
+        mTasks.addAll(tasks);
+        updateFilteredTasks();
+    }
+
+    /** Removes a task from the base list only if it is in the filtered list */
+    boolean remove(Task t) {
+        if (mFilteredTasks.contains(t)) {
+            boolean removed = mTasks.remove(t);
+            updateFilteredTasks();
+            return removed;
+        }
+        return false;
+    }
+
+    /** Returns the index of this task in the list of filtered tasks */
+    int indexOf(Task t) {
+        if (t != null && mFilteredTaskIndices.containsKey(t.key)) {
+            return mFilteredTaskIndices.get(t.key);
+        }
+        return -1;
+    }
+
+    /** Returns the size of the list of filtered tasks */
+    int size() {
+        return mFilteredTasks.size();
+    }
+
+    /** Returns whether the filtered list contains this task */
+    boolean contains(Task t) {
+        return mFilteredTaskIndices.containsKey(t.key);
+    }
+
+    /** Updates the list of filtered tasks whenever the base task list changes */
+    private void updateFilteredTasks() {
+        mFilteredTasks.clear();
+        if (mFilter != null) {
+            // Create a sparse array from task id to Task
+            SparseArray<Task> taskIdMap = new SparseArray<>();
+            int taskCount = mTasks.size();
+            for (int i = 0; i < taskCount; i++) {
+                Task t = mTasks.get(i);
+                taskIdMap.put(t.key.id, t);
+            }
+
+            for (int i = 0; i < taskCount; i++) {
+                Task t = mTasks.get(i);
+                if (mFilter.acceptTask(taskIdMap, t, i)) {
+                    mFilteredTasks.add(t);
+                }
+            }
+        } else {
+            mFilteredTasks.addAll(mTasks);
+        }
+        updateFilteredTaskIndices();
+    }
+
+    /** Updates the mapping of tasks to indices. */
+    private void updateFilteredTaskIndices() {
+        int taskCount = mFilteredTasks.size();
+        mFilteredTaskIndices.clear();
+        for (int i = 0; i < taskCount; i++) {
+            Task t = mFilteredTasks.get(i);
+            mFilteredTaskIndices.put(t.key, i);
+        }
+    }
+
+    /** Returns the list of filtered tasks */
+    ArrayList<Task> getTasks() {
+        return mFilteredTasks;
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/HighResThumbnailLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/HighResThumbnailLoader.java
new file mode 100644
index 0000000..24ba998
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/HighResThumbnailLoader.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.shared.recents.model;
+
+import static android.os.Process.setThreadPriority;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.shared.recents.model.Task.TaskCallbacks;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+
+/**
+ * Loader class that loads full-resolution thumbnails when appropriate.
+ */
+public class HighResThumbnailLoader implements TaskCallbacks {
+
+    private final ActivityManagerWrapper mActivityManager;
+
+    @GuardedBy("mLoadQueue")
+    private final ArrayDeque<Task> mLoadQueue = new ArrayDeque<>();
+    @GuardedBy("mLoadQueue")
+    private final ArraySet<Task> mLoadingTasks = new ArraySet<>();
+    @GuardedBy("mLoadQueue")
+    private boolean mLoaderIdling;
+
+    private final ArrayList<Task> mVisibleTasks = new ArrayList<>();
+
+    private final Thread mLoadThread;
+    private final Handler mMainThreadHandler;
+    private final boolean mIsLowRamDevice;
+    private boolean mLoading;
+    private boolean mVisible;
+    private boolean mFlingingFast;
+    private boolean mTaskLoadQueueIdle;
+
+    public HighResThumbnailLoader(ActivityManagerWrapper activityManager, Looper looper,
+            boolean isLowRamDevice) {
+        mActivityManager = activityManager;
+        mMainThreadHandler = new Handler(looper);
+        mLoadThread = new Thread(mLoader, "Recents-HighResThumbnailLoader");
+        mLoadThread.start();
+        mIsLowRamDevice = isLowRamDevice;
+    }
+
+    public void setVisible(boolean visible) {
+        if (mIsLowRamDevice) {
+            return;
+        }
+        mVisible = visible;
+        updateLoading();
+    }
+
+    public void setFlingingFast(boolean flingingFast) {
+        if (mFlingingFast == flingingFast || mIsLowRamDevice) {
+            return;
+        }
+        mFlingingFast = flingingFast;
+        updateLoading();
+    }
+
+    /**
+     * Sets whether the other task load queue is idling. Avoid double-loading bitmaps by not
+     * starting this queue until the other queue is idling.
+     */
+    public void setTaskLoadQueueIdle(boolean idle) {
+        if (mIsLowRamDevice) {
+            return;
+        }
+        mTaskLoadQueueIdle = idle;
+        updateLoading();
+    }
+
+    @VisibleForTesting
+    boolean isLoading() {
+        return mLoading;
+    }
+
+    private void updateLoading() {
+        setLoading(mVisible && !mFlingingFast && mTaskLoadQueueIdle);
+    }
+
+    private void setLoading(boolean loading) {
+        if (loading == mLoading) {
+            return;
+        }
+        synchronized (mLoadQueue) {
+            mLoading = loading;
+            if (!loading) {
+                stopLoading();
+            } else {
+                startLoading();
+            }
+        }
+    }
+
+    @GuardedBy("mLoadQueue")
+    private void startLoading() {
+        for (int i = mVisibleTasks.size() - 1; i >= 0; i--) {
+            Task t = mVisibleTasks.get(i);
+            if ((t.thumbnail == null || t.thumbnail.reducedResolution)
+                    && !mLoadQueue.contains(t) && !mLoadingTasks.contains(t)) {
+                mLoadQueue.add(t);
+            }
+        }
+        mLoadQueue.notifyAll();
+    }
+
+    @GuardedBy("mLoadQueue")
+    private void stopLoading() {
+        mLoadQueue.clear();
+        mLoadQueue.notifyAll();
+    }
+
+    /**
+     * Needs to be called when a task becomes visible. Note that this is different from
+     * {@link TaskCallbacks#onTaskDataLoaded} as this method should only be called once when it
+     * becomes visible, whereas onTaskDataLoaded can be called multiple times whenever some data
+     * has been updated.
+     */
+    public void onTaskVisible(Task t) {
+        t.addCallback(this);
+        mVisibleTasks.add(t);
+        if ((t.thumbnail == null || t.thumbnail.reducedResolution) && mLoading) {
+            synchronized (mLoadQueue) {
+                mLoadQueue.add(t);
+                mLoadQueue.notifyAll();
+            }
+        }
+    }
+
+    /**
+     * Needs to be called when a task becomes visible. See {@link #onTaskVisible} why this is
+     * different from {@link TaskCallbacks#onTaskDataUnloaded()}
+     */
+    public void onTaskInvisible(Task t) {
+        t.removeCallback(this);
+        mVisibleTasks.remove(t);
+        synchronized (mLoadQueue) {
+            mLoadQueue.remove(t);
+        }
+    }
+
+    @VisibleForTesting
+    void waitForLoaderIdle() {
+        while (true) {
+            synchronized (mLoadQueue) {
+                if (mLoadQueue.isEmpty() && mLoaderIdling) {
+                    return;
+                }
+            }
+            SystemClock.sleep(100);
+        }
+    }
+
+    @Override
+    public void onTaskDataLoaded(Task task, ThumbnailData thumbnailData) {
+        if (thumbnailData != null && !thumbnailData.reducedResolution) {
+            synchronized (mLoadQueue) {
+                mLoadQueue.remove(task);
+            }
+        }
+    }
+
+    @Override
+    public void onTaskDataUnloaded() {
+    }
+
+    @Override
+    public void onTaskWindowingModeChanged() {
+    }
+
+    private final Runnable mLoader = new Runnable() {
+
+        @Override
+        public void run() {
+            setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND + 1);
+            while (true) {
+                Task next = null;
+                synchronized (mLoadQueue) {
+                    if (!mLoading || mLoadQueue.isEmpty()) {
+                        try {
+                            mLoaderIdling = true;
+                            mLoadQueue.wait();
+                            mLoaderIdling = false;
+                        } catch (InterruptedException e) {
+                            // Don't care.
+                        }
+                    } else {
+                        next = mLoadQueue.poll();
+                        if (next != null) {
+                            mLoadingTasks.add(next);
+                        }
+                    }
+                }
+                if (next != null) {
+                    loadTask(next);
+                }
+            }
+        }
+
+        private void loadTask(Task t) {
+            ThumbnailData thumbnail = mActivityManager.getTaskThumbnail(t.key.id,
+                    false /* reducedResolution */);
+            mMainThreadHandler.post(() -> {
+                synchronized (mLoadQueue) {
+                    mLoadingTasks.remove(t);
+                }
+                if (mVisibleTasks.contains(t)) {
+                    t.notifyTaskDataLoaded(thumbnail, t.icon);
+                }
+            });
+        }
+    };
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
new file mode 100644
index 0000000..806a073
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.recents.model;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+
+import android.app.ActivityManager;
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.util.SparseBooleanArray;
+
+import com.android.systemui.shared.recents.model.Task.TaskKey;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+
+/**
+ * This class stores the loading state as it goes through multiple stages of loading:
+ *   1) preloadRawTasks() will load the raw set of recents tasks from the system
+ *   2) preloadPlan() will construct a new task stack with all metadata and only icons and
+ *      thumbnails that are currently in the cache
+ *   3) executePlan() will actually load and fill in the icons and thumbnails according to the load
+ *      options specified, such that we can transition into the Recents activity seamlessly
+ */
+public class RecentsTaskLoadPlan {
+
+    /** The set of conditions to load tasks. */
+    public static class Options {
+        public int runningTaskId = -1;
+        public boolean loadIcons = true;
+        public boolean loadThumbnails = false;
+        public boolean onlyLoadForCache = false;
+        public boolean onlyLoadPausedActivities = false;
+        public int numVisibleTasks = 0;
+        public int numVisibleTaskThumbnails = 0;
+    }
+
+    private final Context mContext;
+    private final KeyguardManager mKeyguardManager;
+
+    private List<ActivityManager.RecentTaskInfo> mRawTasks;
+    private TaskStack mStack;
+
+    private final SparseBooleanArray mTmpLockedUsers = new SparseBooleanArray();
+
+    public RecentsTaskLoadPlan(Context context) {
+        mContext = context;
+        mKeyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
+    }
+
+    /**
+     * An optimization to preload the raw list of tasks. The raw tasks are saved in least-recent
+     * to most-recent order.
+     *
+     * Note: Do not lock, callers should synchronize on the loader before making this call.
+     */
+    void preloadRawTasks() {
+        int currentUserId = ActivityManagerWrapper.getInstance().getCurrentUserId();
+        mRawTasks = ActivityManagerWrapper.getInstance().getRecentTasks(
+                ActivityManager.getMaxRecentTasksStatic(), currentUserId);
+
+        // Since the raw tasks are given in most-recent to least-recent order, we need to reverse it
+        Collections.reverse(mRawTasks);
+    }
+
+    /**
+     * Preloads the list of recent tasks from the system. After this call, the TaskStack will
+     * have a list of all the recent tasks with their metadata, not including icons or
+     * thumbnails which were not cached and have to be loaded.
+     *
+     * The tasks will be ordered by:
+     * - least-recent to most-recent stack tasks
+     *
+     * Note: Do not lock, since this can be calling back to the loader, which separately also drives
+     * this call (callers should synchronize on the loader before making this call).
+     */
+    void preloadPlan(RecentsTaskLoader loader, int runningTaskId) {
+        Resources res = mContext.getResources();
+        ArrayList<Task> allTasks = new ArrayList<>();
+        if (mRawTasks == null) {
+            preloadRawTasks();
+        }
+
+        int taskCount = mRawTasks.size();
+        for (int i = 0; i < taskCount; i++) {
+            ActivityManager.RecentTaskInfo t = mRawTasks.get(i);
+
+            // Compose the task key
+            final int windowingMode = t.configuration.windowConfiguration.getWindowingMode();
+            TaskKey taskKey = new TaskKey(t.persistentId, windowingMode, t.baseIntent,
+                    t.userId, t.lastActiveTime);
+
+            boolean isFreeformTask = windowingMode == WINDOWING_MODE_FREEFORM;
+            boolean isStackTask = !isFreeformTask;
+            boolean isLaunchTarget = taskKey.id == runningTaskId;
+
+            ActivityInfo info = loader.getAndUpdateActivityInfo(taskKey);
+            if (info == null) {
+                continue;
+            }
+
+            // Load the title, icon, and color
+            String title = loader.getAndUpdateActivityTitle(taskKey, t.taskDescription);
+            String titleDescription = loader.getAndUpdateContentDescription(taskKey,
+                    t.taskDescription);
+            Drawable icon = isStackTask
+                    ? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, res, false)
+                    : null;
+            ThumbnailData thumbnail = loader.getAndUpdateThumbnail(taskKey,
+                    false /* loadIfNotCached */, false /* storeInCache */);
+            int activityColor = loader.getActivityPrimaryColor(t.taskDescription);
+            int backgroundColor = loader.getActivityBackgroundColor(t.taskDescription);
+            boolean isSystemApp = (info != null) &&
+                    ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
+
+            // TODO: Refactor to not do this every preload
+            if (mTmpLockedUsers.indexOfKey(t.userId) < 0) {
+                mTmpLockedUsers.put(t.userId, mKeyguardManager.isDeviceLocked(t.userId));
+            }
+            boolean isLocked = mTmpLockedUsers.get(t.userId);
+
+            // Add the task to the stack
+            Task task = new Task(taskKey, icon,
+                    thumbnail, title, titleDescription, activityColor, backgroundColor,
+                    isLaunchTarget, isStackTask, isSystemApp, t.supportsSplitScreenMultiWindow,
+                    t.taskDescription, t.resizeMode, t.topActivity, isLocked);
+
+            allTasks.add(task);
+        }
+
+        // Initialize the stacks
+        mStack = new TaskStack();
+        mStack.setTasks(allTasks, false /* notifyStackChanges */);
+    }
+
+    /**
+     * Called to apply the actual loading based on the specified conditions.
+     *
+     * Note: Do not lock, since this can be calling back to the loader, which separately also drives
+     * this call (callers should synchronize on the loader before making this call).
+     */
+    void executePlan(Options opts, RecentsTaskLoader loader) {
+        Resources res = mContext.getResources();
+
+        // Iterate through each of the tasks and load them according to the load conditions.
+        ArrayList<Task> tasks = mStack.getStackTasks();
+        int taskCount = tasks.size();
+        for (int i = 0; i < taskCount; i++) {
+            Task task = tasks.get(i);
+            TaskKey taskKey = task.key;
+
+            boolean isRunningTask = (task.key.id == opts.runningTaskId);
+            boolean isVisibleTask = i >= (taskCount - opts.numVisibleTasks);
+            boolean isVisibleThumbnail = i >= (taskCount - opts.numVisibleTaskThumbnails);
+
+            // If requested, skip the running task
+            if (opts.onlyLoadPausedActivities && isRunningTask) {
+                continue;
+            }
+
+            if (opts.loadIcons && (isRunningTask || isVisibleTask)) {
+                if (task.icon == null) {
+                    task.icon = loader.getAndUpdateActivityIcon(taskKey, task.taskDescription, res,
+                            true);
+                }
+            }
+            if (opts.loadThumbnails && isVisibleThumbnail) {
+                task.thumbnail = loader.getAndUpdateThumbnail(taskKey,
+                        true /* loadIfNotCached */, true /* storeInCache */);
+            }
+        }
+    }
+
+    /**
+     * Returns the TaskStack from the preloaded list of recent tasks.
+     */
+    public TaskStack getTaskStack() {
+        return mStack;
+    }
+
+    /** Returns whether there are any tasks in any stacks. */
+    public boolean hasTasks() {
+        if (mStack != null) {
+            return mStack.getTaskCount() > 0;
+        }
+        return false;
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
new file mode 100644
index 0000000..de4c72c
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.recents.model;
+
+import android.app.ActivityManager;
+import android.content.ComponentCallbacks2;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Looper;
+import android.os.Trace;
+import android.util.Log;
+import android.util.LruCache;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan.Options;
+import com.android.systemui.shared.recents.model.Task.TaskKey;
+import com.android.systemui.shared.recents.model.TaskKeyLruCache.EvictionCallback;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.PackageManagerWrapper;
+
+import java.io.PrintWriter;
+import java.util.Map;
+
+
+/**
+ * Recents task loader
+ */
+public class RecentsTaskLoader {
+    private static final String TAG = "RecentsTaskLoader";
+    private static final boolean DEBUG = false;
+
+    /** Levels of svelte in increasing severity/austerity. */
+    // No svelting.
+    public static final int SVELTE_NONE = 0;
+    // Limit thumbnail cache to number of visible thumbnails when Recents was loaded, disable
+    // caching thumbnails as you scroll.
+    public static final int SVELTE_LIMIT_CACHE = 1;
+    // Disable the thumbnail cache, load thumbnails asynchronously when the activity loads and
+    // evict all thumbnails when hidden.
+    public static final int SVELTE_DISABLE_CACHE = 2;
+    // Disable all thumbnail loading.
+    public static final int SVELTE_DISABLE_LOADING = 3;
+
+    private final Context mContext;
+
+    // This activity info LruCache is useful because it can be expensive to retrieve ActivityInfos
+    // for many tasks, which we use to get the activity labels and icons.  Unlike the other caches
+    // below, this is per-package so we can't invalidate the items in the cache based on the last
+    // active time.  Instead, we rely on the PackageMonitor to keep us informed whenever a
+    // package in the cache has been updated, so that we may remove it.
+    private final LruCache<ComponentName, ActivityInfo> mActivityInfoCache;
+    private final TaskKeyLruCache<Drawable> mIconCache;
+    private final TaskKeyLruCache<String> mActivityLabelCache;
+    private final TaskKeyLruCache<String> mContentDescriptionCache;
+    private final TaskResourceLoadQueue mLoadQueue;
+    private final BackgroundTaskLoader mLoader;
+    private final HighResThumbnailLoader mHighResThumbnailLoader;
+    @GuardedBy("this")
+    private final TaskKeyStrongCache<ThumbnailData> mThumbnailCache = new TaskKeyStrongCache<>();
+    @GuardedBy("this")
+    private final TaskKeyStrongCache<ThumbnailData> mTempCache = new TaskKeyStrongCache<>();
+    private final int mMaxThumbnailCacheSize;
+    private final int mMaxIconCacheSize;
+    private int mNumVisibleTasksLoaded;
+    private int mSvelteLevel;
+
+    private int mDefaultTaskBarBackgroundColor;
+    private int mDefaultTaskViewBackgroundColor;
+    private final BitmapDrawable mDefaultIcon;
+
+    private EvictionCallback mClearActivityInfoOnEviction = new EvictionCallback() {
+        @Override
+        public void onEntryEvicted(TaskKey key) {
+            if (key != null) {
+                mActivityInfoCache.remove(key.getComponent());
+            }
+        }
+    };
+
+    public RecentsTaskLoader(Context context, int maxThumbnailCacheSize, int maxIconCacheSize,
+            int svelteLevel) {
+        mContext = context;
+        mMaxThumbnailCacheSize = maxThumbnailCacheSize;
+        mMaxIconCacheSize = maxIconCacheSize;
+        mSvelteLevel = svelteLevel;
+
+        // Create the default assets
+        Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
+        icon.eraseColor(0);
+        mDefaultIcon = new BitmapDrawable(context.getResources(), icon);
+
+        // Initialize the proxy, cache and loaders
+        int numRecentTasks = ActivityManager.getMaxRecentTasksStatic();
+        mHighResThumbnailLoader = new HighResThumbnailLoader(ActivityManagerWrapper.getInstance(),
+                Looper.getMainLooper(), ActivityManager.isLowRamDeviceStatic());
+        mLoadQueue = new TaskResourceLoadQueue();
+        mIconCache = new TaskKeyLruCache<>(mMaxIconCacheSize, mClearActivityInfoOnEviction);
+        mActivityLabelCache = new TaskKeyLruCache<>(numRecentTasks, mClearActivityInfoOnEviction);
+        mContentDescriptionCache = new TaskKeyLruCache<>(numRecentTasks,
+                mClearActivityInfoOnEviction);
+        mActivityInfoCache = new LruCache<>(numRecentTasks);
+        mLoader = new BackgroundTaskLoader(mLoadQueue, mIconCache, mDefaultIcon,
+                mHighResThumbnailLoader::setTaskLoadQueueIdle);
+    }
+
+    /**
+     * Sets the default task bar/view colors if none are provided by the app.
+     */
+    public void setDefaultColors(int defaultTaskBarBackgroundColor,
+            int defaultTaskViewBackgroundColor) {
+        mDefaultTaskBarBackgroundColor = defaultTaskBarBackgroundColor;
+        mDefaultTaskViewBackgroundColor = defaultTaskViewBackgroundColor;
+    }
+
+    /** Returns the size of the app icon cache. */
+    public int getIconCacheSize() {
+        return mMaxIconCacheSize;
+    }
+
+    /** Returns the size of the thumbnail cache. */
+    public int getThumbnailCacheSize() {
+        return mMaxThumbnailCacheSize;
+    }
+
+    public HighResThumbnailLoader getHighResThumbnailLoader() {
+        return mHighResThumbnailLoader;
+    }
+
+    /** Preloads recents tasks using the specified plan to store the output. */
+    public synchronized void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId) {
+        try {
+            Trace.beginSection("preloadPlan");
+            plan.preloadPlan(this, runningTaskId);
+        } finally {
+            Trace.endSection();
+        }
+    }
+
+    /** Begins loading the heavy task data according to the specified options. */
+    public synchronized void loadTasks(RecentsTaskLoadPlan plan, Options opts) {
+        if (opts == null) {
+            throw new RuntimeException("Requires load options");
+        }
+        if (opts.onlyLoadForCache && opts.loadThumbnails) {
+            // If we are loading for the cache, we'd like to have the real cache only include the
+            // visible thumbnails. However, we also don't want to reload already cached thumbnails.
+            // Thus, we copy over the current entries into a second cache, and clear the real cache,
+            // such that the real cache only contains visible thumbnails.
+            mTempCache.copyEntries(mThumbnailCache);
+            mThumbnailCache.evictAll();
+        }
+        plan.executePlan(opts, this);
+        mTempCache.evictAll();
+        if (!opts.onlyLoadForCache) {
+            mNumVisibleTasksLoaded = opts.numVisibleTasks;
+        }
+    }
+
+    /**
+     * Acquires the task resource data directly from the cache, loading if necessary.
+     */
+    public void loadTaskData(Task t) {
+        Drawable icon = mIconCache.getAndInvalidateIfModified(t.key);
+        icon = icon != null ? icon : mDefaultIcon;
+        mLoadQueue.addTask(t);
+        t.notifyTaskDataLoaded(t.thumbnail, icon);
+    }
+
+    /** Releases the task resource data back into the pool. */
+    public void unloadTaskData(Task t) {
+        mLoadQueue.removeTask(t);
+        t.notifyTaskDataUnloaded(mDefaultIcon);
+    }
+
+    /** Completely removes the resource data from the pool. */
+    public void deleteTaskData(Task t, boolean notifyTaskDataUnloaded) {
+        mLoadQueue.removeTask(t);
+        mIconCache.remove(t.key);
+        mActivityLabelCache.remove(t.key);
+        mContentDescriptionCache.remove(t.key);
+        if (notifyTaskDataUnloaded) {
+            t.notifyTaskDataUnloaded(mDefaultIcon);
+        }
+    }
+
+    /**
+     * Handles signals from the system, trimming memory when requested to prevent us from running
+     * out of memory.
+     */
+    public synchronized void onTrimMemory(int level) {
+        switch (level) {
+            case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
+                // Stop the loader immediately when the UI is no longer visible
+                stopLoader();
+                mIconCache.trimToSize(Math.max(mNumVisibleTasksLoaded,
+                        mMaxIconCacheSize / 2));
+                break;
+            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
+            case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
+                // We are leaving recents, so trim the data a bit
+                mIconCache.trimToSize(Math.max(1, mMaxIconCacheSize / 2));
+                mActivityInfoCache.trimToSize(Math.max(1,
+                        ActivityManager.getMaxRecentTasksStatic() / 2));
+                break;
+            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
+            case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
+                // We are going to be low on memory
+                mIconCache.trimToSize(Math.max(1, mMaxIconCacheSize / 4));
+                mActivityInfoCache.trimToSize(Math.max(1,
+                        ActivityManager.getMaxRecentTasksStatic() / 4));
+                break;
+            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
+            case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
+                // We are low on memory, so release everything
+                mIconCache.evictAll();
+                mActivityInfoCache.evictAll();
+                // The cache is small, only clear the label cache when we are critical
+                mActivityLabelCache.evictAll();
+                mContentDescriptionCache.evictAll();
+                mThumbnailCache.evictAll();
+                break;
+            default:
+                break;
+        }
+    }
+
+    public void onPackageChanged(String packageName) {
+        // Remove all the cached activity infos for this package.  The other caches do not need to
+        // be pruned at this time, as the TaskKey expiration checks will flush them next time their
+        // cached contents are requested
+        Map<ComponentName, ActivityInfo> activityInfoCache = mActivityInfoCache.snapshot();
+        for (ComponentName cn : activityInfoCache.keySet()) {
+            if (cn.getPackageName().equals(packageName)) {
+                if (DEBUG) {
+                    Log.d(TAG, "Removing activity info from cache: " + cn);
+                }
+                mActivityInfoCache.remove(cn);
+            }
+        }
+    }
+
+    /**
+     * Returns the cached task label if the task key is not expired, updating the cache if it is.
+     */
+    String getAndUpdateActivityTitle(TaskKey taskKey, ActivityManager.TaskDescription td) {
+        // Return the task description label if it exists
+        if (td != null && td.getLabel() != null) {
+            return td.getLabel();
+        }
+        // Return the cached activity label if it exists
+        String label = mActivityLabelCache.getAndInvalidateIfModified(taskKey);
+        if (label != null) {
+            return label;
+        }
+        // All short paths failed, load the label from the activity info and cache it
+        ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey);
+        if (activityInfo != null) {
+            label = ActivityManagerWrapper.getInstance().getBadgedActivityLabel(activityInfo,
+                    taskKey.userId);
+            mActivityLabelCache.put(taskKey, label);
+            return label;
+        }
+        // If the activity info does not exist or fails to load, return an empty label for now,
+        // but do not cache it
+        return "";
+    }
+
+    /**
+     * Returns the cached task content description if the task key is not expired, updating the
+     * cache if it is.
+     */
+    String getAndUpdateContentDescription(TaskKey taskKey, ActivityManager.TaskDescription td) {
+        // Return the cached content description if it exists
+        String label = mContentDescriptionCache.getAndInvalidateIfModified(taskKey);
+        if (label != null) {
+            return label;
+        }
+
+        // All short paths failed, load the label from the activity info and cache it
+        ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey);
+        if (activityInfo != null) {
+            label = ActivityManagerWrapper.getInstance().getBadgedContentDescription(
+                    activityInfo, taskKey.userId, td);
+            if (td == null) {
+                // Only add to the cache if the task description is null, otherwise, it is possible
+                // for the task description to change between calls without the last active time
+                // changing (ie. between preloading and Overview starting) which would lead to stale
+                // content descriptions
+                // TODO: Investigate improving this
+                mContentDescriptionCache.put(taskKey, label);
+            }
+            return label;
+        }
+        // If the content description does not exist, return an empty label for now, but do not
+        // cache it
+        return "";
+    }
+
+    /**
+     * Returns the cached task icon if the task key is not expired, updating the cache if it is.
+     */
+    Drawable getAndUpdateActivityIcon(TaskKey taskKey, ActivityManager.TaskDescription td,
+            Resources res, boolean loadIfNotCached) {
+        // Return the cached activity icon if it exists
+        Drawable icon = mIconCache.getAndInvalidateIfModified(taskKey);
+        if (icon != null) {
+            return icon;
+        }
+
+        if (loadIfNotCached) {
+            // Return and cache the task description icon if it exists
+            icon = ActivityManagerWrapper.getInstance().getBadgedTaskDescriptionIcon(mContext, td,
+                    taskKey.userId, res);
+            if (icon != null) {
+                mIconCache.put(taskKey, icon);
+                return icon;
+            }
+
+            // Load the icon from the activity info and cache it
+            ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey);
+            if (activityInfo != null) {
+                icon = ActivityManagerWrapper.getInstance().getBadgedActivityIcon(activityInfo,
+                        taskKey.userId);
+                if (icon != null) {
+                    mIconCache.put(taskKey, icon);
+                    return icon;
+                }
+            }
+        }
+        // We couldn't load any icon
+        return null;
+    }
+
+    /**
+     * Returns the cached thumbnail if the task key is not expired, updating the cache if it is.
+     */
+    synchronized ThumbnailData getAndUpdateThumbnail(TaskKey taskKey, boolean loadIfNotCached,
+            boolean storeInCache) {
+        ThumbnailData cached = mThumbnailCache.getAndInvalidateIfModified(taskKey);
+        if (cached != null) {
+            return cached;
+        }
+
+        cached = mTempCache.getAndInvalidateIfModified(taskKey);
+        if (cached != null) {
+            mThumbnailCache.put(taskKey, cached);
+            return cached;
+        }
+
+        if (loadIfNotCached) {
+            if (mSvelteLevel < SVELTE_DISABLE_LOADING) {
+                // Load the thumbnail from the system
+                ThumbnailData thumbnailData = ActivityManagerWrapper.getInstance().getTaskThumbnail(
+                        taskKey.id, true /* reducedResolution */);
+                if (thumbnailData.thumbnail != null) {
+                    if (storeInCache) {
+                        mThumbnailCache.put(taskKey, thumbnailData);
+                    }
+                    return thumbnailData;
+                }
+            }
+        }
+
+        // We couldn't load any thumbnail
+        return null;
+    }
+
+    /**
+     * Returns the task's primary color if possible, defaulting to the default color if there is
+     * no specified primary color.
+     */
+    int getActivityPrimaryColor(ActivityManager.TaskDescription td) {
+        if (td != null && td.getPrimaryColor() != 0) {
+            return td.getPrimaryColor();
+        }
+        return mDefaultTaskBarBackgroundColor;
+    }
+
+    /**
+     * Returns the task's background color if possible.
+     */
+    int getActivityBackgroundColor(ActivityManager.TaskDescription td) {
+        if (td != null && td.getBackgroundColor() != 0) {
+            return td.getBackgroundColor();
+        }
+        return mDefaultTaskViewBackgroundColor;
+    }
+
+    /**
+     * Returns the activity info for the given task key, retrieving one from the system if the
+     * task key is expired.
+     */
+    ActivityInfo getAndUpdateActivityInfo(TaskKey taskKey) {
+        ComponentName cn = taskKey.getComponent();
+        ActivityInfo activityInfo = mActivityInfoCache.get(cn);
+        if (activityInfo == null) {
+            activityInfo = PackageManagerWrapper.getInstance().getActivityInfo(cn, taskKey.userId);
+            if (cn == null || activityInfo == null) {
+                Log.e(TAG, "Unexpected null component name or activity info: " + cn + ", " +
+                        activityInfo);
+                return null;
+            }
+            mActivityInfoCache.put(cn, activityInfo);
+        }
+        return activityInfo;
+    }
+
+    /**
+     * Starts loading tasks.
+     */
+    public void startLoader(Context ctx) {
+        mLoader.start(ctx);
+    }
+
+    /**
+     * Stops the task loader and clears all queued, pending task loads.
+     */
+    private void stopLoader() {
+        mLoader.stop();
+        mLoadQueue.clearTasks();
+    }
+
+    public synchronized void dump(String prefix, PrintWriter writer) {
+        String innerPrefix = prefix + "  ";
+
+        writer.print(prefix); writer.println(TAG);
+        writer.print(prefix); writer.println("Icon Cache");
+        mIconCache.dump(innerPrefix, writer);
+        writer.print(prefix); writer.println("Thumbnail Cache");
+        mThumbnailCache.dump(innerPrefix, writer);
+        writer.print(prefix); writer.println("Temp Thumbnail Cache");
+        mTempCache.dump(innerPrefix, writer);
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
new file mode 100644
index 0000000..6bddbe0
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.recents.model;
+
+import android.app.ActivityManager.TaskDescription;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.view.ViewDebug;
+
+import com.android.systemui.shared.recents.utilities.Utilities;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Objects;
+
+/**
+ * A task represents the top most task in the system's task stack.
+ */
+public class Task {
+
+    public static final String TAG = "Task";
+
+    /* Task callbacks */
+    public interface TaskCallbacks {
+        /* Notifies when a task has been bound */
+        void onTaskDataLoaded(Task task, ThumbnailData thumbnailData);
+        /* Notifies when a task has been unbound */
+        void onTaskDataUnloaded();
+        /* Notifies when a task's windowing mode has changed. */
+        void onTaskWindowingModeChanged();
+    }
+
+    /* The Task Key represents the unique primary key for the task */
+    public static class TaskKey {
+        @ViewDebug.ExportedProperty(category="recents")
+        public final int id;
+        @ViewDebug.ExportedProperty(category="recents")
+        public int windowingMode;
+        @ViewDebug.ExportedProperty(category="recents")
+        public final Intent baseIntent;
+        @ViewDebug.ExportedProperty(category="recents")
+        public final int userId;
+        @ViewDebug.ExportedProperty(category="recents")
+        public long lastActiveTime;
+
+        private int mHashCode;
+
+        public TaskKey(int id, int windowingMode, Intent intent, int userId, long lastActiveTime) {
+            this.id = id;
+            this.windowingMode = windowingMode;
+            this.baseIntent = intent;
+            this.userId = userId;
+            this.lastActiveTime = lastActiveTime;
+            updateHashCode();
+        }
+
+        public void setWindowingMode(int windowingMode) {
+            this.windowingMode = windowingMode;
+            updateHashCode();
+        }
+
+        public ComponentName getComponent() {
+            return this.baseIntent.getComponent();
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (!(o instanceof TaskKey)) {
+                return false;
+            }
+            TaskKey otherKey = (TaskKey) o;
+            return id == otherKey.id
+                    && windowingMode == otherKey.windowingMode
+                    && userId == otherKey.userId;
+        }
+
+        @Override
+        public int hashCode() {
+            return mHashCode;
+        }
+
+        @Override
+        public String toString() {
+            return "id=" + id + " windowingMode=" + windowingMode + " user=" + userId
+                    + " lastActiveTime=" + lastActiveTime;
+        }
+
+        private void updateHashCode() {
+            mHashCode = Objects.hash(id, windowingMode, userId);
+        }
+    }
+
+    @ViewDebug.ExportedProperty(deepExport=true, prefix="key_")
+    public TaskKey key;
+
+    /**
+     * The temporary sort index in the stack, used when ordering the stack.
+     */
+    public int temporarySortIndexInStack;
+
+    /**
+     * The icon is the task description icon (if provided), which falls back to the activity icon,
+     * which can then fall back to the application icon.
+     */
+    public Drawable icon;
+    public ThumbnailData thumbnail;
+    @ViewDebug.ExportedProperty(category="recents")
+    public String title;
+    @ViewDebug.ExportedProperty(category="recents")
+    public String titleDescription;
+    @ViewDebug.ExportedProperty(category="recents")
+    public int colorPrimary;
+    @ViewDebug.ExportedProperty(category="recents")
+    public int colorBackground;
+    @ViewDebug.ExportedProperty(category="recents")
+    public boolean useLightOnPrimaryColor;
+
+    /**
+     * The task description for this task, only used to reload task icons.
+     */
+    public TaskDescription taskDescription;
+
+    /**
+     * The state isLaunchTarget will be set for the correct task upon launching Recents.
+     */
+    @ViewDebug.ExportedProperty(category="recents")
+    public boolean isLaunchTarget;
+    @ViewDebug.ExportedProperty(category="recents")
+    public boolean isStackTask;
+    @ViewDebug.ExportedProperty(category="recents")
+    public boolean isSystemApp;
+    @ViewDebug.ExportedProperty(category="recents")
+    public boolean isDockable;
+
+    /**
+     * Resize mode. See {@link ActivityInfo#resizeMode}.
+     */
+    @ViewDebug.ExportedProperty(category="recents")
+    public int resizeMode;
+
+    @ViewDebug.ExportedProperty(category="recents")
+    public ComponentName topActivity;
+
+    @ViewDebug.ExportedProperty(category="recents")
+    public boolean isLocked;
+
+    private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>();
+
+    public Task() {
+        // Do nothing
+    }
+
+    public Task(TaskKey key, Drawable icon, ThumbnailData thumbnail, String title,
+            String titleDescription, int colorPrimary, int colorBackground, boolean isLaunchTarget,
+            boolean isStackTask, boolean isSystemApp, boolean isDockable,
+            TaskDescription taskDescription, int resizeMode, ComponentName topActivity,
+            boolean isLocked) {
+        this.key = key;
+        this.icon = icon;
+        this.thumbnail = thumbnail;
+        this.title = title;
+        this.titleDescription = titleDescription;
+        this.colorPrimary = colorPrimary;
+        this.colorBackground = colorBackground;
+        this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(this.colorPrimary,
+                Color.WHITE) > 3f;
+        this.taskDescription = taskDescription;
+        this.isLaunchTarget = isLaunchTarget;
+        this.isStackTask = isStackTask;
+        this.isSystemApp = isSystemApp;
+        this.isDockable = isDockable;
+        this.resizeMode = resizeMode;
+        this.topActivity = topActivity;
+        this.isLocked = isLocked;
+    }
+
+    /**
+     * Copies the metadata from another task, but retains the current callbacks.
+     */
+    public void copyFrom(Task o) {
+        this.key = o.key;
+        this.icon = o.icon;
+        this.thumbnail = o.thumbnail;
+        this.title = o.title;
+        this.titleDescription = o.titleDescription;
+        this.colorPrimary = o.colorPrimary;
+        this.colorBackground = o.colorBackground;
+        this.useLightOnPrimaryColor = o.useLightOnPrimaryColor;
+        this.taskDescription = o.taskDescription;
+        this.isLaunchTarget = o.isLaunchTarget;
+        this.isStackTask = o.isStackTask;
+        this.isSystemApp = o.isSystemApp;
+        this.isDockable = o.isDockable;
+        this.resizeMode = o.resizeMode;
+        this.isLocked = o.isLocked;
+        this.topActivity = o.topActivity;
+    }
+
+    /**
+     * Add a callback.
+     */
+    public void addCallback(TaskCallbacks cb) {
+        if (!mCallbacks.contains(cb)) {
+            mCallbacks.add(cb);
+        }
+    }
+
+    /**
+     * Remove a callback.
+     */
+    public void removeCallback(TaskCallbacks cb) {
+        mCallbacks.remove(cb);
+    }
+
+    /** Updates the task's windowing mode. */
+    public void setWindowingMode(int windowingMode) {
+        key.setWindowingMode(windowingMode);
+        int callbackCount = mCallbacks.size();
+        for (int i = 0; i < callbackCount; i++) {
+            mCallbacks.get(i).onTaskWindowingModeChanged();
+        }
+    }
+
+    /** Notifies the callback listeners that this task has been loaded */
+    public void notifyTaskDataLoaded(ThumbnailData thumbnailData, Drawable applicationIcon) {
+        this.icon = applicationIcon;
+        this.thumbnail = thumbnailData;
+        int callbackCount = mCallbacks.size();
+        for (int i = 0; i < callbackCount; i++) {
+            mCallbacks.get(i).onTaskDataLoaded(this, thumbnailData);
+        }
+    }
+
+    /** Notifies the callback listeners that this task has been unloaded */
+    public void notifyTaskDataUnloaded(Drawable defaultApplicationIcon) {
+        icon = defaultApplicationIcon;
+        thumbnail = null;
+        for (int i = mCallbacks.size() - 1; i >= 0; i--) {
+            mCallbacks.get(i).onTaskDataUnloaded();
+        }
+    }
+
+    /**
+     * Returns the top activity component.
+     */
+    public ComponentName getTopComponent() {
+        return topActivity != null
+                ? topActivity
+                : key.baseIntent.getComponent();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        // Check that the id matches
+        Task t = (Task) o;
+        return key.equals(t.key);
+    }
+
+    @Override
+    public String toString() {
+        return "[" + key.toString() + "] " + title;
+    }
+
+    public void dump(String prefix, PrintWriter writer) {
+        writer.print(prefix); writer.print(key);
+        if (!isDockable) {
+            writer.print(" dockable=N");
+        }
+        if (isLaunchTarget) {
+            writer.print(" launchTarget=Y");
+        }
+        if (isLocked) {
+            writer.print(" locked=Y");
+        }
+        writer.print(" "); writer.print(title);
+        writer.println();
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java
new file mode 100644
index 0000000..9a1ff54
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.shared.recents.model;
+
+import android.util.SparseArray;
+
+/**
+ * An interface for a task filter to query whether a particular task should show in a stack.
+ */
+interface TaskFilter {
+    /** Returns whether the filter accepts the specified task */
+    boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index);
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java
new file mode 100644
index 0000000..4bf3500
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.shared.recents.model;
+
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.systemui.shared.recents.model.Task.TaskKey;
+
+/**
+ * Base class for both strong and LRU task key cache.
+ */
+public abstract class TaskKeyCache<V> {
+
+    protected static final String TAG = "TaskKeyCache";
+
+    protected final SparseArray<TaskKey> mKeys = new SparseArray<>();
+
+    /**
+     * Gets a specific entry in the cache with the specified key, regardless of whether the cached
+     * value is valid or not.
+     */
+    final V get(TaskKey key) {
+        return getCacheEntry(key.id);
+    }
+
+    /**
+     * Returns the value only if the key is valid (has not been updated since the last time it was
+     * in the cache)
+     */
+    final V getAndInvalidateIfModified(TaskKey key) {
+        TaskKey lastKey = mKeys.get(key.id);
+        if (lastKey != null) {
+            if ((lastKey.windowingMode != key.windowingMode) ||
+                    (lastKey.lastActiveTime != key.lastActiveTime)) {
+                // The task has updated (been made active since the last time it was put into the
+                // LRU cache) or the stack id for the task has changed, invalidate that cache item
+                remove(key);
+                return null;
+            }
+        }
+        // Either the task does not exist in the cache, or the last active time is the same as
+        // the key specified, so return what is in the cache
+        return getCacheEntry(key.id);
+    }
+
+    /** Puts an entry in the cache for a specific key. */
+    final void put(TaskKey key, V value) {
+        if (key == null || value == null) {
+            Log.e(TAG, "Unexpected null key or value: " + key + ", " + value);
+            return;
+        }
+        mKeys.put(key.id, key);
+        putCacheEntry(key.id, value);
+    }
+
+
+    /** Removes a cache entry for a specific key. */
+    final void remove(TaskKey key) {
+        // Remove the key after the cache value because we need it to make the callback
+        removeCacheEntry(key.id);
+        mKeys.remove(key.id);
+    }
+
+    /** Removes all the entries in the cache. */
+    final void evictAll() {
+        evictAllCache();
+        mKeys.clear();
+    }
+
+    protected abstract V getCacheEntry(int id);
+    protected abstract void putCacheEntry(int id, V value);
+    protected abstract void removeCacheEntry(int id);
+    protected abstract void evictAllCache();
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java
new file mode 100644
index 0000000..0ba2c3bf
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.recents.model;
+
+import android.util.LruCache;
+
+import com.android.systemui.shared.recents.model.Task.TaskKey;
+
+import java.io.PrintWriter;
+
+/**
+ * A mapping of {@link TaskKey} to value, with additional LRU functionality where the least
+ * recently referenced key/values will be evicted as more values than the given cache size are
+ * inserted.
+ *
+ * In addition, this also allows the caller to invalidate cached values for keys that have since
+ * changed.
+ */
+public class TaskKeyLruCache<V> extends TaskKeyCache<V> {
+
+    public interface EvictionCallback {
+        void onEntryEvicted(TaskKey key);
+    }
+
+    private final LruCache<Integer, V> mCache;
+    private final EvictionCallback mEvictionCallback;
+
+    public TaskKeyLruCache(int cacheSize) {
+        this(cacheSize, null);
+    }
+
+    public TaskKeyLruCache(int cacheSize, EvictionCallback evictionCallback) {
+        mEvictionCallback = evictionCallback;
+        mCache = new LruCache<Integer, V>(cacheSize) {
+
+            @Override
+            protected void entryRemoved(boolean evicted, Integer taskId, V oldV, V newV) {
+                if (mEvictionCallback != null) {
+                    mEvictionCallback.onEntryEvicted(mKeys.get(taskId));
+                }
+                mKeys.remove(taskId);
+            }
+        };
+    }
+
+    /** Trims the cache to a specific size */
+    final void trimToSize(int cacheSize) {
+        mCache.trimToSize(cacheSize);
+    }
+
+    public void dump(String prefix, PrintWriter writer) {
+        String innerPrefix = prefix + "  ";
+
+        writer.print(prefix); writer.print(TAG);
+        writer.print(" numEntries="); writer.print(mKeys.size());
+        writer.println();
+        int keyCount = mKeys.size();
+        for (int i = 0; i < keyCount; i++) {
+            writer.print(innerPrefix); writer.println(mKeys.get(mKeys.keyAt(i)));
+        }
+    }
+
+    @Override
+    protected V getCacheEntry(int id) {
+        return mCache.get(id);
+    }
+
+    @Override
+    protected void putCacheEntry(int id, V value) {
+        mCache.put(id, value);
+    }
+
+    @Override
+    protected void removeCacheEntry(int id) {
+        mCache.remove(id);
+    }
+
+    @Override
+    protected void evictAllCache() {
+        mCache.evictAll();
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyStrongCache.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyStrongCache.java
new file mode 100644
index 0000000..4408ece
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyStrongCache.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.shared.recents.model;
+
+import android.util.ArrayMap;
+
+import com.android.systemui.shared.recents.model.Task.TaskKey;
+
+import java.io.PrintWriter;
+
+/**
+ * Like {@link TaskKeyLruCache}, but without LRU functionality.
+ */
+public class TaskKeyStrongCache<V> extends TaskKeyCache<V> {
+
+    private static final String TAG = "TaskKeyCache";
+
+    private final ArrayMap<Integer, V> mCache = new ArrayMap<>();
+
+    final void copyEntries(TaskKeyStrongCache<V> other) {
+        for (int i = other.mKeys.size() - 1; i >= 0; i--) {
+            TaskKey key = other.mKeys.valueAt(i);
+            put(key, other.mCache.get(key.id));
+        }
+    }
+
+    public void dump(String prefix, PrintWriter writer) {
+        String innerPrefix = prefix + "  ";
+        writer.print(prefix); writer.print(TAG);
+        writer.print(" numEntries="); writer.print(mKeys.size());
+        writer.println();
+        int keyCount = mKeys.size();
+        for (int i = 0; i < keyCount; i++) {
+            writer.print(innerPrefix); writer.println(mKeys.get(mKeys.keyAt(i)));
+        }
+    }
+
+    @Override
+    protected V getCacheEntry(int id) {
+        return mCache.get(id);
+    }
+
+    @Override
+    protected void putCacheEntry(int id, V value) {
+        mCache.put(id, value);
+    }
+
+    @Override
+    protected void removeCacheEntry(int id) {
+        mCache.remove(id);
+    }
+
+    @Override
+    protected void evictAllCache() {
+        mCache.clear();
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskResourceLoadQueue.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskResourceLoadQueue.java
new file mode 100644
index 0000000..fbb6ace
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskResourceLoadQueue.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.shared.recents.model;
+
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+/**
+ * A Task load queue
+ */
+class TaskResourceLoadQueue {
+
+    private final ConcurrentLinkedQueue<Task> mQueue = new ConcurrentLinkedQueue<>();
+
+    /** Adds a new task to the load queue */
+    void addTask(Task t) {
+        if (!mQueue.contains(t)) {
+            mQueue.add(t);
+        }
+        synchronized(this) {
+            notifyAll();
+        }
+    }
+
+    /**
+     * Retrieves the next task from the load queue, as well as whether we want that task to be
+     * force reloaded.
+     */
+    Task nextTask() {
+        return mQueue.poll();
+    }
+
+    /** Removes a task from the load queue */
+    void removeTask(Task t) {
+        mQueue.remove(t);
+    }
+
+    /** Clears all the tasks from the load queue */
+    void clearTasks() {
+        mQueue.clear();
+    }
+
+    /** Returns whether the load queue is empty */
+    boolean isEmpty() {
+        return mQueue.isEmpty();
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java
new file mode 100644
index 0000000..693379d3
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.recents.model;
+
+import android.content.ComponentName;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.SparseArray;
+
+import com.android.systemui.shared.recents.model.Task.TaskKey;
+import com.android.systemui.shared.recents.utilities.AnimationProps;
+import com.android.systemui.shared.system.PackageManagerWrapper;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * The task stack contains a list of multiple tasks.
+ */
+public class TaskStack {
+
+    private static final String TAG = "TaskStack";
+
+    /** Task stack callbacks */
+    public interface TaskStackCallbacks {
+        /**
+         * Notifies when a new task has been added to the stack.
+         */
+        void onStackTaskAdded(TaskStack stack, Task newTask);
+
+        /**
+         * Notifies when a task has been removed from the stack.
+         */
+        void onStackTaskRemoved(TaskStack stack, Task removedTask, Task newFrontMostTask,
+                AnimationProps animation, boolean fromDockGesture,
+                boolean dismissRecentsIfAllRemoved);
+
+        /**
+         * Notifies when all tasks have been removed from the stack.
+         */
+        void onStackTasksRemoved(TaskStack stack);
+
+        /**
+         * Notifies when tasks in the stack have been updated.
+         */
+        void onStackTasksUpdated(TaskStack stack);
+    }
+
+    private final ArrayList<Task> mRawTaskList = new ArrayList<>();
+    private final FilteredTaskList mStackTaskList = new FilteredTaskList();
+    private TaskStackCallbacks mCb;
+
+    public TaskStack() {
+        // Ensure that we only show stack tasks
+        mStackTaskList.setFilter((taskIdMap, t, index) -> t.isStackTask);
+    }
+
+    /** Sets the callbacks for this task stack. */
+    public void setCallbacks(TaskStackCallbacks cb) {
+        mCb = cb;
+    }
+
+    /**
+     * Removes a task from the stack, with an additional {@param animation} hint to the callbacks on
+     * how they should update themselves.
+     */
+    public void removeTask(Task t, AnimationProps animation, boolean fromDockGesture) {
+        removeTask(t, animation, fromDockGesture, true /* dismissRecentsIfAllRemoved */);
+    }
+
+    /**
+     * Removes a task from the stack, with an additional {@param animation} hint to the callbacks on
+     * how they should update themselves.
+     */
+    public void removeTask(Task t, AnimationProps animation, boolean fromDockGesture,
+            boolean dismissRecentsIfAllRemoved) {
+        if (mStackTaskList.contains(t)) {
+            mStackTaskList.remove(t);
+            Task newFrontMostTask = getStackFrontMostTask();
+            if (mCb != null) {
+                // Notify that a task has been removed
+                mCb.onStackTaskRemoved(this, t, newFrontMostTask, animation,
+                        fromDockGesture, dismissRecentsIfAllRemoved);
+            }
+        }
+        mRawTaskList.remove(t);
+    }
+
+    /**
+     * Removes all tasks from the stack.
+     */
+    public void removeAllTasks(boolean notifyStackChanges) {
+        ArrayList<Task> tasks = mStackTaskList.getTasks();
+        for (int i = tasks.size() - 1; i >= 0; i--) {
+            Task t = tasks.get(i);
+            mStackTaskList.remove(t);
+            mRawTaskList.remove(t);
+        }
+        if (mCb != null && notifyStackChanges) {
+            // Notify that all tasks have been removed
+            mCb.onStackTasksRemoved(this);
+        }
+    }
+
+
+    /**
+     * @see #setTasks(List, boolean)
+     */
+    public void setTasks(TaskStack stack, boolean notifyStackChanges) {
+        setTasks(stack.mRawTaskList, notifyStackChanges);
+    }
+
+    /**
+     * Sets a few tasks in one go, without calling any callbacks.
+     *
+     * @param tasks the new set of tasks to replace the current set.
+     * @param notifyStackChanges whether or not to callback on specific changes to the list of tasks.
+     */
+    public void setTasks(List<Task> tasks, boolean notifyStackChanges) {
+        // Compute a has set for each of the tasks
+        ArrayMap<TaskKey, Task> currentTasksMap = createTaskKeyMapFromList(mRawTaskList);
+        ArrayMap<TaskKey, Task> newTasksMap = createTaskKeyMapFromList(tasks);
+        ArrayList<Task> addedTasks = new ArrayList<>();
+        ArrayList<Task> removedTasks = new ArrayList<>();
+        ArrayList<Task> allTasks = new ArrayList<>();
+
+        // Disable notifications if there are no callbacks
+        if (mCb == null) {
+            notifyStackChanges = false;
+        }
+
+        // Remove any tasks that no longer exist
+        int taskCount = mRawTaskList.size();
+        for (int i = taskCount - 1; i >= 0; i--) {
+            Task task = mRawTaskList.get(i);
+            if (!newTasksMap.containsKey(task.key)) {
+                if (notifyStackChanges) {
+                    removedTasks.add(task);
+                }
+            }
+        }
+
+        // Add any new tasks
+        taskCount = tasks.size();
+        for (int i = 0; i < taskCount; i++) {
+            Task newTask = tasks.get(i);
+            Task currentTask = currentTasksMap.get(newTask.key);
+            if (currentTask == null && notifyStackChanges) {
+                addedTasks.add(newTask);
+            } else if (currentTask != null) {
+                // The current task has bound callbacks, so just copy the data from the new task
+                // state and add it back into the list
+                currentTask.copyFrom(newTask);
+                newTask = currentTask;
+            }
+            allTasks.add(newTask);
+        }
+
+        // Sort all the tasks to ensure they are ordered correctly
+        for (int i = allTasks.size() - 1; i >= 0; i--) {
+            allTasks.get(i).temporarySortIndexInStack = i;
+        }
+
+        mStackTaskList.set(allTasks);
+        mRawTaskList.clear();
+        mRawTaskList.addAll(allTasks);
+
+        // Only callback for the removed tasks after the stack has updated
+        int removedTaskCount = removedTasks.size();
+        Task newFrontMostTask = getStackFrontMostTask();
+        for (int i = 0; i < removedTaskCount; i++) {
+            mCb.onStackTaskRemoved(this, removedTasks.get(i), newFrontMostTask,
+                    AnimationProps.IMMEDIATE, false /* fromDockGesture */,
+                    true /* dismissRecentsIfAllRemoved */);
+        }
+
+        // Only callback for the newly added tasks after this stack has been updated
+        int addedTaskCount = addedTasks.size();
+        for (int i = 0; i < addedTaskCount; i++) {
+            mCb.onStackTaskAdded(this, addedTasks.get(i));
+        }
+
+        // Notify that the task stack has been updated
+        if (notifyStackChanges) {
+            mCb.onStackTasksUpdated(this);
+        }
+    }
+
+    /**
+     * Gets the front-most task in the stack.
+     */
+    public Task getStackFrontMostTask() {
+        ArrayList<Task> stackTasks = mStackTaskList.getTasks();
+        if (stackTasks.isEmpty()) {
+            return null;
+        }
+        return stackTasks.get(stackTasks.size() - 1);
+    }
+
+    /** Gets the task keys */
+    public ArrayList<TaskKey> getTaskKeys() {
+        ArrayList<TaskKey> taskKeys = new ArrayList<>();
+        ArrayList<Task> tasks = computeAllTasksList();
+        int taskCount = tasks.size();
+        for (int i = 0; i < taskCount; i++) {
+            Task task = tasks.get(i);
+            taskKeys.add(task.key);
+        }
+        return taskKeys;
+    }
+
+    /**
+     * Returns the set of "active" (non-historical) tasks in the stack that have been used recently.
+     */
+    public ArrayList<Task> getStackTasks() {
+        return mStackTaskList.getTasks();
+    }
+
+    /**
+     * Computes a set of all the active and historical tasks.
+     */
+    public ArrayList<Task> computeAllTasksList() {
+        ArrayList<Task> tasks = new ArrayList<>();
+        tasks.addAll(mStackTaskList.getTasks());
+        return tasks;
+    }
+
+    /**
+     * Returns the number of stacktasks.
+     */
+    public int getTaskCount() {
+        return mStackTaskList.size();
+    }
+
+    /**
+     * Returns the number of stack tasks.
+     */
+    public int getStackTaskCount() {
+        return mStackTaskList.size();
+    }
+
+    /**
+     * Returns the task in stack tasks which is the launch target.
+     */
+    public Task getLaunchTarget() {
+        ArrayList<Task> tasks = mStackTaskList.getTasks();
+        int taskCount = tasks.size();
+        for (int i = 0; i < taskCount; i++) {
+            Task task = tasks.get(i);
+            if (task.isLaunchTarget) {
+                return task;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns whether the next launch target should actually be the PiP task.
+     */
+    public boolean isNextLaunchTargetPip(long lastPipTime) {
+        Task launchTarget = getLaunchTarget();
+        Task nextLaunchTarget = getNextLaunchTargetRaw();
+        if (nextLaunchTarget != null && lastPipTime > 0) {
+            // If the PiP time is more recent than the next launch target, then launch the PiP task
+            return lastPipTime > nextLaunchTarget.key.lastActiveTime;
+        } else if (launchTarget != null && lastPipTime > 0 && getTaskCount() == 1) {
+            // Otherwise, if there is no next launch target, but there is a PiP, then launch
+            // the PiP task
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns the task in stack tasks which should be launched next if Recents are toggled
+     * again, or null if there is no task to be launched. Callers should check
+     * {@link #isNextLaunchTargetPip(long)} before fetching the next raw launch target from the
+     * stack.
+     */
+    public Task getNextLaunchTarget() {
+        Task nextLaunchTarget = getNextLaunchTargetRaw();
+        if (nextLaunchTarget != null) {
+            return nextLaunchTarget;
+        }
+        return getStackTasks().get(getTaskCount() - 1);
+    }
+
+    private Task getNextLaunchTargetRaw() {
+        int taskCount = getTaskCount();
+        if (taskCount == 0) {
+            return null;
+        }
+        int launchTaskIndex = indexOfStackTask(getLaunchTarget());
+        if (launchTaskIndex != -1 && launchTaskIndex > 0) {
+            return getStackTasks().get(launchTaskIndex - 1);
+        }
+        return null;
+    }
+
+    /** Returns the index of this task in this current task stack */
+    public int indexOfStackTask(Task t) {
+        return mStackTaskList.indexOf(t);
+    }
+
+    /** Finds the task with the specified task id. */
+    public Task findTaskWithId(int taskId) {
+        ArrayList<Task> tasks = computeAllTasksList();
+        int taskCount = tasks.size();
+        for (int i = 0; i < taskCount; i++) {
+            Task task = tasks.get(i);
+            if (task.key.id == taskId) {
+                return task;
+            }
+        }
+        return null;
+    }
+    
+    /**
+     * Computes the components of tasks in this stack that have been removed as a result of a change
+     * in the specified package.
+     */
+    public ArraySet<ComponentName> computeComponentsRemoved(String packageName, int userId) {
+        // Identify all the tasks that should be removed as a result of the package being removed.
+        // Using a set to ensure that we callback once per unique component.
+        ArraySet<ComponentName> existingComponents = new ArraySet<>();
+        ArraySet<ComponentName> removedComponents = new ArraySet<>();
+        ArrayList<TaskKey> taskKeys = getTaskKeys();
+        int taskKeyCount = taskKeys.size();
+        for (int i = 0; i < taskKeyCount; i++) {
+            TaskKey t = taskKeys.get(i);
+
+            // Skip if this doesn't apply to the current user
+            if (t.userId != userId) continue;
+
+            ComponentName cn = t.getComponent();
+            if (cn.getPackageName().equals(packageName)) {
+                if (existingComponents.contains(cn)) {
+                    // If we know that the component still exists in the package, then skip
+                    continue;
+                }
+                if (PackageManagerWrapper.getInstance().getActivityInfo(cn, userId) != null) {
+                    existingComponents.add(cn);
+                } else {
+                    removedComponents.add(cn);
+                }
+            }
+        }
+        return removedComponents;
+    }
+
+    @Override
+    public String toString() {
+        String str = "Stack Tasks (" + mStackTaskList.size() + "):\n";
+        ArrayList<Task> tasks = mStackTaskList.getTasks();
+        int taskCount = tasks.size();
+        for (int i = 0; i < taskCount; i++) {
+            str += "    " + tasks.get(i).toString() + "\n";
+        }
+        return str;
+    }
+
+    /**
+     * Given a list of tasks, returns a map of each task's key to the task.
+     */
+    private ArrayMap<TaskKey, Task> createTaskKeyMapFromList(List<Task> tasks) {
+        ArrayMap<TaskKey, Task> map = new ArrayMap<>(tasks.size());
+        int taskCount = tasks.size();
+        for (int i = 0; i < taskCount; i++) {
+            Task task = tasks.get(i);
+            map.put(task.key, task);
+        }
+        return map;
+    }
+
+    public void dump(String prefix, PrintWriter writer) {
+        String innerPrefix = prefix + "  ";
+
+        writer.print(prefix); writer.print(TAG);
+        writer.print(" numStackTasks="); writer.print(mStackTaskList.size());
+        writer.println();
+        ArrayList<Task> tasks = mStackTaskList.getTasks();
+        int taskCount = tasks.size();
+        for (int i = 0; i < taskCount; i++) {
+            tasks.get(i).dump(innerPrefix, writer);
+        }
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
new file mode 100644
index 0000000..dd1763b
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
@@ -0,0 +1,51 @@
+/*
+ * 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 com.android.systemui.shared.recents.model;
+
+import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
+
+import android.app.ActivityManager.TaskSnapshot;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+
+/**
+ * Data for a single thumbnail.
+ */
+public class ThumbnailData {
+
+    public final Bitmap thumbnail;
+    public int orientation;
+    public Rect insets;
+    public boolean reducedResolution;
+    public float scale;
+
+    public ThumbnailData() {
+        thumbnail = null;
+        orientation = ORIENTATION_UNDEFINED;
+        insets = new Rect();
+        reducedResolution = false;
+        scale = 1f;
+    }
+
+    public ThumbnailData(TaskSnapshot snapshot) {
+        thumbnail = Bitmap.createHardwareBitmap(snapshot.getSnapshot());
+        insets = new Rect(snapshot.getContentInsets());
+        orientation = snapshot.getOrientation();
+        reducedResolution = snapshot.isReducedResolution();
+        scale = snapshot.getScale();
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AnimationProps.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AnimationProps.java
new file mode 100644
index 0000000..2de7f74
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AnimationProps.java
@@ -0,0 +1,229 @@
+/*
+ * 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 com.android.systemui.shared.recents.utilities;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
+import android.annotation.IntDef;
+import android.util.SparseArray;
+import android.util.SparseLongArray;
+import android.view.View;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
+/**
+ * The generic set of animation properties to animate a {@link View}. The animation can have
+ * different interpolators, start delays and durations for each of the different properties.
+ */
+public class AnimationProps {
+
+    private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
+    public static final AnimationProps IMMEDIATE = new AnimationProps(0, LINEAR_INTERPOLATOR);
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({ALL, TRANSLATION_X, TRANSLATION_Y, TRANSLATION_Z, ALPHA, SCALE, BOUNDS})
+    public @interface PropType {}
+
+    public static final int ALL = 0;
+    public static final int TRANSLATION_X = 1;
+    public static final int TRANSLATION_Y = 2;
+    public static final int TRANSLATION_Z = 3;
+    public static final int ALPHA = 4;
+    public static final int SCALE = 5;
+    public static final int BOUNDS = 6;
+    public static final int DIM_ALPHA = 7;
+
+    private SparseLongArray mPropStartDelay;
+    private SparseLongArray mPropDuration;
+    private SparseArray<Interpolator> mPropInterpolators;
+    private Animator.AnimatorListener mListener;
+
+    /**
+     * The builder constructor.
+     */
+    public AnimationProps() {}
+
+    /**
+     * Creates an animation with a default {@param duration} and {@param interpolator} for all
+     * properties in this animation.
+     */
+    public AnimationProps(int duration, Interpolator interpolator) {
+        this(0, duration, interpolator, null);
+    }
+
+    /**
+     * Creates an animation with a default {@param duration} and {@param interpolator} for all
+     * properties in this animation.
+     */
+    public AnimationProps(int duration, Interpolator interpolator,
+            Animator.AnimatorListener listener) {
+        this(0, duration, interpolator, listener);
+    }
+
+    /**
+     * Creates an animation with a default {@param startDelay}, {@param duration} and
+     * {@param interpolator} for all properties in this animation.
+     */
+    public AnimationProps(int startDelay, int duration, Interpolator interpolator) {
+        this(startDelay, duration, interpolator, null);
+    }
+
+    /**
+     * Creates an animation with a default {@param startDelay}, {@param duration} and
+     * {@param interpolator} for all properties in this animation.
+     */
+    public AnimationProps(int startDelay, int duration, Interpolator interpolator,
+            Animator.AnimatorListener listener) {
+        setStartDelay(ALL, startDelay);
+        setDuration(ALL, duration);
+        setInterpolator(ALL, interpolator);
+        setListener(listener);
+    }
+
+    /**
+     * Creates a new {@link AnimatorSet} that will animate the given animators.  Callers need to
+     * manually apply the individual animation properties for each of the animators respectively.
+     */
+    public AnimatorSet createAnimator(List<Animator> animators) {
+        AnimatorSet anim = new AnimatorSet();
+        if (mListener != null) {
+            anim.addListener(mListener);
+        }
+        anim.playTogether(animators);
+        return anim;
+    }
+
+    /**
+     * Applies the specific start delay, duration and interpolator to the given {@param animator}
+     * for the specified {@param propertyType}.
+     */
+    public <T extends ValueAnimator> T apply(@PropType int propertyType, T animator) {
+        animator.setStartDelay(getStartDelay(propertyType));
+        animator.setDuration(getDuration(propertyType));
+        animator.setInterpolator(getInterpolator(propertyType));
+        return animator;
+    }
+
+    /**
+     * Sets a start delay for a specific property.
+     */
+    public AnimationProps setStartDelay(@PropType int propertyType, int startDelay) {
+        if (mPropStartDelay == null) {
+            mPropStartDelay = new SparseLongArray();
+        }
+        mPropStartDelay.append(propertyType, startDelay);
+        return this;
+    }
+
+    /**
+     * Returns the start delay for a specific property.
+     */
+    public long getStartDelay(@PropType int propertyType) {
+        if (mPropStartDelay != null) {
+            long startDelay = mPropStartDelay.get(propertyType, -1);
+            if (startDelay != -1) {
+                return startDelay;
+            }
+            return mPropStartDelay.get(ALL, 0);
+        }
+        return 0;
+    }
+
+    /**
+     * Sets a duration for a specific property.
+     */
+    public AnimationProps setDuration(@PropType int propertyType, int duration) {
+        if (mPropDuration == null) {
+            mPropDuration = new SparseLongArray();
+        }
+        mPropDuration.append(propertyType, duration);
+        return this;
+    }
+
+    /**
+     * Returns the duration for a specific property.
+     */
+    public long getDuration(@PropType int propertyType) {
+        if (mPropDuration != null) {
+            long duration = mPropDuration.get(propertyType, -1);
+            if (duration != -1) {
+                return duration;
+            }
+            return mPropDuration.get(ALL, 0);
+        }
+        return 0;
+    }
+
+    /**
+     * Sets an interpolator for a specific property.
+     */
+    public AnimationProps setInterpolator(@PropType int propertyType, Interpolator interpolator) {
+        if (mPropInterpolators == null) {
+            mPropInterpolators = new SparseArray<>();
+        }
+        mPropInterpolators.append(propertyType, interpolator);
+        return this;
+    }
+
+    /**
+     * Returns the interpolator for a specific property, falling back to the general interpolator
+     * if there is no specific property interpolator.
+     */
+    public Interpolator getInterpolator(@PropType int propertyType) {
+        if (mPropInterpolators != null) {
+            Interpolator interp = mPropInterpolators.get(propertyType);
+            if (interp != null) {
+                return interp;
+            }
+            return mPropInterpolators.get(ALL, LINEAR_INTERPOLATOR);
+        }
+        return LINEAR_INTERPOLATOR;
+    }
+
+    /**
+     * Sets an animator listener for this animation.
+     */
+    public AnimationProps setListener(Animator.AnimatorListener listener) {
+        mListener = listener;
+        return this;
+    }
+
+    /**
+     * Returns the animator listener for this animation.
+     */
+    public Animator.AnimatorListener getListener() {
+        return mListener;
+    }
+
+    /**
+     * Returns whether this animation has any duration.
+     */
+    public boolean isImmediate() {
+        int count = mPropDuration.size();
+        for (int i = 0; i < count; i++) {
+            if (mPropDuration.valueAt(i) > 0) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/RectFEvaluator.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/RectFEvaluator.java
new file mode 100644
index 0000000..51c1b5a
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/RectFEvaluator.java
@@ -0,0 +1,52 @@
+/*
+ * 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 com.android.systemui.shared.recents.utilities;
+
+import android.animation.TypeEvaluator;
+import android.graphics.RectF;
+
+/**
+ * This evaluator can be used to perform type interpolation between <code>RectF</code> values.
+ */
+public class RectFEvaluator implements TypeEvaluator<RectF> {
+
+    private final RectF mRect = new RectF();
+
+    /**
+     * This function returns the result of linearly interpolating the start and
+     * end Rect values, with <code>fraction</code> representing the proportion
+     * between the start and end values. The calculation is a simple parametric
+     * calculation on each of the separate components in the Rect objects
+     * (left, top, right, and bottom).
+     *
+     * <p>The object returned will be the <code>reuseRect</code> passed into the constructor.</p>
+     *
+     * @param fraction   The fraction from the starting to the ending values
+     * @param startValue The start Rect
+     * @param endValue   The end Rect
+     * @return A linear interpolation between the start and end values, given the
+     *         <code>fraction</code> parameter.
+     */
+    @Override
+    public RectF evaluate(float fraction, RectF startValue, RectF endValue) {
+        float left = startValue.left + ((endValue.left - startValue.left) * fraction);
+        float top = startValue.top + ((endValue.top - startValue.top) * fraction);
+        float right = startValue.right + ((endValue.right - startValue.right) * fraction);
+        float bottom = startValue.bottom + ((endValue.bottom - startValue.bottom) * fraction);
+        mRect.set(left, top, right, bottom);
+        return mRect;
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
new file mode 100644
index 0000000..a5d1963
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.recents.utilities;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.RectEvaluator;
+import android.annotation.FloatRange;
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.os.Trace;
+import android.util.ArraySet;
+import android.util.IntProperty;
+import android.util.Property;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.ViewStub;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/* Common code */
+public class Utilities {
+
+    public static final Property<Drawable, Integer> DRAWABLE_ALPHA =
+            new IntProperty<Drawable>("drawableAlpha") {
+                @Override
+                public void setValue(Drawable object, int alpha) {
+                    object.setAlpha(alpha);
+                }
+
+                @Override
+                public Integer get(Drawable object) {
+                    return object.getAlpha();
+                }
+            };
+
+    public static final Property<Drawable, Rect> DRAWABLE_RECT =
+            new Property<Drawable, Rect>(Rect.class, "drawableBounds") {
+                @Override
+                public void set(Drawable object, Rect bounds) {
+                    object.setBounds(bounds);
+                }
+
+                @Override
+                public Rect get(Drawable object) {
+                    return object.getBounds();
+                }
+            };
+
+    public static final RectFEvaluator RECTF_EVALUATOR = new RectFEvaluator();
+    public static final RectEvaluator RECT_EVALUATOR = new RectEvaluator(new Rect());
+
+    /**
+     * @return the first parent walking up the view hierarchy that has the given class type.
+     *
+     * @param parentClass must be a class derived from {@link View}
+     */
+    public static <T extends View> T findParent(View v, Class<T> parentClass) {
+        ViewParent parent = v.getParent();
+        while (parent != null) {
+            if (parentClass.isAssignableFrom(parent.getClass())) {
+                return (T) parent;
+            }
+            parent = parent.getParent();
+        }
+        return null;
+    }
+
+    /**
+     * Initializes the {@param setOut} with the given object.
+     */
+    public static <T> ArraySet<T> objectToSet(T obj, ArraySet<T> setOut) {
+        setOut.clear();
+        if (obj != null) {
+            setOut.add(obj);
+        }
+        return setOut;
+    }
+
+    /**
+     * Replaces the contents of {@param setOut} with the contents of the {@param array}.
+     */
+    public static <T> ArraySet<T> arrayToSet(T[] array, ArraySet<T> setOut) {
+        setOut.clear();
+        if (array != null) {
+            Collections.addAll(setOut, array);
+        }
+        return setOut;
+    }
+
+    /**
+     * @return the clamped {@param value} between the provided {@param min} and {@param max}.
+     */
+    public static float clamp(float value, float min, float max) {
+        return Math.max(min, Math.min(max, value));
+    }
+
+    /**
+     * @return the clamped {@param value} between the provided {@param min} and {@param max}.
+     */
+    public static int clamp(int value, int min, int max) {
+        return Math.max(min, Math.min(max, value));
+    }
+
+    /**
+     * @return the clamped {@param value} between 0 and 1.
+     */
+    public static float clamp01(float value) {
+        return Math.max(0f, Math.min(1f, value));
+    }
+
+    /**
+     * Scales the {@param value} to be proportionally between the {@param min} and
+     * {@param max} values.
+     *
+     * @param value must be between 0 and 1
+     */
+    public static float mapRange(@FloatRange(from=0.0,to=1.0) float value, float min, float max) {
+        return min + (value * (max - min));
+    }
+
+    /**
+     * Scales the {@param value} proportionally from {@param min} and {@param max} to 0 and 1.
+     *
+     * @param value must be between {@param min} and {@param max}
+     */
+    public static float unmapRange(float value, float min, float max) {
+        return (value - min) / (max - min);
+    }
+
+    /** Scales a rect about its centroid */
+    public static void scaleRectAboutCenter(RectF r, float scale) {
+        if (scale != 1.0f) {
+            float cx = r.centerX();
+            float cy = r.centerY();
+            r.offset(-cx, -cy);
+            r.left *= scale;
+            r.top *= scale;
+            r.right *= scale;
+            r.bottom *= scale;
+            r.offset(cx, cy);
+        }
+    }
+
+    /** Calculates the constrast between two colors, using the algorithm provided by the WCAG v2. */
+    public static float computeContrastBetweenColors(int bg, int fg) {
+        float bgR = Color.red(bg) / 255f;
+        float bgG = Color.green(bg) / 255f;
+        float bgB = Color.blue(bg) / 255f;
+        bgR = (bgR < 0.03928f) ? bgR / 12.92f : (float) Math.pow((bgR + 0.055f) / 1.055f, 2.4f);
+        bgG = (bgG < 0.03928f) ? bgG / 12.92f : (float) Math.pow((bgG + 0.055f) / 1.055f, 2.4f);
+        bgB = (bgB < 0.03928f) ? bgB / 12.92f : (float) Math.pow((bgB + 0.055f) / 1.055f, 2.4f);
+        float bgL = 0.2126f * bgR + 0.7152f * bgG + 0.0722f * bgB;
+        
+        float fgR = Color.red(fg) / 255f;
+        float fgG = Color.green(fg) / 255f;
+        float fgB = Color.blue(fg) / 255f;
+        fgR = (fgR < 0.03928f) ? fgR / 12.92f : (float) Math.pow((fgR + 0.055f) / 1.055f, 2.4f);
+        fgG = (fgG < 0.03928f) ? fgG / 12.92f : (float) Math.pow((fgG + 0.055f) / 1.055f, 2.4f);
+        fgB = (fgB < 0.03928f) ? fgB / 12.92f : (float) Math.pow((fgB + 0.055f) / 1.055f, 2.4f);
+        float fgL = 0.2126f * fgR + 0.7152f * fgG + 0.0722f * fgB;
+
+        return Math.abs((fgL + 0.05f) / (bgL + 0.05f));
+    }
+
+    /** Returns the base color overlaid with another overlay color with a specified alpha. */
+    public static int getColorWithOverlay(int baseColor, int overlayColor, float overlayAlpha) {
+        return Color.rgb(
+            (int) (overlayAlpha * Color.red(baseColor) +
+                    (1f - overlayAlpha) * Color.red(overlayColor)),
+            (int) (overlayAlpha * Color.green(baseColor) +
+                    (1f - overlayAlpha) * Color.green(overlayColor)),
+            (int) (overlayAlpha * Color.blue(baseColor) +
+                    (1f - overlayAlpha) * Color.blue(overlayColor)));
+    }
+
+    /**
+     * Cancels an animation ensuring that if it has listeners, onCancel and onEnd
+     * are not called.
+     */
+    public static void cancelAnimationWithoutCallbacks(Animator animator) {
+        if (animator != null && animator.isStarted()) {
+            removeAnimationListenersRecursive(animator);
+            animator.cancel();
+        }
+    }
+
+    /**
+     * Recursively removes all the listeners of all children of this animator
+     */
+    public static void removeAnimationListenersRecursive(Animator animator) {
+        if (animator instanceof AnimatorSet) {
+            ArrayList<Animator> animators = ((AnimatorSet) animator).getChildAnimations();
+            for (int i = animators.size() - 1; i >= 0; i--) {
+                removeAnimationListenersRecursive(animators.get(i));
+            }
+        }
+        animator.removeAllListeners();
+    }
+
+    /**
+     * Sets the given {@link View}'s frame from its current translation.
+     */
+    public static void setViewFrameFromTranslation(View v) {
+        RectF taskViewRect = new RectF(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
+        taskViewRect.offset(v.getTranslationX(), v.getTranslationY());
+        v.setTranslationX(0);
+        v.setTranslationY(0);
+        v.setLeftTopRightBottom((int) taskViewRect.left, (int) taskViewRect.top,
+                (int) taskViewRect.right, (int) taskViewRect.bottom);
+    }
+
+    /**
+     * Returns a view stub for the given view id.
+     */
+    public static ViewStub findViewStubById(View v, int stubId) {
+        return (ViewStub) v.findViewById(stubId);
+    }
+
+    /**
+     * Returns a view stub for the given view id.
+     */
+    public static ViewStub findViewStubById(Activity a, int stubId) {
+        return (ViewStub) a.findViewById(stubId);
+    }
+
+    /**
+     * Used for debugging, converts DP to PX.
+     */
+    public static float dpToPx(Resources res, float dp) {
+        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, res.getDisplayMetrics());
+    }
+
+    /**
+     * Adds a trace event for debugging.
+     */
+    public static void addTraceEvent(String event) {
+        Trace.traceBegin(Trace.TRACE_TAG_VIEW, event);
+        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+    }
+
+    /**
+     * Returns whether this view, or one of its descendants have accessibility focus.
+     */
+    public static boolean isDescendentAccessibilityFocused(View v) {
+        if (v.isAccessibilityFocused()) {
+            return true;
+        }
+
+        if (v instanceof ViewGroup) {
+            ViewGroup vg = (ViewGroup) v;
+            int childCount = vg.getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                if (isDescendentAccessibilityFocused(vg.getChildAt(i))) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the application configuration, which is independent of the activity's current
+     * configuration in multiwindow.
+     */
+    public static Configuration getAppConfiguration(Context context) {
+        return context.getApplicationContext().getResources().getConfiguration();
+    }
+
+    /**
+     * Returns a lightweight dump of a rect.
+     */
+    public static String dumpRect(Rect r) {
+        if (r == null) {
+            return "N:0,0-0,0";
+        }
+        return r.left + "," + r.top + "-" + r.right + "," + r.bottom;
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
new file mode 100644
index 0000000..3f93f76
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 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.systemui.shared.system;
+
+import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
+
+import android.annotation.NonNull;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RecentTaskInfo;
+import android.app.AppGlobals;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.IconDrawableFactory;
+import android.util.Log;
+
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ActivityManagerWrapper {
+
+    private static final String TAG = "ActivityManagerWrapper";
+
+    private static final ActivityManagerWrapper sInstance = new ActivityManagerWrapper();
+
+    private final PackageManager mPackageManager;
+    private final IconDrawableFactory mDrawableFactory;
+
+    private ActivityManagerWrapper() {
+        final Context context = AppGlobals.getInitialApplication();
+        mPackageManager = context.getPackageManager();
+        mDrawableFactory = IconDrawableFactory.newInstance(context);
+    }
+
+    public static ActivityManagerWrapper getInstance() {
+        return sInstance;
+    }
+
+    /**
+     * @return the current user's id.
+     */
+    public int getCurrentUserId() {
+        UserInfo ui;
+        try {
+            ui = ActivityManager.getService().getCurrentUser();
+            return ui != null ? ui.id : 0;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * @return a list of the recents tasks.
+     */
+    public List<RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
+        try {
+            return ActivityManager.getService().getRecentTasks(numTasks,
+                            RECENT_IGNORE_UNAVAILABLE, userId).getList();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to get recent tasks", e);
+            return new ArrayList<>();
+        }
+    }
+
+    /**
+     * @return the task snapshot for the given {@param taskId}.
+     */
+    public @NonNull ThumbnailData getTaskThumbnail(int taskId, boolean reducedResolution) {
+        ActivityManager.TaskSnapshot snapshot = null;
+        try {
+            snapshot = ActivityManager.getService().getTaskSnapshot(taskId, reducedResolution);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to retrieve task snapshot", e);
+        }
+        if (snapshot != null) {
+            return new ThumbnailData(snapshot);
+        } else {
+            return new ThumbnailData();
+        }
+    }
+
+    /**
+     * @return the task description icon, loading and badging it if it necessary.
+     */
+    public Drawable getBadgedTaskDescriptionIcon(Context context,
+            ActivityManager.TaskDescription taskDescription, int userId, Resources res) {
+        Bitmap tdIcon = taskDescription.getInMemoryIcon();
+        Drawable dIcon = null;
+        if (tdIcon != null) {
+            dIcon = new BitmapDrawable(res, tdIcon);
+        } else if (taskDescription.getIconResource() != 0) {
+            try {
+                dIcon = context.getDrawable(taskDescription.getIconResource());
+            } catch (NotFoundException e) {
+                Log.e(TAG, "Could not find icon drawable from resource", e);
+            }
+        } else {
+            tdIcon = ActivityManager.TaskDescription.loadTaskDescriptionIcon(
+                    taskDescription.getIconFilename(), userId);
+            if (tdIcon != null) {
+                dIcon = new BitmapDrawable(res, tdIcon);
+            }
+        }
+        if (dIcon != null) {
+            return getBadgedIcon(dIcon, userId);
+        }
+        return null;
+    }
+
+    /**
+     * @return the given icon for a user, badging if necessary.
+     */
+    private Drawable getBadgedIcon(Drawable icon, int userId) {
+        if (userId != UserHandle.myUserId()) {
+            icon = mPackageManager.getUserBadgedIcon(icon, new UserHandle(userId));
+        }
+        return icon;
+    }
+
+    /**
+     * @return the activity icon for the ActivityInfo for a user, badging if necessary.
+     */
+    public Drawable getBadgedActivityIcon(ActivityInfo info, int userId) {
+        return mDrawableFactory.getBadgedIcon(info, info.applicationInfo, userId);
+    }
+
+    /**
+     * @return the application icon for the ApplicationInfo for a user, badging if necessary.
+     */
+    public Drawable getBadgedApplicationIcon(ApplicationInfo appInfo, int userId) {
+        return mDrawableFactory.getBadgedIcon(appInfo, userId);
+    }
+
+    /**
+     * @return the activity label, badging if necessary.
+     */
+    public String getBadgedActivityLabel(ActivityInfo info, int userId) {
+        return getBadgedLabel(info.loadLabel(mPackageManager).toString(), userId);
+    }
+
+    /**
+     * @return the application label, badging if necessary.
+     */
+    public String getBadgedApplicationLabel(ApplicationInfo appInfo, int userId) {
+        return getBadgedLabel(appInfo.loadLabel(mPackageManager).toString(), userId);
+    }
+
+    /**
+     * @return the content description for a given task, badging it if necessary.  The content
+     * description joins the app and activity labels.
+     */
+    public String getBadgedContentDescription(ActivityInfo info, int userId,
+            ActivityManager.TaskDescription td) {
+        String activityLabel;
+        if (td != null && td.getLabel() != null) {
+            activityLabel = td.getLabel();
+        } else {
+            activityLabel = info.loadLabel(mPackageManager).toString();
+        }
+        String applicationLabel = info.applicationInfo.loadLabel(mPackageManager).toString();
+        String badgedApplicationLabel = getBadgedLabel(applicationLabel, userId);
+        return applicationLabel.equals(activityLabel)
+                ? badgedApplicationLabel
+                : badgedApplicationLabel + " " + activityLabel;
+    }
+
+    /**
+     * @return the given label for a user, badging if necessary.
+     */
+    private String getBadgedLabel(String label, int userId) {
+        if (userId != UserHandle.myUserId()) {
+            label = mPackageManager.getUserBadgedLabel(label, new UserHandle(userId)).toString();
+        }
+        return label;
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/PackageManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PackageManagerWrapper.java
new file mode 100644
index 0000000..d5e6e6e
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PackageManagerWrapper.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 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.systemui.shared.system;
+
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.os.RemoteException;
+
+public class PackageManagerWrapper {
+
+    private static final String TAG = "PackageManagerWrapper";
+
+    private static final PackageManagerWrapper sInstance = new PackageManagerWrapper();
+
+    private static final IPackageManager mIPackageManager = AppGlobals.getPackageManager();
+
+    public static PackageManagerWrapper getInstance() {
+        return sInstance;
+    }
+
+    /**
+     * @return the activity info for a given {@param componentName} and {@param userId}.
+     */
+    public ActivityInfo getActivityInfo(ComponentName componentName, int userId) {
+        try {
+            return mIPackageManager.getActivityInfo(componentName, PackageManager.GET_META_DATA,
+                    userId);
+        } catch (RemoteException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+}
diff --git a/packages/SystemUI/shared/tests/Android.mk b/packages/SystemUI/shared/tests/Android.mk
new file mode 100644
index 0000000..ce3b442
--- /dev/null
+++ b/packages/SystemUI/shared/tests/Android.mk
@@ -0,0 +1,53 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_USE_AAPT2 := true
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JACK_FLAGS := --multi-dex native
+LOCAL_DX_FLAGS := --multi-dex
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+LOCAL_PROTOC_FLAGS := -I$(LOCAL_PATH)/..
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
+
+LOCAL_PACKAGE_NAME := SystemUISharedLibTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
+# Add local path sources as well as shared lib sources
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+    $(call all-java-files-under, ../src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    metrics-helper-lib \
+    android-support-test \
+    mockito-target-minus-junit4 \
+    SystemUI-proto \
+    SystemUI-tags \
+    legacy-android-test \
+    testables \
+    truth-prebuilt \
+
+LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common android.car
+
+# sign this with platform cert, so this test is allowed to inject key events into
+# UI it doesn't own. This is necessary to allow screenshots to be taken
+LOCAL_CERTIFICATE := platform
+
+ifeq ($(EXCLUDE_SYSTEMUI_TESTS),)
+    include $(BUILD_PACKAGE)
+endif
\ No newline at end of file
diff --git a/packages/SystemUI/shared/tests/AndroidManifest.xml b/packages/SystemUI/shared/tests/AndroidManifest.xml
new file mode 100644
index 0000000..3e1de49
--- /dev/null
+++ b/packages/SystemUI/shared/tests/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.systemui.shared.tests">
+
+    <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.testing.TestableInstrumentation"
+        android:targetPackage="com.android.systemui.shared.tests"
+        android:label="Tests for SystemUISharedLib">
+    </instrumentation>
+</manifest>
diff --git a/packages/SystemUI/shared/tests/AndroidTest.xml b/packages/SystemUI/shared/tests/AndroidTest.xml
new file mode 100644
index 0000000..b3de836
--- /dev/null
+++ b/packages/SystemUI/shared/tests/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs Tests for SystemUISharedLib.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="SystemUISharedLibTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="framework-base-presubmit" />
+    <option name="test-tag" value="SystemUISharedLibTests" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.systemui.shared.tests" />
+        <option name="runner" value="android.testing.TestableInstrumentation" />
+    </test>
+</configuration>
diff --git a/packages/SystemUI/shared/tests/src/com/android/systemui/shared/SysuiSharedLibTestCase.java b/packages/SystemUI/shared/tests/src/com/android/systemui/shared/SysuiSharedLibTestCase.java
new file mode 100644
index 0000000..04b341e3
--- /dev/null
+++ b/packages/SystemUI/shared/tests/src/com/android/systemui/shared/SysuiSharedLibTestCase.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.MessageQueue;
+import android.support.test.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Before;
+
+/**
+ * Base class that does System UI Shared Lib specific setup.
+ */
+public abstract class SysuiSharedLibTestCase {
+
+    private static final String TAG = "SysuiSharedLibTestCase";
+
+    private Handler mHandler;
+    private Context mContext = InstrumentationRegistry.getContext();
+
+    @Before
+    public void SysuiSetup() throws Exception {
+        // Enable shared class loader to test package-private classes/methods
+        System.setProperty("dexmaker.share_classloader", "true");
+    }
+
+    @After
+    public void SysuiTeardown() {
+        // Do nothing
+    }
+
+    public Context getContext() {
+        return mContext;
+    }
+
+    protected void waitForIdleSync() {
+        if (mHandler == null) {
+            mHandler = new Handler(Looper.getMainLooper());
+        }
+        waitForIdleSync(mHandler);
+    }
+
+    public static void waitForIdleSync(Handler h) {
+        validateThread(h.getLooper());
+        Idler idler = new Idler(null);
+        h.getLooper().getQueue().addIdleHandler(idler);
+        // Ensure we are non-idle, so the idle handler can run.
+        h.post(new EmptyRunnable());
+        idler.waitForIdle();
+    }
+
+    private static final void validateThread(Looper l) {
+        if (Looper.myLooper() == l) {
+            throw new RuntimeException(
+                "This method can not be called from the looper being synced");
+        }
+    }
+
+    public static final class EmptyRunnable implements Runnable {
+        public void run() {
+        }
+    }
+
+    public static final class Idler implements MessageQueue.IdleHandler {
+        private final Runnable mCallback;
+        private boolean mIdle;
+
+        public Idler(Runnable callback) {
+            mCallback = callback;
+            mIdle = false;
+        }
+
+        @Override
+        public boolean queueIdle() {
+            if (mCallback != null) {
+                mCallback.run();
+            }
+            synchronized (this) {
+                mIdle = true;
+                notifyAll();
+            }
+            return false;
+        }
+
+        public void waitForIdle() {
+            synchronized (this) {
+                while (!mIdle) {
+                    try {
+                        wait();
+                    } catch (InterruptedException e) {
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/shared/tests/src/com/android/systemui/shared/recents/model/HighResThumbnailLoaderTest.java b/packages/SystemUI/shared/tests/src/com/android/systemui/shared/recents/model/HighResThumbnailLoaderTest.java
new file mode 100644
index 0000000..b03ea90
--- /dev/null
+++ b/packages/SystemUI/shared/tests/src/com/android/systemui/shared/recents/model/HighResThumbnailLoaderTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.shared.recents.model;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.Looper;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.systemui.shared.SysuiSharedLibTestCase;
+import com.android.systemui.shared.recents.model.Task.TaskKey;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * runtest --path frameworks/base/packages/SystemUI/shared/tests/src/com/android/systemui/shared/recents/model/HighResThumbnailLoaderTest.java
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class HighResThumbnailLoaderTest extends SysuiSharedLibTestCase {
+
+    private HighResThumbnailLoader mLoader;
+
+    @Mock
+    private ActivityManagerWrapper mMockActivityManagerWrapper;
+    @Mock
+    private Task mTask;
+
+    private ThumbnailData mThumbnailData = new ThumbnailData();
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mLoader = new HighResThumbnailLoader(mMockActivityManagerWrapper, Looper.getMainLooper(),
+                false /* reducedResolution */);
+        mTask.key = new TaskKey(0, WINDOWING_MODE_UNDEFINED, null, 0, 0);
+        when(mMockActivityManagerWrapper.getTaskThumbnail(anyInt(), anyBoolean()))
+                .thenReturn(mThumbnailData);
+        mLoader.setVisible(true);
+        mLoader.setTaskLoadQueueIdle(true);
+    }
+
+    @Test
+    public void testLoading() throws Exception {
+        mLoader.setVisible(true);
+        assertTrue(mLoader.isLoading());
+        mLoader.setVisible(false);
+        assertFalse(mLoader.isLoading());
+        mLoader.setVisible(true);
+        mLoader.setFlingingFast(true);
+        assertFalse(mLoader.isLoading());
+        mLoader.setFlingingFast(false);
+        assertTrue(mLoader.isLoading());
+        mLoader.setFlingingFast(false);
+        mLoader.setTaskLoadQueueIdle(false);
+        assertFalse(mLoader.isLoading());
+        mLoader.setTaskLoadQueueIdle(true);
+        assertTrue(mLoader.isLoading());
+    }
+
+    @Test
+    public void testLoad() throws Exception {
+        mLoader.onTaskVisible(mTask);
+        mLoader.waitForLoaderIdle();
+        waitForIdleSync();
+        verify(mTask).notifyTaskDataLoaded(mThumbnailData, null);
+    }
+
+    @Test
+    public void testFlinging_notLoaded() throws Exception {
+        mLoader.setFlingingFast(true);
+        mLoader.onTaskVisible(mTask);
+        mLoader.waitForLoaderIdle();
+        waitForIdleSync();
+        verify(mTask, never()).notifyTaskDataLoaded(mThumbnailData, null);
+    }
+
+    /**
+     * Tests whether task is loaded after stopping to fling
+     */
+    @Test
+    public void testAfterFlinging() throws Exception {
+        mLoader.setFlingingFast(true);
+        mLoader.onTaskVisible(mTask);
+        mLoader.setFlingingFast(false);
+        mLoader.waitForLoaderIdle();
+        waitForIdleSync();
+        verify(mTask).notifyTaskDataLoaded(mThumbnailData, null);
+    }
+
+    @Test
+    public void testAlreadyLoaded() throws Exception {
+        mTask.thumbnail = new ThumbnailData();
+        mTask.thumbnail.reducedResolution = false;
+        mLoader.onTaskVisible(mTask);
+        mLoader.waitForLoaderIdle();
+        waitForIdleSync();
+        verify(mTask, never()).notifyTaskDataLoaded(mThumbnailData, null);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierText.java b/packages/SystemUI/src/com/android/keyguard/CarrierText.java
index 159ac4c..13c48d0 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierText.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierText.java
@@ -39,6 +39,7 @@
 import com.android.internal.telephony.IccCardConstants.State;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.settingslib.WirelessUtils;
+import android.telephony.TelephonyManager;
 
 public class CarrierText extends TextView {
     private static final boolean DEBUG = KeyguardConstants.DEBUG;
@@ -52,6 +53,8 @@
 
     private WifiManager mWifiManager;
 
+    private boolean[] mSimErrorState = new boolean[TelephonyManager.getDefault().getPhoneCount()];
+
     private KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
         @Override
         public void onRefreshCarrierInfo() {
@@ -65,6 +68,22 @@
         public void onStartedWakingUp() {
             setSelected(true);
         };
+
+        public void onSimStateChanged(int subId, int slotId, IccCardConstants.State simState) {
+            if (slotId < 0) {
+                Log.d(TAG, "onSimStateChanged() - slotId invalid: " + slotId);
+                return;
+            }
+
+            if (DEBUG) Log.d(TAG,"onSimStateChanged: " + getStatusForIccState(simState));
+            if (getStatusForIccState(simState) == StatusMode.SimIoError) {
+                mSimErrorState[slotId] = true;
+                updateCarrierText();
+            } else if (mSimErrorState[slotId]) {
+                mSimErrorState[slotId] = false;
+                updateCarrierText();
+            }
+        };
     };
     /**
      * The status of this lock screen. Primarily used for widgets on LockScreen.
@@ -77,7 +96,8 @@
         SimPukLocked, // SIM card is PUK locked because SIM entered wrong too many times
         SimLocked, // SIM card is currently locked
         SimPermDisabled, // SIM card is permanently disabled due to PUK unlock failure
-        SimNotReady; // SIM is not ready yet. May never be on devices w/o a SIM.
+        SimNotReady, // SIM is not ready yet. May never be on devices w/o a SIM.
+        SimIoError; // SIM card is faulty
     }
 
     public CarrierText(Context context) {
@@ -101,6 +121,35 @@
         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
     }
 
+    /**
+     * Checks if there are faulty cards. Adds the text depending on the slot of the card
+     * @param text: current carrier text based on the sim state
+     * @param noSims: whether a valid sim card is inserted
+     * @return text
+    */
+    private CharSequence updateCarrierTextWithSimIoError(CharSequence text, boolean noSims) {
+        final CharSequence carrier = "";
+        CharSequence carrierTextForSimIOError = getCarrierTextForSimState(
+            IccCardConstants.State.CARD_IO_ERROR, carrier);
+        for (int index = 0; index < mSimErrorState.length; index++) {
+            if (mSimErrorState[index]) {
+                // In the case when no sim cards are detected but a faulty card is inserted
+                // overwrite the text and only show "Invalid card"
+                if (noSims) {
+                    return concatenate(carrierTextForSimIOError,
+                        getContext().getText(com.android.internal.R.string.emergency_calls_only));
+                } else if (index == 0) {
+                    // prepend "Invalid card" when faulty card is inserted in slot 0
+                    text = concatenate(carrierTextForSimIOError, text);
+                } else {
+                    // concatenate "Invalid card" when faulty card is inserted in slot 1
+                    text = concatenate(text, carrierTextForSimIOError);
+                }
+            }
+        }
+        return text;
+    }
+
     protected void updateCarrierText() {
         boolean allSimsMissing = true;
         boolean anySimReadyAndInService = false;
@@ -179,6 +228,7 @@
             }
         }
 
+        displayText = updateCarrierTextWithSimIoError(displayText, allSimsMissing);
         // APM (airplane mode) != no carrier state. There are carrier services
         // (e.g. WFC = Wi-Fi calling) which may operate in APM.
         if (!anySimReadyAndInService && WirelessUtils.isAirplaneModeOn(mContext)) {
@@ -270,6 +320,11 @@
                         getContext().getText(R.string.keyguard_sim_puk_locked_message),
                         text);
                 break;
+            case SimIoError:
+                carrierText = makeCarrierStringOnEmergencyCapable(
+                        getContext().getText(R.string.keyguard_sim_error_message_short),
+                        text);
+                break;
         }
 
         return carrierText;
@@ -319,6 +374,8 @@
                 return StatusMode.SimPermDisabled;
             case UNKNOWN:
                 return StatusMode.SimMissing;
+            case CARD_IO_ERROR:
+                return StatusMode.SimIoError;
         }
         return StatusMode.SimMissing;
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
index 7baa57e..0cb6423 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -57,16 +57,16 @@
     SecurityMode getSecurityMode(int userId) {
         KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
 
-        if (SubscriptionManager.isValidSubscriptionId(
-                monitor.getNextSubIdForState(IccCardConstants.State.PIN_REQUIRED))) {
-            return SecurityMode.SimPin;
-        }
-
         if (mIsPukScreenAvailable && SubscriptionManager.isValidSubscriptionId(
                 monitor.getNextSubIdForState(IccCardConstants.State.PUK_REQUIRED))) {
             return SecurityMode.SimPuk;
         }
 
+        if (SubscriptionManager.isValidSubscriptionId(
+                monitor.getNextSubIdForState(IccCardConstants.State.PIN_REQUIRED))) {
+            return SecurityMode.SimPin;
+        }
+
         final int security = mLockPatternUtils.getActivePasswordQuality(userId);
         switch (security) {
             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index d83a6c6..2bb992c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -52,7 +52,6 @@
 import android.os.BatteryManager;
 import android.os.CancellationSignal;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.IRemoteCallback;
 import android.os.Message;
 import android.os.RemoteException;
@@ -78,7 +77,7 @@
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
+import com.android.systemui.recents.misc.TaskStackChangeListener;
 
 import com.google.android.collect.Lists;
 
@@ -902,6 +901,8 @@
                 }
             } else if (IccCardConstants.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) {
                 state = IccCardConstants.State.NETWORK_LOCKED;
+            } else if (IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR.equals(stateExtra)) {
+                state = IccCardConstants.State.CARD_IO_ERROR;
             } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(stateExtra)
                         || IccCardConstants.INTENT_VALUE_ICC_IMSI.equals(stateExtra)) {
                 // This is required because telephony doesn't return to "READY" after
@@ -1771,7 +1772,7 @@
         }
     }
 
-    private final TaskStackListener mTaskStackListener = new TaskStackListener() {
+    private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
         @Override
         public void onTaskStackChangedBackground() {
             try {
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 2937a25..d8a47c5 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -22,6 +22,8 @@
 import android.os.Looper;
 import android.os.Process;
 import android.util.ArrayMap;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.NightDisplayController;
@@ -304,6 +306,8 @@
 
         mProviders.put(LightBarController.class, () -> new LightBarController(mContext));
 
+        mProviders.put(IWindowManager.class, () -> WindowManagerGlobal.getWindowManagerService());
+
         // Put all dependencies above here so the factory can override them if it wants.
         SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 907a79e..593bb50 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -16,11 +16,6 @@
 
 package com.android.systemui;
 
-import static android.opengl.GLES20.*;
-
-import static javax.microedition.khronos.egl.EGL10.*;
-
-import android.app.ActivityManager;
 import android.app.WallpaperManager;
 import android.content.ComponentCallbacks2;
 import android.graphics.Bitmap;
@@ -28,31 +23,18 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region.Op;
-import android.opengl.GLUtils;
 import android.os.AsyncTask;
-import android.os.SystemProperties;
 import android.os.Trace;
-import android.renderscript.Matrix4f;
 import android.service.wallpaper.WallpaperService;
 import android.util.Log;
 import android.view.Display;
 import android.view.DisplayInfo;
-import android.view.MotionEvent;
 import android.view.SurfaceHolder;
 import android.view.WindowManager;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.FloatBuffer;
-
-import javax.microedition.khronos.egl.EGL10;
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.egl.EGLContext;
-import javax.microedition.khronos.egl.EGLDisplay;
-import javax.microedition.khronos.egl.EGLSurface;
 
 /**
  * Default built-in wallpaper that simply shows a static image.
@@ -64,24 +46,13 @@
     private static final boolean DEBUG = false;
     private static final String PROPERTY_KERNEL_QEMU = "ro.kernel.qemu";
 
-    static final boolean FIXED_SIZED_SURFACE = true;
-    static final boolean USE_OPENGL = true;
-
-    WallpaperManager mWallpaperManager;
-
-    DrawableEngine mEngine;
-
-    boolean mIsHwAccelerated;
+    private WallpaperManager mWallpaperManager;
+    private DrawableEngine mEngine;
 
     @Override
     public void onCreate() {
         super.onCreate();
-        mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE);
-
-        //noinspection PointlessBooleanExpression,ConstantConditions
-        if (FIXED_SIZED_SURFACE && USE_OPENGL) {
-            mIsHwAccelerated = ActivityManager.isHighEndGfx();
-        }
+        mWallpaperManager = getSystemService(WallpaperManager.class);
     }
 
     @Override
@@ -98,15 +69,12 @@
     }
 
     class DrawableEngine extends Engine {
-        static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
-        static final int EGL_OPENGL_ES2_BIT = 4;
-
         Bitmap mBackground;
         int mBackgroundWidth = -1, mBackgroundHeight = -1;
         int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
         int mLastRotation = -1;
-        float mXOffset = 0.5f;
-        float mYOffset = 0.5f;
+        float mXOffset = 0f;
+        float mYOffset = 0f;
         float mScale = 1f;
 
         private Display mDefaultDisplay;
@@ -117,34 +85,6 @@
         int mLastXTranslation;
         int mLastYTranslation;
 
-        private EGL10 mEgl;
-        private EGLDisplay mEglDisplay;
-        private EGLConfig mEglConfig;
-        private EGLContext mEglContext;
-        private EGLSurface mEglSurface;
-
-        private static final String sSimpleVS =
-                "attribute vec4 position;\n" +
-                "attribute vec2 texCoords;\n" +
-                "varying vec2 outTexCoords;\n" +
-                "uniform mat4 projection;\n" +
-                "\nvoid main(void) {\n" +
-                "    outTexCoords = texCoords;\n" +
-                "    gl_Position = projection * position;\n" +
-                "}\n\n";
-        private static final String sSimpleFS =
-                "precision mediump float;\n\n" +
-                "varying vec2 outTexCoords;\n" +
-                "uniform sampler2D texture;\n" +
-                "\nvoid main(void) {\n" +
-                "    gl_FragColor = texture2D(texture, outTexCoords);\n" +
-                "}\n\n";
-
-        private static final int FLOAT_SIZE_BYTES = 4;
-        private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
-        private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
-        private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
-
         private int mRotationAtLastSurfaceSizeUpdate = -1;
         private int mDisplayWidthAtLastSurfaceSizeUpdate = -1;
         private int mDisplayHeightAtLastSurfaceSizeUpdate = -1;
@@ -154,13 +94,14 @@
         private AsyncTask<Void, Void, Bitmap> mLoader;
         private boolean mNeedsDrawAfterLoadingWallpaper;
         private boolean mSurfaceValid;
+        private boolean mSurfaceRedrawNeeded;
 
-        public DrawableEngine() {
+        DrawableEngine() {
             super();
             setFixedSizeAllowed(true);
         }
 
-        public void trimMemory(int level) {
+        void trimMemory(int level) {
             if (level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW
                     && level <= ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL
                     && mBackground != null) {
@@ -179,6 +120,7 @@
 
             super.onCreate(surfaceHolder);
 
+            //noinspection ConstantConditions
             mDefaultDisplay = getSystemService(WindowManager.class).getDefaultDisplay();
             setOffsetNotificationsEnabled(false);
 
@@ -199,7 +141,7 @@
             // Load background image dimensions, if we haven't saved them yet
             if (mBackgroundWidth <= 0 || mBackgroundHeight <= 0) {
                 // Need to load the image to get dimensions
-                loadWallpaper(forDraw, false /* needsReset */);
+                loadWallpaper(forDraw);
                 if (DEBUG) {
                     Log.d(TAG, "Reloading, redoing updateSurfaceSize later.");
                 }
@@ -210,16 +152,13 @@
             int surfaceWidth = Math.max(displayInfo.logicalWidth, mBackgroundWidth);
             int surfaceHeight = Math.max(displayInfo.logicalHeight, mBackgroundHeight);
 
-            if (FIXED_SIZED_SURFACE) {
-                // Used a fixed size surface, because we are special.  We can do
-                // this because we know the current design of window animations doesn't
-                // cause this to break.
-                surfaceHolder.setFixedSize(surfaceWidth, surfaceHeight);
-                mLastRequestedWidth = surfaceWidth;
-                mLastRequestedHeight = surfaceHeight;
-            } else {
-                surfaceHolder.setSizeFromLayout();
-            }
+            // Used a fixed size surface, because we are special.  We can do
+            // this because we know the current design of window animations doesn't
+            // cause this to break.
+            surfaceHolder.setFixedSize(surfaceWidth, surfaceHeight);
+            mLastRequestedWidth = surfaceWidth;
+            mLastRequestedHeight = surfaceHeight;
+
             return hasWallpaper;
         }
 
@@ -300,6 +239,13 @@
                 Log.d(TAG, "onSurfaceRedrawNeeded");
             }
             super.onSurfaceRedrawNeeded(holder);
+            // At the end of this method we should have drawn into the surface.
+            // This means that the bitmap should be loaded synchronously if
+            // it was already unloaded.
+            if (mBackground == null) {
+                updateBitmap(mWallpaperManager.getBitmap(true /* hardware */));
+            }
+            mSurfaceRedrawNeeded = true;
             drawFrame();
         }
 
@@ -336,7 +282,8 @@
                 boolean surfaceDimensionsChanged = dw != mLastSurfaceWidth
                         || dh != mLastSurfaceHeight;
 
-                boolean redrawNeeded = surfaceDimensionsChanged || newRotation != mLastRotation;
+                boolean redrawNeeded = surfaceDimensionsChanged || newRotation != mLastRotation
+                        || mSurfaceRedrawNeeded;
                 if (!redrawNeeded && !mOffsetsChanged) {
                     if (DEBUG) {
                         Log.d(TAG, "Suppressed drawFrame since redraw is not needed "
@@ -345,40 +292,24 @@
                     return;
                 }
                 mLastRotation = newRotation;
+                mSurfaceRedrawNeeded = false;
 
                 // Load bitmap if it is not yet loaded
                 if (mBackground == null) {
-                    if (DEBUG) {
-                        Log.d(TAG, "Reloading bitmap: mBackground, bgw, bgh, dw, dh = " +
-                                mBackground + ", " +
-                                ((mBackground == null) ? 0 : mBackground.getWidth()) + ", " +
-                                ((mBackground == null) ? 0 : mBackground.getHeight()) + ", " +
-                                dw + ", " + dh);
-                    }
-                    loadWallpaper(true /* needDraw */, true /* needReset */);
+                    loadWallpaper(true);
                     if (DEBUG) {
                         Log.d(TAG, "Reloading, resuming draw later");
                     }
                     return;
                 }
 
-                // Center the scaled image
+                // Left align the scaled image
                 mScale = Math.max(1f, Math.max(dw / (float) mBackground.getWidth(),
                         dh / (float) mBackground.getHeight()));
-                final int availw = dw - (int) (mBackground.getWidth() * mScale);
-                final int availh = dh - (int) (mBackground.getHeight() * mScale);
-                int xPixels = availw / 2;
-                int yPixels = availh / 2;
-
-                // Adjust the image for xOffset/yOffset values. If window manager is handling offsets,
-                // mXOffset and mYOffset are set to 0.5f by default and therefore xPixels and yPixels
-                // will remain unchanged
-                final int availwUnscaled = dw - mBackground.getWidth();
-                final int availhUnscaled = dh - mBackground.getHeight();
-                if (availwUnscaled < 0)
-                    xPixels += (int) (availwUnscaled * (mXOffset - .5f) + .5f);
-                if (availhUnscaled < 0)
-                    yPixels += (int) (availhUnscaled * (mYOffset - .5f) + .5f);
+                final int availw = (int) (mBackground.getWidth() * mScale) - dw;
+                final int availh = (int) (mBackground.getHeight() * mScale) - dh;
+                int xPixels = (int) (availw * mXOffset);
+                int yPixels = (int) (availh * mYOffset);
 
                 mOffsetsChanged = false;
                 if (surfaceDimensionsChanged) {
@@ -399,21 +330,7 @@
                     Log.d(TAG, "Redrawing wallpaper");
                 }
 
-                if (mIsHwAccelerated) {
-                    if (!drawWallpaperWithOpenGL(sh, availw, availh, xPixels, yPixels)) {
-                        drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels);
-                    }
-                } else {
-                    drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels);
-                    if (FIXED_SIZED_SURFACE) {
-                        // If the surface is fixed-size, we should only need to
-                        // draw it once and then we'll let the window manager
-                        // position it appropriately.  As such, we no longer needed
-                        // the loaded bitmap.  Yay!
-                        // hw-accelerated renderer retains bitmap for faster rotation
-                        unloadWallpaper(false /* forgetSize */);
-                    }
-                }
+                drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels);
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
             }
@@ -428,28 +345,20 @@
          *
          * If {@param needsReset} is set also clears the cache in WallpaperManager first.
          */
-        private void loadWallpaper(boolean needsDraw, boolean needsReset) {
+        private void loadWallpaper(boolean needsDraw) {
             mNeedsDrawAfterLoadingWallpaper |= needsDraw;
             if (mLoader != null) {
-                if (needsReset) {
-                    mLoader.cancel(false /* interrupt */);
-                    mLoader = null;
-                } else {
-                    if (DEBUG) {
-                        Log.d(TAG, "Skipping loadWallpaper, already in flight ");
-                    }
-                    return;
+                if (DEBUG) {
+                    Log.d(TAG, "Skipping loadWallpaper, already in flight ");
                 }
+                return;
             }
             mLoader = new AsyncTask<Void, Void, Bitmap>() {
                 @Override
                 protected Bitmap doInBackground(Void... params) {
                     Throwable exception;
                     try {
-                        if (needsReset) {
-                            mWallpaperManager.forgetLoadedWallpaper();
-                        }
-                        return mWallpaperManager.getBitmap();
+                        return mWallpaperManager.getBitmap(true /* hardware */);
                     } catch (RuntimeException | OutOfMemoryError e) {
                         exception = e;
                     }
@@ -458,48 +367,33 @@
                         return null;
                     }
 
-                    if (exception != null) {
-                        // Note that if we do fail at this, and the default wallpaper can't
-                        // be loaded, we will go into a cycle.  Don't do a build where the
-                        // default wallpaper can't be loaded.
-                        Log.w(TAG, "Unable to load wallpaper!", exception);
-                        try {
-                            mWallpaperManager.clear();
-                        } catch (IOException ex) {
-                            // now we're really screwed.
-                            Log.w(TAG, "Unable reset to default wallpaper!", ex);
-                        }
+                    // Note that if we do fail at this, and the default wallpaper can't
+                    // be loaded, we will go into a cycle.  Don't do a build where the
+                    // default wallpaper can't be loaded.
+                    Log.w(TAG, "Unable to load wallpaper!", exception);
+                    try {
+                        mWallpaperManager.clear();
+                    } catch (IOException ex) {
+                        // now we're really screwed.
+                        Log.w(TAG, "Unable reset to default wallpaper!", ex);
+                    }
 
-                        if (isCancelled()) {
-                            return null;
-                        }
+                    if (isCancelled()) {
+                        return null;
+                    }
 
-                        try {
-                            return mWallpaperManager.getBitmap();
-                        } catch (RuntimeException | OutOfMemoryError e) {
-                            Log.w(TAG, "Unable to load default wallpaper!", e);
-                        }
+                    try {
+                        return mWallpaperManager.getBitmap(true /* hardware */);
+                    } catch (RuntimeException | OutOfMemoryError e) {
+                        Log.w(TAG, "Unable to load default wallpaper!", e);
                     }
                     return null;
                 }
 
                 @Override
                 protected void onPostExecute(Bitmap b) {
-                    mBackground = null;
-                    mBackgroundWidth = -1;
-                    mBackgroundHeight = -1;
+                    updateBitmap(b);
 
-                    if (b != null) {
-                        mBackground = b;
-                        mBackgroundWidth = mBackground.getWidth();
-                        mBackgroundHeight = mBackground.getHeight();
-                    }
-
-                    if (DEBUG) {
-                        Log.d(TAG, "Wallpaper loaded: " + mBackground);
-                    }
-                    updateSurfaceSize(getSurfaceHolder(), getDefaultDisplayInfo(),
-                            false /* forDraw */);
                     if (mNeedsDrawAfterLoadingWallpaper) {
                         drawFrame();
                     }
@@ -510,6 +404,24 @@
             }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
         }
 
+        private void updateBitmap(Bitmap bitmap) {
+            mBackground = null;
+            mBackgroundWidth = -1;
+            mBackgroundHeight = -1;
+
+            if (bitmap != null) {
+                mBackground = bitmap;
+                mBackgroundWidth = mBackground.getWidth();
+                mBackgroundHeight = mBackground.getHeight();
+            }
+
+            if (DEBUG) {
+                Log.d(TAG, "Wallpaper loaded: " + mBackground);
+            }
+            updateSurfaceSize(getSurfaceHolder(), getDefaultDisplayInfo(),
+                    false /* forDraw */);
+        }
+
         private void unloadWallpaper(boolean forgetSize) {
             if (mLoader != null) {
                 mLoader.cancel(false);
@@ -564,7 +476,7 @@
         }
 
         private void drawWallpaperWithCanvas(SurfaceHolder sh, int w, int h, int left, int top) {
-            Canvas c = sh.lockCanvas();
+            Canvas c = sh.lockHardwareCanvas();
             if (c != null) {
                 try {
                     if (DEBUG) {
@@ -590,278 +502,5 @@
                 }
             }
         }
-
-        private boolean drawWallpaperWithOpenGL(SurfaceHolder sh, int w, int h, int left, int top) {
-            if (!initGL(sh)) return false;
-
-            final float right = left + mBackground.getWidth() * mScale;
-            final float bottom = top + mBackground.getHeight() * mScale;
-
-            final Rect frame = sh.getSurfaceFrame();
-            final Matrix4f ortho = new Matrix4f();
-            ortho.loadOrtho(0.0f, frame.width(), frame.height(), 0.0f, -1.0f, 1.0f);
-
-            final FloatBuffer triangleVertices = createMesh(left, top, right, bottom);
-
-            final int texture = loadTexture(mBackground);
-            final int program = buildProgram(sSimpleVS, sSimpleFS);
-
-            final int attribPosition = glGetAttribLocation(program, "position");
-            final int attribTexCoords = glGetAttribLocation(program, "texCoords");
-            final int uniformTexture = glGetUniformLocation(program, "texture");
-            final int uniformProjection = glGetUniformLocation(program, "projection");
-
-            checkGlError();
-
-            glViewport(0, 0, frame.width(), frame.height());
-            glBindTexture(GL_TEXTURE_2D, texture);
-
-            glUseProgram(program);
-            glEnableVertexAttribArray(attribPosition);
-            glEnableVertexAttribArray(attribTexCoords);
-            glUniform1i(uniformTexture, 0);
-            glUniformMatrix4fv(uniformProjection, 1, false, ortho.getArray(), 0);
-
-            checkGlError();
-
-            if (w > 0 || h > 0) {
-                glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-                glClear(GL_COLOR_BUFFER_BIT);
-            }
-
-            // drawQuad
-            triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
-            glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false,
-                    TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
-
-            triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
-            glVertexAttribPointer(attribTexCoords, 3, GL_FLOAT, false,
-                    TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
-
-            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
-            boolean status = mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
-            checkEglError();
-
-            finishGL(texture, program);
-
-            return status;
-        }
-
-        private FloatBuffer createMesh(int left, int top, float right, float bottom) {
-            final float[] verticesData = {
-                    // X, Y, Z, U, V
-                     left,  bottom, 0.0f, 0.0f, 1.0f,
-                     right, bottom, 0.0f, 1.0f, 1.0f,
-                     left,  top,    0.0f, 0.0f, 0.0f,
-                     right, top,    0.0f, 1.0f, 0.0f,
-            };
-
-            final int bytes = verticesData.length * FLOAT_SIZE_BYTES;
-            final FloatBuffer triangleVertices = ByteBuffer.allocateDirect(bytes).order(
-                    ByteOrder.nativeOrder()).asFloatBuffer();
-            triangleVertices.put(verticesData).position(0);
-            return triangleVertices;
-        }
-
-        private int loadTexture(Bitmap bitmap) {
-            int[] textures = new int[1];
-
-            glActiveTexture(GL_TEXTURE0);
-            glGenTextures(1, textures, 0);
-            checkGlError();
-
-            int texture = textures[0];
-            glBindTexture(GL_TEXTURE_2D, texture);
-            checkGlError();
-
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
-            GLUtils.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap, GL_UNSIGNED_BYTE, 0);
-            checkGlError();
-
-            return texture;
-        }
-
-        private int buildProgram(String vertex, String fragment) {
-            int vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
-            if (vertexShader == 0) return 0;
-
-            int fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
-            if (fragmentShader == 0) return 0;
-
-            int program = glCreateProgram();
-            glAttachShader(program, vertexShader);
-            glAttachShader(program, fragmentShader);
-            glLinkProgram(program);
-            checkGlError();
-
-            glDeleteShader(vertexShader);
-            glDeleteShader(fragmentShader);
-
-            int[] status = new int[1];
-            glGetProgramiv(program, GL_LINK_STATUS, status, 0);
-            if (status[0] != GL_TRUE) {
-                String error = glGetProgramInfoLog(program);
-                Log.d(GL_LOG_TAG, "Error while linking program:\n" + error);
-                glDeleteProgram(program);
-                return 0;
-            }
-
-            return program;
-        }
-
-        private int buildShader(String source, int type) {
-            int shader = glCreateShader(type);
-
-            glShaderSource(shader, source);
-            checkGlError();
-
-            glCompileShader(shader);
-            checkGlError();
-
-            int[] status = new int[1];
-            glGetShaderiv(shader, GL_COMPILE_STATUS, status, 0);
-            if (status[0] != GL_TRUE) {
-                String error = glGetShaderInfoLog(shader);
-                Log.d(GL_LOG_TAG, "Error while compiling shader:\n" + error);
-                glDeleteShader(shader);
-                return 0;
-            }
-
-            return shader;
-        }
-
-        private void checkEglError() {
-            int error = mEgl.eglGetError();
-            if (error != EGL_SUCCESS) {
-                Log.w(GL_LOG_TAG, "EGL error = " + GLUtils.getEGLErrorString(error));
-            }
-        }
-
-        private void checkGlError() {
-            int error = glGetError();
-            if (error != GL_NO_ERROR) {
-                Log.w(GL_LOG_TAG, "GL error = 0x" + Integer.toHexString(error), new Throwable());
-            }
-        }
-
-        private void finishGL(int texture, int program) {
-            int[] textures = new int[1];
-            textures[0] = texture;
-            glDeleteTextures(1, textures, 0);
-            glDeleteProgram(program);
-            mEgl.eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-            mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
-            mEgl.eglDestroyContext(mEglDisplay, mEglContext);
-            mEgl.eglTerminate(mEglDisplay);
-        }
-
-        private boolean initGL(SurfaceHolder surfaceHolder) {
-            mEgl = (EGL10) EGLContext.getEGL();
-
-            mEglDisplay = mEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
-            if (mEglDisplay == EGL_NO_DISPLAY) {
-                throw new RuntimeException("eglGetDisplay failed " +
-                        GLUtils.getEGLErrorString(mEgl.eglGetError()));
-            }
-
-            int[] version = new int[2];
-            if (!mEgl.eglInitialize(mEglDisplay, version)) {
-                throw new RuntimeException("eglInitialize failed " +
-                        GLUtils.getEGLErrorString(mEgl.eglGetError()));
-            }
-
-            mEglConfig = chooseEglConfig();
-            if (mEglConfig == null) {
-                throw new RuntimeException("eglConfig not initialized");
-            }
-
-            mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
-            if (mEglContext == EGL_NO_CONTEXT) {
-                throw new RuntimeException("createContext failed " +
-                        GLUtils.getEGLErrorString(mEgl.eglGetError()));
-            }
-
-            int attribs[] = {
-                EGL_WIDTH, 1,
-                EGL_HEIGHT, 1,
-                EGL_NONE
-            };
-            EGLSurface tmpSurface = mEgl.eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs);
-            mEgl.eglMakeCurrent(mEglDisplay, tmpSurface, tmpSurface, mEglContext);
-
-            int[] maxSize = new int[1];
-            Rect frame = surfaceHolder.getSurfaceFrame();
-            glGetIntegerv(GL_MAX_TEXTURE_SIZE, maxSize, 0);
-
-            mEgl.eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-            mEgl.eglDestroySurface(mEglDisplay, tmpSurface);
-
-            if(frame.width() > maxSize[0] || frame.height() > maxSize[0]) {
-                mEgl.eglDestroyContext(mEglDisplay, mEglContext);
-                mEgl.eglTerminate(mEglDisplay);
-                Log.e(GL_LOG_TAG, "requested  texture size " +
-                    frame.width() + "x" + frame.height() + " exceeds the support maximum of " +
-                    maxSize[0] + "x" + maxSize[0]);
-                return false;
-            }
-
-            mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceHolder, null);
-            if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
-                int error = mEgl.eglGetError();
-                if (error == EGL_BAD_NATIVE_WINDOW || error == EGL_BAD_ALLOC) {
-                    Log.e(GL_LOG_TAG, "createWindowSurface returned " +
-                                         GLUtils.getEGLErrorString(error) + ".");
-                    return false;
-                }
-                throw new RuntimeException("createWindowSurface failed " +
-                        GLUtils.getEGLErrorString(error));
-            }
-
-            if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
-                throw new RuntimeException("eglMakeCurrent failed " +
-                        GLUtils.getEGLErrorString(mEgl.eglGetError()));
-            }
-
-            return true;
-        }
-
-
-        EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
-            int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
-            return egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, attrib_list);
-        }
-
-        private EGLConfig chooseEglConfig() {
-            int[] configsCount = new int[1];
-            EGLConfig[] configs = new EGLConfig[1];
-            int[] configSpec = getConfig();
-            if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
-                throw new IllegalArgumentException("eglChooseConfig failed " +
-                        GLUtils.getEGLErrorString(mEgl.eglGetError()));
-            } else if (configsCount[0] > 0) {
-                return configs[0];
-            }
-            return null;
-        }
-
-        private int[] getConfig() {
-            return new int[] {
-                    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-                    EGL_RED_SIZE, 8,
-                    EGL_GREEN_SIZE, 8,
-                    EGL_BLUE_SIZE, 8,
-                    EGL_ALPHA_SIZE, 0,
-                    EGL_DEPTH_SIZE, 0,
-                    EGL_STENCIL_SIZE, 0,
-                    EGL_CONFIG_CAVEAT, EGL_NONE,
-                    EGL_NONE
-            };
-        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
index f198229..4c3d5ba 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.keyguard;
 
-import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.IActivityManager;
@@ -29,9 +28,8 @@
 import android.os.UserHandle;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
+import com.android.systemui.recents.misc.TaskStackChangeListener;
 
 public class WorkLockActivityController {
     private final Context mContext;
@@ -98,7 +96,7 @@
         }
     }
 
-    private final TaskStackListener mLockListener = new TaskStackListener() {
+    private final TaskStackChangeListener mLockListener = new TaskStackChangeListener() {
         @Override
         public void onTaskProfileLocked(int taskId, int userId) {
             startWorkChallengeInTask(taskId, userId);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
index abc5667..e6d6c55 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
@@ -28,8 +28,6 @@
 import android.view.IWindowManager;
 import android.view.MotionEvent;
 
-import com.android.systemui.recents.misc.Utilities;
-
 import java.io.PrintWriter;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index f8996aa..7e87666 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -41,8 +41,7 @@
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.component.ExpandPipEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
-import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.recents.misc.TaskStackChangeListener;
 
 import java.io.PrintWriter;
 
@@ -70,7 +69,7 @@
     /**
      * Handler for system task stack changes.
      */
-    TaskStackListener mTaskStackListener = new TaskStackListener() {
+    TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
         @Override
         public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
             mTouchHandler.onActivityPinned();
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index e0445c1..312b990 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -20,7 +20,6 @@
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManager.StackInfo;
 import android.app.IActivityManager;
-import android.app.RemoteAction;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -47,7 +46,7 @@
 import com.android.systemui.R;
 import com.android.systemui.pip.BasePipManager;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
+import com.android.systemui.recents.misc.TaskStackChangeListener;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -621,7 +620,7 @@
         return false;
     }
 
-    private TaskStackListener mTaskStackListener = new TaskStackListener() {
+    private TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
         @Override
         public void onTaskStackChanged() {
             if (DEBUG) Log.d(TAG, "onTaskStackChanged()");
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index f378268..c1a3623 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -28,8 +28,14 @@
 import android.os.BatteryManager;
 import android.os.Handler;
 import android.os.HardwarePropertiesManager;
+import android.os.IBinder;
+import android.os.IThermalEventListener;
+import android.os.IThermalService;
 import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.Temperature;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.format.DateUtils;
@@ -75,6 +81,7 @@
     private float[] mRecentTemps = new float[MAX_RECENT_TEMPS];
     private int mNumTemps;
     private long mNextLogTime;
+    private IThermalService mThermalService;
 
     // We create a method reference here so that we are guaranteed that we can remove a callback
     // by using the same instance (method references are not guaranteed to be the same object
@@ -263,7 +270,7 @@
                 resources.getInteger(R.integer.config_warningTemperature));
 
         if (mThresholdTemp < 0f) {
-            // Get the throttling temperature. No need to check if we're not throttling.
+            // Get the shutdown temperature, adjust for warning tolerance.
             float[] throttlingTemps = mHardwarePropertiesManager.getDeviceTemperatures(
                     HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
                     HardwarePropertiesManager.TEMPERATURE_SHUTDOWN);
@@ -276,6 +283,25 @@
                     resources.getInteger(R.integer.config_warningTemperatureTolerance);
         }
 
+        if (mThermalService == null) {
+            // Enable push notifications of throttling from vendor thermal
+            // management subsystem via thermalservice, in addition to our
+            // usual polling, to react to temperature jumps more quickly.
+            IBinder b = ServiceManager.getService("thermalservice");
+
+            if (b != null) {
+                mThermalService = IThermalService.Stub.asInterface(b);
+                try {
+                    mThermalService.registerThermalEventListener(
+                        new ThermalEventListener());
+                } catch (RemoteException e) {
+                    // Should never happen.
+                }
+            } else {
+                Slog.w(TAG, "cannot find thermalservice, no throttling push notifications");
+            }
+        }
+
         setNextLogTime();
 
         // This initialization method may be called on a configuration change. Only one set of
@@ -414,5 +440,15 @@
         void dump(PrintWriter pw);
         void userSwitched();
     }
-}
 
+    // Thermal event received from vendor thermal management subsystem
+    private final class ThermalEventListener extends IThermalEventListener.Stub {
+        @Override public void notifyThrottling(boolean isThrottling, Temperature temp) {
+            // Trigger an update of the temperature warning.  Only one
+            // callback can be enabled at a time, so remove any existing
+            // callback; updateTemperatureWarning will schedule another one.
+            mHandler.removeCallbacks(mUpdateTempCallback);
+            updateTemperatureWarning();
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
index b4cc4b1..8869e8d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
@@ -34,6 +34,7 @@
 import android.widget.TextView;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
+import com.android.systemui.plugins.qs.QSTile;
 
 /**
  * Quick settings common detail view with line items.
@@ -185,7 +186,7 @@
             view.setVisibility(mItemsVisible ? VISIBLE : INVISIBLE);
             final ImageView iv = (ImageView) view.findViewById(android.R.id.icon);
             if (item.iconDrawable != null) {
-                iv.setImageDrawable(item.iconDrawable);
+                iv.setImageDrawable(item.iconDrawable.getDrawable(iv.getContext()));
             } else {
                 iv.setImageResource(item.icon);
             }
@@ -258,7 +259,7 @@
 
     public static class Item {
         public int icon;
-        public Drawable iconDrawable;
+        public QSTile.Icon iconDrawable;
         public Drawable overlay;
         public CharSequence line1;
         public CharSequence line2;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 176112b..b3244a5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -305,7 +305,15 @@
             state.state = Tile.STATE_UNAVAILABLE;
             drawable = mDefaultIcon.loadDrawable(mContext);
         }
-        state.icon = new DrawableIcon(drawable);
+
+        final Drawable drawableF = drawable;
+        state.iconSupplier = () -> {
+            Drawable.ConstantState cs = drawableF.getConstantState();
+            if (cs != null) {
+                return new DrawableIcon(cs.newDrawable());
+            }
+            return null;
+        };
         state.label = mTile.getLabel();
         if (mTile.getContentDescription() != null) {
             state.contentDescription = mTile.getContentDescription();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index e8c8b90..c249e37 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -87,14 +87,15 @@
     }
 
     protected void updateIcon(ImageView iv, State state) {
-        if (!Objects.equals(state.icon, iv.getTag(R.id.qs_icon_tag))
+        final QSTile.Icon icon = state.iconSupplier != null ? state.iconSupplier.get() : state.icon;
+        if (!Objects.equals(icon, iv.getTag(R.id.qs_icon_tag))
                 || !Objects.equals(state.slash, iv.getTag(R.id.qs_slash_tag))) {
             boolean shouldAnimate = iv.isShown() && mAnimationEnabled
                     && iv.getDrawable() != null;
-            Drawable d = state.icon != null
-                    ? shouldAnimate ? state.icon.getDrawable(mContext)
-                    : state.icon.getInvisibleDrawable(mContext) : null;
-            int padding = state.icon != null ? state.icon.getPadding() : 0;
+            Drawable d = icon != null
+                    ? shouldAnimate ? icon.getDrawable(mContext)
+                    : icon.getInvisibleDrawable(mContext) : null;
+            int padding = icon != null ? icon.getPadding() : 0;
             if (d != null) {
                 d.setAutoMirrored(false);
                 d.setLayoutDirection(getLayoutDirection());
@@ -107,7 +108,7 @@
                 iv.setImageDrawable(d);
             }
 
-            iv.setTag(R.id.qs_icon_tag, state.icon);
+            iv.setTag(R.id.qs_icon_tag, icon);
             iv.setTag(R.id.qs_slash_tag, state.slash);
             iv.setPadding(0, padding, 0, padding);
             if (d instanceof Animatable2) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 81b8622..bc3ccb4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -134,7 +134,9 @@
                 if (lastDevice != null) {
                     int batteryLevel = lastDevice.getBatteryLevel();
                     if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
-                        state.icon = new BluetoothBatteryDrawable(batteryLevel);
+                        state.icon = new BluetoothBatteryDrawable(batteryLevel,
+                                mContext.getResources().getFraction(
+                                        R.fraction.bt_battery_scale_fraction, 1, 1));
                     }
                 }
                 state.contentDescription = mContext.getString(
@@ -212,17 +214,21 @@
 
     private class BluetoothBatteryDrawable extends Icon {
         private int mLevel;
+        private float mIconScale;
 
         BluetoothBatteryDrawable(int level) {
+            this(level, 1 /* iconScale */);
+        }
+
+        BluetoothBatteryDrawable(int level, float iconScale) {
             mLevel = level;
+            mIconScale = iconScale;
         }
 
         @Override
         public Drawable getDrawable(Context context) {
             return createLayerDrawable(context,
-                    R.drawable.ic_qs_bluetooth_connected, mLevel,
-                    context.getResources().getFraction(
-                            R.fraction.bt_battery_scale_fraction, 1, 1));
+                    R.drawable.ic_qs_bluetooth_connected, mLevel, mIconScale);
         }
     }
 
@@ -304,8 +310,7 @@
                         item.icon = R.drawable.ic_qs_bluetooth_connected;
                         int batteryLevel = device.getBatteryLevel();
                         if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
-                            item.iconDrawable = createLayerDrawable(mContext, item.icon,
-                                    batteryLevel);
+                            item.iconDrawable = new BluetoothBatteryDrawable(batteryLevel);
                             item.line2 = mContext.getString(
                                     R.string.quick_settings_connected_battery_level,
                                     Utils.formatPercentage(batteryLevel));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
index cc7798e..58d8d8f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
@@ -31,5 +31,6 @@
     void sendRecentsDrawnEvent();
     void sendDockingTopTaskEvent(int dragMode, in Rect initialRect);
     void sendLaunchRecentsEvent();
+    void sendDockedFirstAnimationFrameEvent();
     void setWaitingForTransitionStartEvent(boolean waitingForTransitionStart);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 283ac0c..ce1438a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -29,14 +29,13 @@
 import android.content.ServiceConnection;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
-import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.EventLog;
@@ -53,6 +52,7 @@
 import com.android.systemui.SystemUI;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
+import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
 import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent;
 import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
@@ -62,7 +62,7 @@
 import com.android.systemui.recents.events.component.ShowUserToastEvent;
 import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.RecentsTaskLoader;
+import com.android.systemui.shared.recents.model.RecentsTaskLoader;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.CommandQueue;
 
@@ -81,23 +81,15 @@
         implements RecentsComponent, CommandQueue.Callbacks {
 
     private final static String TAG = "Recents";
-    private final static boolean DEBUG = false;
 
     public final static int EVENT_BUS_PRIORITY = 1;
     public final static int BIND_TO_SYSTEM_USER_RETRY_DELAY = 5000;
-    public final static int RECENTS_GROW_TARGET_INVALID = -1;
 
     public final static Set<String> RECENTS_ACTIVITIES = new HashSet<>();
     static {
         RECENTS_ACTIVITIES.add(RecentsImpl.RECENTS_ACTIVITY);
     }
 
-    // Purely for experimentation
-    private final static String RECENTS_OVERRIDE_SYSPROP_KEY = "persist.recents_override_pkg";
-    private final static String ACTION_SHOW_RECENTS = "com.android.systemui.recents.ACTION_SHOW";
-    private final static String ACTION_HIDE_RECENTS = "com.android.systemui.recents.ACTION_HIDE";
-    private final static String ACTION_TOGGLE_RECENTS = "com.android.systemui.recents.ACTION_TOGGLE";
-
     private static final String COUNTER_WINDOW_SUPPORTED = "window_enter_supported";
     private static final String COUNTER_WINDOW_UNSUPPORTED = "window_enter_unsupported";
     private static final String COUNTER_WINDOW_INCOMPATIBLE = "window_enter_incompatible";
@@ -107,11 +99,6 @@
     private static RecentsTaskLoader sTaskLoader;
     private static RecentsConfiguration sConfiguration;
 
-    // For experiments only, allows another package to handle recents if it is defined in the system
-    // properties.  This is limited to show/toggle/hide, and does not tie into the ActivityManager,
-    // and does not reside in the home stack.
-    private String mOverrideRecentsPackageName;
-
     private Handler mHandler;
     private RecentsImpl mImpl;
     private int mDraggingInRecentsCurrentUser;
@@ -204,21 +191,23 @@
 
     @Override
     public void start() {
-        sDebugFlags = new RecentsDebugFlags(mContext);
+        final Resources res = mContext.getResources();
+        final int defaultTaskBarBackgroundColor =
+                mContext.getColor(R.color.recents_task_bar_default_background_color);
+        final int defaultTaskViewBackgroundColor =
+                mContext.getColor(R.color.recents_task_view_default_background_color);
+        sDebugFlags = new RecentsDebugFlags();
         sSystemServicesProxy = SystemServicesProxy.getInstance(mContext);
         sConfiguration = new RecentsConfiguration(mContext);
-        sTaskLoader = new RecentsTaskLoader(mContext);
+        sTaskLoader = new RecentsTaskLoader(mContext,
+                // TODO: Once we start building the AAR, move these into the loader
+                res.getInteger(R.integer.config_recents_max_thumbnail_count),
+                res.getInteger(R.integer.config_recents_max_icon_count),
+                res.getInteger(R.integer.recents_svelte_level));
+        sTaskLoader.setDefaultColors(defaultTaskBarBackgroundColor, defaultTaskViewBackgroundColor);
         mHandler = new Handler();
         mImpl = new RecentsImpl(mContext);
 
-        // Check if there is a recents override package
-        if (Build.IS_USERDEBUG || Build.IS_ENG) {
-            String cnStr = SystemProperties.get(RECENTS_OVERRIDE_SYSPROP_KEY);
-            if (!cnStr.isEmpty()) {
-                mOverrideRecentsPackageName = cnStr;
-            }
-        }
-
         // Register with the event bus
         EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
         EventBus.getDefault().register(sSystemServicesProxy, EVENT_BUS_PRIORITY);
@@ -257,16 +246,8 @@
             return;
         }
 
-        if (proxyToOverridePackage(ACTION_SHOW_RECENTS)) {
-            return;
-        }
-        try {
-            ActivityManager.getService().closeSystemDialogs(SYSTEM_DIALOG_REASON_RECENT_APPS);
-        } catch (RemoteException e) {
-        }
-
+        sSystemServicesProxy.sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
         int recentsGrowTarget = getComponent(Divider.class).getView().growsRecents();
-
         int currentUser = sSystemServicesProxy.getCurrentUser();
         if (sSystemServicesProxy.isSystemUser(currentUser)) {
             mImpl.showRecents(triggeredFromAltTab, false /* draggingInRecents */,
@@ -301,10 +282,6 @@
             return;
         }
 
-        if (proxyToOverridePackage(ACTION_HIDE_RECENTS)) {
-            return;
-        }
-
         int currentUser = sSystemServicesProxy.getCurrentUser();
         if (sSystemServicesProxy.isSystemUser(currentUser)) {
             mImpl.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
@@ -336,12 +313,7 @@
             return;
         }
 
-        if (proxyToOverridePackage(ACTION_TOGGLE_RECENTS)) {
-            return;
-        }
-
         int growTarget = getComponent(Divider.class).getView().growsRecents();
-
         int currentUser = sSystemServicesProxy.getCurrentUser();
         if (sSystemServicesProxy.isSystemUser(currentUser)) {
             mImpl.toggleRecents(growTarget);
@@ -634,6 +606,23 @@
         }
     }
 
+    public final void onBusEvent(DockedFirstAnimationFrameEvent event) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        int processUser = ssp.getProcessUser();
+        if (!ssp.isSystemUser(processUser)) {
+            postToSystemUser(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        mUserToSystemCallbacks.sendDockedFirstAnimationFrameEvent();
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                }
+            });
+        }
+    }
+
     /**
      * Handle screen pinning request.
      */
@@ -820,21 +809,6 @@
                 (Settings.Secure.getInt(cr, Settings.Secure.USER_SETUP_COMPLETE, 0) != 0);
     }
 
-    /**
-     * Attempts to proxy the following action to the override recents package.
-     * @return whether the proxying was successful
-     */
-    private boolean proxyToOverridePackage(String action) {
-        if (mOverrideRecentsPackageName != null) {
-            Intent intent = new Intent(action);
-            intent.setPackage(mOverrideRecentsPackageName);
-            intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-            mContext.sendBroadcast(intent);
-            return true;
-        }
-        return false;
-    }
-
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("Recents");
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 86b7790..b75a142 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -17,7 +17,6 @@
 package com.android.systemui.recents;
 
 import android.app.Activity;
-import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.TaskStackBuilder;
 import android.app.WallpaperManager;
@@ -29,10 +28,10 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.provider.Settings.Secure;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.View;
@@ -42,6 +41,7 @@
 import android.view.WindowManager.LayoutParams;
 
 import com.android.internal.colorextraction.ColorExtractor;
+import com.android.internal.content.PackageMonitor;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.keyguard.LatencyTracker;
@@ -53,7 +53,6 @@
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
 import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
-import com.android.systemui.recents.events.activity.DebugFlagsChangedEvent;
 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
 import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
@@ -61,10 +60,10 @@
 import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.ExitRecentsWindowFirstAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
-import com.android.systemui.recents.events.activity.IterateRecentsEvent;
 import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent;
 import com.android.systemui.recents.events.activity.LaunchTaskSucceededEvent;
 import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
+import com.android.systemui.recents.events.activity.PackagesChangedEvent;
 import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
 import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
 import com.android.systemui.recents.events.component.ActivityUnpinnedEvent;
@@ -79,28 +78,24 @@
 import com.android.systemui.recents.events.ui.ShowIncompatibleAppOverlayEvent;
 import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
 import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
-import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
 import com.android.systemui.recents.events.ui.UserInteractionEvent;
 import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent.Direction;
-import com.android.systemui.recents.misc.DozeTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.RecentsPackageMonitor;
-import com.android.systemui.recents.model.RecentsTaskLoadPlan;
-import com.android.systemui.recents.model.RecentsTaskLoader;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
+import com.android.systemui.shared.recents.model.RecentsTaskLoader;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.TaskStack;
 import com.android.systemui.recents.views.RecentsView;
 import com.android.systemui.recents.views.SystemBarScrimViews;
 import com.android.systemui.statusbar.phone.StatusBar;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.List;
 
 /**
  * The main Recents activity that is started from RecentsComponent.
@@ -114,7 +109,23 @@
     public final static int EVENT_BUS_PRIORITY = Recents.EVENT_BUS_PRIORITY + 1;
     public final static int INCOMPATIBLE_APP_ALPHA_DURATION = 150;
 
-    private RecentsPackageMonitor mPackageMonitor;
+    private PackageMonitor mPackageMonitor = new PackageMonitor() {
+            @Override
+            public void onPackageRemoved(String packageName, int uid) {
+                RecentsActivity.this.onPackageChanged(packageName, getChangingUserId());
+            }
+
+            @Override
+            public boolean onPackageChanged(String packageName, int uid, String[] components) {
+                RecentsActivity.this.onPackageChanged(packageName, getChangingUserId());
+                return true;
+            }
+
+            @Override
+            public void onPackageModified(String packageName) {
+                RecentsActivity.this.onPackageChanged(packageName, getChangingUserId());
+            }
+        };
     private Handler mHandler = new Handler();
     private long mLastTabKeyEventTime;
     private boolean mFinishedOnStartup;
@@ -133,7 +144,6 @@
 
     // The trigger to automatically launch the current task
     private int mFocusTimerDuration;
-    private DozeTrigger mIterateTrigger;
     private final UserInteractionEvent mUserInteractionEvent = new UserInteractionEvent();
 
     // Theme and colors
@@ -188,41 +198,6 @@
             } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
                 // When switching users, dismiss Recents to Home similar to screen off
                 finish();
-            } else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
-                // If the time shifts but the currentTime >= lastStackActiveTime, then that boundary
-                // is still valid.  Otherwise, we need to reset the lastStackactiveTime to the
-                // currentTime and remove the old tasks in between which would not be previously
-                // visible, but currently would be in the new currentTime
-                int currentUser = SystemServicesProxy.getInstance(RecentsActivity.this)
-                        .getCurrentUser();
-                long oldLastStackActiveTime = Settings.Secure.getLongForUser(getContentResolver(),
-                        Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, -1, currentUser);
-                if (oldLastStackActiveTime != -1) {
-                    long currentTime = System.currentTimeMillis();
-                    if (currentTime < oldLastStackActiveTime) {
-                        // We are only removing tasks that are between the new current time
-                        // and the old last stack active time, they were not visible and in the
-                        // TaskStack so we don't need to remove any associated TaskViews but we do
-                        // need to load the task id's from the system
-                        RecentsTaskLoader loader = Recents.getTaskLoader();
-                        RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(ctx);
-                        loader.preloadRawTasks(loadPlan, false /* includeFrontMostExcludedTask */);
-                        List<ActivityManager.RecentTaskInfo> tasks = loadPlan.getRawTasks();
-                        for (int i = tasks.size() - 1; i >= 0; i--) {
-                            ActivityManager.RecentTaskInfo task = tasks.get(i);
-                            if (currentTime <= task.lastActiveTime && task.lastActiveTime <
-                                    oldLastStackActiveTime) {
-                                Recents.getSystemServices().removeTask(task.persistentId);
-                            }
-                        }
-                        Recents.getSystemServices().updateOverviewLastStackActiveTimeAsync(
-                                currentTime, currentUser);
-
-                        // Clear the last PiP task time, it's an edge case and we'd rather it
-                        // not relaunch the PiP task if the user double taps
-                        RecentsImpl.clearLastPipTime();
-                    }
-                }
             }
         }
     };
@@ -340,8 +315,8 @@
         EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
 
         // Initialize the package monitor
-        mPackageMonitor = new RecentsPackageMonitor();
-        mPackageMonitor.register(this);
+        mPackageMonitor.register(this, Looper.getMainLooper(), UserHandle.ALL,
+                true /* externalStorage */);
 
         // Select theme based on wallpaper colors
         mColorExtractor = Dependency.get(SysuiColorExtractor.class);
@@ -363,13 +338,6 @@
         }
 
         mLastConfig = new Configuration(Utilities.getAppConfiguration(this));
-        mFocusTimerDuration = getResources().getInteger(R.integer.recents_auto_advance_duration);
-        mIterateTrigger = new DozeTrigger(mFocusTimerDuration, new Runnable() {
-            @Override
-            public void run() {
-                dismissRecentsToFocusedTask(MetricsEvent.OVERVIEW_SELECT_TIMEOUT);
-            }
-        });
 
         // Set the window background
         mRecentsView.updateBackgroundScrim(getWindow(), isInMultiWindowMode());
@@ -383,7 +351,6 @@
         // Register the broadcast receiver to handle messages when the screen is turned off
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_SCREEN_OFF);
-        filter.addAction(Intent.ACTION_TIME_CHANGED);
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         registerReceiver(mSystemBroadcastReceiver, filter);
 
@@ -460,22 +427,21 @@
         RecentsTaskLoader loader = Recents.getTaskLoader();
         RecentsTaskLoadPlan loadPlan = RecentsImpl.consumeInstanceLoadPlan();
         if (loadPlan == null) {
-            loadPlan = loader.createLoadPlan(this);
+            loadPlan = new RecentsTaskLoadPlan(this);
         }
 
         // Start loading tasks according to the load plan
         RecentsConfiguration config = Recents.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
         if (!loadPlan.hasTasks()) {
-            loader.preloadTasks(loadPlan, launchState.launchedToTaskId,
-                    !launchState.launchedFromHome && !launchState.launchedViaDockGesture);
+            loader.preloadTasks(loadPlan, launchState.launchedToTaskId);
         }
 
         RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
         loadOpts.runningTaskId = launchState.launchedToTaskId;
         loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
         loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
-        loader.loadTasks(this, loadPlan, loadOpts);
+        loader.loadTasks(loadPlan, loadOpts);
         TaskStack stack = loadPlan.getTaskStack();
         mRecentsView.onReload(stack, mIsVisible);
 
@@ -540,7 +506,6 @@
         super.onPause();
 
         mIgnoreAltTabRelease = false;
-        mIterateTrigger.stopDozing();
     }
 
     @Override
@@ -643,8 +608,7 @@
                     if (backward) {
                         EventBus.getDefault().send(new FocusPreviousTaskViewEvent());
                     } else {
-                        EventBus.getDefault().send(
-                                new FocusNextTaskViewEvent(0 /* timerIndicatorDuration */));
+                        EventBus.getDefault().send(new FocusNextTaskViewEvent());
                     }
                     mLastTabKeyEventTime = SystemClock.elapsedRealtime();
 
@@ -702,38 +666,10 @@
         }
     }
 
-    public final void onBusEvent(IterateRecentsEvent event) {
-        final RecentsDebugFlags debugFlags = Recents.getDebugFlags();
-
-        // Start dozing after the recents button is clicked
-        int timerIndicatorDuration = 0;
-        if (debugFlags.isFastToggleRecentsEnabled()) {
-            timerIndicatorDuration = getResources().getInteger(
-                    R.integer.recents_subsequent_auto_advance_duration);
-
-            mIterateTrigger.setDozeDuration(timerIndicatorDuration);
-            if (!mIterateTrigger.isDozing()) {
-                mIterateTrigger.startDozing();
-            } else {
-                mIterateTrigger.poke();
-            }
-        }
-
-        // Focus the next task
-        EventBus.getDefault().send(new FocusNextTaskViewEvent(timerIndicatorDuration));
-
-        MetricsLogger.action(this, MetricsEvent.ACTION_OVERVIEW_PAGE);
-    }
-
     public final void onBusEvent(RecentsActivityStartingEvent event) {
         mRecentsStartRequested = true;
     }
 
-    public final void onBusEvent(UserInteractionEvent event) {
-        // Stop the fast-toggle dozer
-        mIterateTrigger.stopDozing();
-    }
-
     public final void onBusEvent(HideRecentsEvent event) {
         if (event.triggeredFromAltTab) {
             // If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app
@@ -751,15 +687,11 @@
     }
 
     public final void onBusEvent(EnterRecentsWindowLastAnimationFrameEvent event) {
-        EventBus.getDefault().send(new UpdateFreeformTaskViewVisibilityEvent(true));
         mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
         mRecentsView.invalidate();
     }
 
     public final void onBusEvent(ExitRecentsWindowFirstAnimationFrameEvent event) {
-        if (mRecentsView.isLastTaskLaunchedFreeform()) {
-            EventBus.getDefault().send(new UpdateFreeformTaskViewVisibilityEvent(false));
-        }
         mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
         mRecentsView.invalidate();
     }
@@ -859,11 +791,6 @@
         MetricsLogger.count(this, "overview_screen_pinned", 1);
     }
 
-    public final void onBusEvent(DebugFlagsChangedEvent event) {
-        // Just finish recents so that we can reload the flags anew on the next instantiation
-        finish();
-    }
-
     public final void onBusEvent(StackViewScrolledEvent event) {
         // Once the user has scrolled while holding alt-tab, then we should ignore the release of
         // the key
@@ -888,14 +815,13 @@
         RecentsConfiguration config = Recents.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
         RecentsTaskLoader loader = Recents.getTaskLoader();
-        RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
-        loader.preloadTasks(loadPlan, -1 /* runningTaskId */,
-                false /* includeFrontMostExcludedTask */);
+        RecentsTaskLoadPlan loadPlan = new RecentsTaskLoadPlan(this);
+        loader.preloadTasks(loadPlan, -1 /* runningTaskId */);
 
         RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
         loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
         loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
-        loader.loadTasks(this, loadPlan, loadOpts);
+        loader.loadTasks(loadPlan, loadOpts);
 
         TaskStack stack = loadPlan.getTaskStack();
         int numStackTasks = stack.getStackTaskCount();
@@ -924,6 +850,11 @@
         return true;
     }
 
+    public void onPackageChanged(String packageName, int userId) {
+        Recents.getTaskLoader().onPackageChanged(packageName);
+        EventBus.getDefault().send(new PackagesChangedEvent(packageName, userId));
+    }
+
     @Override
     public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
         super.dump(prefix, fd, writer, args);
@@ -931,13 +862,9 @@
         Recents.getTaskLoader().dump(prefix, writer);
 
         String id = Integer.toHexString(System.identityHashCode(this));
-        long lastStackActiveTime = Settings.Secure.getLongForUser(getContentResolver(),
-                Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, -1,
-                SystemServicesProxy.getInstance(this).getCurrentUser());
 
         writer.print(prefix); writer.print(TAG);
         writer.print(" visible="); writer.print(mIsVisible ? "Y" : "N");
-        writer.print(" lastStackTaskActiveTime="); writer.print(lastStackActiveTime);
         writer.print(" currentTime="); writer.print(System.currentTimeMillis());
         writer.print(" [0x"); writer.print(id); writer.print("]");
         writer.println();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
index 5b8ed94..d2326ce 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -33,7 +33,6 @@
     public boolean launchedFromPipApp;
     // Set if the next activity that quick-switch will launch is the PiP activity
     public boolean launchedWithNextPipApp;
-    public boolean launchedFromBlacklistedApp;
     public boolean launchedFromHome;
     public boolean launchedViaDragGesture;
     public boolean launchedViaDockGesture;
@@ -44,7 +43,6 @@
     public void reset() {
         launchedFromHome = false;
         launchedFromApp = false;
-        launchedFromBlacklistedApp = false;
         launchedFromPipApp = false;
         launchedWithNextPipApp = false;
         launchedToTaskId = -1;
@@ -60,18 +58,6 @@
         RecentsDebugFlags debugFlags = Recents.getDebugFlags();
         RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
         if (launchedFromApp) {
-            if (!launchState.launchedWithAltTab && debugFlags.isFastToggleRecentsEnabled()) {
-                // If fast toggling, focus the front most task so that the next tap will launch the
-                // task
-                return numTasks - 1;
-            }
-
-            if (launchState.launchedFromBlacklistedApp) {
-                // If we are launching from a blacklisted app, focus the front most task so that the
-                // next tap will launch the task
-                return numTasks - 1;
-            }
-
             if (useGridLayout) {
                 // If coming from another app to the grid layout, focus the front most task
                 return numTasks - 1;
@@ -80,12 +66,6 @@
             // If coming from another app, focus the next task
             return Math.max(0, numTasks - 2);
         } else {
-            if (!launchState.launchedWithAltTab && debugFlags.isFastToggleRecentsEnabled()) {
-                // If fast toggling, defer focusing until the next tap (which will automatically
-                // focus the front most task)
-                return -1;
-            }
-
             // If coming from home, focus the front most task
             return numTasks - 1;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 5dc6f31..68df1d5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -20,31 +20,31 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.graphics.Rect;
 
 import android.os.SystemProperties;
 
 import com.android.systemui.R;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.views.DockState;
+import com.android.systemui.shared.recents.model.TaskStack;
 
 /**
  * Represents the dock regions for each orientation.
  */
 class DockRegion {
-    public static TaskStack.DockState[] PHONE_LANDSCAPE = {
+    public static DockState[] PHONE_LANDSCAPE = {
             // We only allow docking to the left in landscape for now on small devices
-            TaskStack.DockState.LEFT
+            DockState.LEFT
     };
-    public static TaskStack.DockState[] PHONE_PORTRAIT = {
+    public static DockState[] PHONE_PORTRAIT = {
             // We only allow docking to the top for now on small devices
-            TaskStack.DockState.TOP
+            DockState.TOP
     };
-    public static TaskStack.DockState[] TABLET_LANDSCAPE = {
-            TaskStack.DockState.LEFT,
-            TaskStack.DockState.RIGHT
+    public static DockState[] TABLET_LANDSCAPE = {
+            DockState.LEFT,
+            DockState.RIGHT
     };
-    public static TaskStack.DockState[] TABLET_PORTRAIT = PHONE_PORTRAIT;
+    public static DockState[] TABLET_PORTRAIT = PHONE_PORTRAIT;
 }
 
 /**
@@ -56,18 +56,6 @@
     private static final int LARGE_SCREEN_MIN_DP = 600;
     private static final int XLARGE_SCREEN_MIN_DP = 720;
 
-    /** Levels of svelte in increasing severity/austerity. */
-    // No svelting.
-    public static final int SVELTE_NONE = 0;
-    // Limit thumbnail cache to number of visible thumbnails when Recents was loaded, disable
-    // caching thumbnails as you scroll.
-    public static final int SVELTE_LIMIT_CACHE = 1;
-    // Disable the thumbnail cache, load thumbnails asynchronously when the activity loads and
-    // evict all thumbnails when hidden.
-    public static final int SVELTE_DISABLE_CACHE = 2;
-    // Disable all thumbnail loading.
-    public static final int SVELTE_DISABLE_LOADING = 3;
-
     // Launch states
     public RecentsActivityLaunchState mLaunchState = new RecentsActivityLaunchState();
 
@@ -125,7 +113,7 @@
      * Returns the preferred dock states for the current orientation.
      * @return a list of dock states for device and its orientation
      */
-    public TaskStack.DockState[] getDockStatesForCurrentOrientation() {
+    public DockState[] getDockStatesForCurrentOrientation() {
         boolean isLandscape = mAppContext.getResources().getConfiguration().orientation ==
                 Configuration.ORIENTATION_LANDSCAPE;
         RecentsConfiguration config = Recents.getConfiguration();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
index 0262a09..1918593 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
@@ -16,75 +16,14 @@
 
 package com.android.systemui.recents;
 
-import android.content.Context;
-
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.DebugFlagsChangedEvent;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.tuner.TunerService;
-
-/**
- * Tunable debug flags
- */
-public class RecentsDebugFlags implements TunerService.Tunable {
+public class RecentsDebugFlags {
 
     public static class Static {
         // Enables debug drawing for the transition thumbnail
         public static final boolean EnableTransitionThumbnailDebugMode = false;
-        // This disables the bitmap and icon caches
-        public static final boolean DisableBackgroundCache = false;
-        // Enables the task affiliations
-        public static final boolean EnableAffiliatedTaskGroups = false;
-        // Enables the button above the stack
-        public static final boolean EnableStackActionButton = true;
-        // Overrides the Tuner flags and enables the timeout
-        private static final boolean EnableFastToggleTimeout = false;
-        // Overrides the Tuner flags and enables the paging via the Recents button
-        private static final boolean EnablePaging = false;
+
         // Disables enter and exit transitions for other tasks for low ram devices
         public static final boolean DisableRecentsLowRamEnterExitAnimation = false;
 
-        // Enables us to create mock recents tasks
-        public static final boolean EnableMockTasks = false;
-        // Defines the number of mock recents packages to create
-        public static final int MockTasksPackageCount = 3;
-        // Defines the number of mock recents tasks to create
-        public static final int MockTaskCount = 100;
-        // Enables the simulated task affiliations
-        public static final boolean EnableMockTaskGroups = false;
-        // Defines the number of mock task affiliations per group
-        public static final int MockTaskGroupsTaskCount = 12;
-    }
-
-    /**
-     * We read the prefs once when we start the activity, then update them as the tuner changes
-     * the flags.
-     */
-    public RecentsDebugFlags(Context context) {
-        // Register all our flags, this will also call onTuningChanged() for each key, which will
-        // initialize the current state of each flag
-    }
-
-    /**
-     * @return whether we are enabling fast toggling.
-     */
-    public boolean isFastToggleRecentsEnabled() {
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        if (ssp.hasFreeformWorkspaceSupport() || ssp.isTouchExplorationEnabled()) {
-            return false;
-        }
-        return Static.EnableFastToggleTimeout;
-    }
-
-    /**
-     * @return whether we are enabling paging.
-     */
-    public boolean isPagingEnabled() {
-        return Static.EnablePaging;
-    }
-
-    @Override
-    public void onTuningChanged(String key, String newValue) {
-        EventBus.getDefault().send(new DebugFlagsChangedEvent());
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 3e2a5f3..868ed64 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -18,7 +18,6 @@
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.view.View.MeasureSpec;
 
 import android.app.ActivityManager;
@@ -56,7 +55,6 @@
 import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
-import com.android.systemui.recents.events.activity.IterateRecentsEvent;
 import com.android.systemui.recents.events.activity.LaunchMostRecentTaskRequestEvent;
 import com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent;
 import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
@@ -72,20 +70,18 @@
 import com.android.systemui.recents.misc.DozeTrigger;
 import com.android.systemui.recents.misc.ForegroundThread;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
-import com.android.systemui.recents.model.RecentsTaskLoadPlan;
-import com.android.systemui.recents.model.RecentsTaskLoader;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.Task.TaskKey;
-import com.android.systemui.recents.model.TaskGrouping;
-import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.recents.model.ThumbnailData;
+import com.android.systemui.recents.misc.TaskStackChangeListener;
+import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
+import com.android.systemui.shared.recents.model.RecentsTaskLoader;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task.TaskKey;
+import com.android.systemui.shared.recents.model.TaskStack;
+import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.recents.views.RecentsTransitionHelper;
 import com.android.systemui.recents.views.RecentsTransitionHelper.AppTransitionAnimationSpecsFuture;
 import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
 import com.android.systemui.recents.views.TaskStackLayoutAlgorithm.VisibilityReport;
 import com.android.systemui.recents.views.TaskStackView;
-import com.android.systemui.recents.views.TaskStackViewScroller;
 import com.android.systemui.recents.views.TaskViewHeader;
 import com.android.systemui.recents.views.TaskViewTransform;
 import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
@@ -117,10 +113,10 @@
     public final static String RECENTS_ACTIVITY = "com.android.systemui.recents.RecentsActivity";
 
     /**
-     * An implementation of TaskStackListener, that allows us to listen for changes to the system
+     * An implementation of TaskStackChangeListener, that allows us to listen for changes to the system
      * task stacks and update recents accordingly.
      */
-    class TaskStackListenerImpl extends TaskStackListener {
+    class TaskStackListenerImpl extends TaskStackChangeListener {
 
         @Override
         public void onTaskStackChangedBackground() {
@@ -131,7 +127,7 @@
 
             // Preloads the next task
             RecentsConfiguration config = Recents.getConfiguration();
-            if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
+            if (config.svelteLevel == RecentsTaskLoader.SVELTE_NONE) {
                 Rect windowRect = getWindowRect(null /* windowRectOverride */);
                 if (windowRect.isEmpty()) {
                     return;
@@ -141,8 +137,8 @@
                 SystemServicesProxy ssp = Recents.getSystemServices();
                 ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask();
                 RecentsTaskLoader loader = Recents.getTaskLoader();
-                RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
-                loader.preloadTasks(plan, -1, false /* includeFrontMostExcludedTask */);
+                RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext);
+                loader.preloadTasks(plan, -1);
                 TaskStack stack = plan.getTaskStack();
                 RecentsActivityLaunchState launchState = new RecentsActivityLaunchState();
                 RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
@@ -168,7 +164,7 @@
                     launchOpts.onlyLoadPausedActivities = true;
                     launchOpts.loadThumbnails = true;
                 }
-                loader.loadTasks(mContext, plan, launchOpts);
+                loader.loadTasks(plan, launchOpts);
             }
         }
 
@@ -207,7 +203,7 @@
             }
 
             EventBus.getDefault().send(new TaskSnapshotChangedEvent(taskId,
-                    ThumbnailData.createFromTaskSnapshot(snapshot)));
+                    new ThumbnailData(snapshot)));
         }
     }
 
@@ -282,13 +278,13 @@
         // When we start, preload the data associated with the previous recent tasks.
         // We can use a new plan since the caches will be the same.
         RecentsTaskLoader loader = Recents.getTaskLoader();
-        RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
-        loader.preloadTasks(plan, -1, false /* includeFrontMostExcludedTask */);
+        RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext);
+        loader.preloadTasks(plan, -1);
         RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
         launchOpts.numVisibleTasks = loader.getIconCacheSize();
         launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize();
         launchOpts.onlyLoadForCache = true;
-        loader.loadTasks(mContext, plan, launchOpts);
+        loader.loadTasks(plan, launchOpts);
     }
 
     public void onConfigurationChanged() {
@@ -409,22 +405,17 @@
                 RecentsConfiguration config = Recents.getConfiguration();
                 RecentsActivityLaunchState launchState = config.getLaunchState();
                 if (!launchState.launchedWithAltTab) {
-                    // Has the user tapped quickly?
-                    boolean isQuickTap = elapsedTime < ViewConfiguration.getDoubleTapTimeout();
                     if (Recents.getConfiguration().isGridEnabled) {
+                        // Has the user tapped quickly?
+                        boolean isQuickTap = elapsedTime < ViewConfiguration.getDoubleTapTimeout();
                         if (isQuickTap) {
                             EventBus.getDefault().post(new LaunchNextTaskRequestEvent());
                         } else {
                             EventBus.getDefault().post(new LaunchMostRecentTaskRequestEvent());
                         }
                     } else {
-                        if (!debugFlags.isPagingEnabled() || isQuickTap) {
-                            // Launch the next focused task
-                            EventBus.getDefault().post(new LaunchNextTaskRequestEvent());
-                        } else {
-                            // Notify recents to move onto the next task
-                            EventBus.getDefault().post(new IterateRecentsEvent());
-                        }
+                        // Launch the next focused task
+                        EventBus.getDefault().post(new LaunchNextTaskRequestEvent());
                     }
                 } else {
                     // If the user has toggled it too quickly, then just eat up the event here (it's
@@ -473,16 +464,15 @@
         // RecentsActivity) only if there is a task to animate to.  Post this to ensure that we
         // don't block the touch feedback on the nav bar button which triggers this.
         mHandler.post(() -> {
-            MutableBoolean isHomeStackVisible = new MutableBoolean(true);
-            if (!ssp.isRecentsActivityVisible(isHomeStackVisible)) {
+            if (!ssp.isRecentsActivityVisible(null)) {
                 ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
                 if (runningTask == null) {
                     return;
                 }
 
                 RecentsTaskLoader loader = Recents.getTaskLoader();
-                sInstanceLoadPlan = loader.createLoadPlan(mContext);
-                loader.preloadTasks(sInstanceLoadPlan, runningTask.id, !isHomeStackVisible.value);
+                sInstanceLoadPlan = new RecentsTaskLoadPlan(mContext);
+                loader.preloadTasks(sInstanceLoadPlan, runningTask.id);
                 TaskStack stack = sInstanceLoadPlan.getTaskStack();
                 if (stack.getTaskCount() > 0) {
                     // Only preload the icon (but not the thumbnail since it may not have been taken
@@ -521,8 +511,8 @@
     public void showNextTask() {
         SystemServicesProxy ssp = Recents.getSystemServices();
         RecentsTaskLoader loader = Recents.getTaskLoader();
-        RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
-        loader.preloadTasks(plan, -1, false /* includeFrontMostExcludedTask */);
+        RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext);
+        loader.preloadTasks(plan, -1);
         TaskStack focusedStack = plan.getTaskStack();
 
         // Return early if there are no tasks in the focused stack
@@ -576,8 +566,8 @@
     public void showRelativeAffiliatedTask(boolean showNextTask) {
         SystemServicesProxy ssp = Recents.getSystemServices();
         RecentsTaskLoader loader = Recents.getTaskLoader();
-        RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
-        loader.preloadTasks(plan, -1, false /* includeFrontMostExcludedTask */);
+        RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext);
+        loader.preloadTasks(plan, -1);
         TaskStack focusedStack = plan.getTaskStack();
 
         // Return early if there are no tasks in the focused stack
@@ -595,43 +585,38 @@
         Task toTask = null;
         ActivityOptions launchOpts = null;
         int taskCount = tasks.size();
-        int numAffiliatedTasks = 0;
         for (int i = 0; i < taskCount; i++) {
             Task task = tasks.get(i);
             if (task.key.id == runningTask.id) {
-                TaskGrouping group = task.group;
-                Task.TaskKey toTaskKey;
                 if (showNextTask) {
-                    toTaskKey = group.getNextTaskInGroup(task);
-                    launchOpts = ActivityOptions.makeCustomAnimation(mContext,
-                            R.anim.recents_launch_next_affiliated_task_target,
-                            R.anim.recents_launch_next_affiliated_task_source);
+                    if ((i + 1) < taskCount) {
+                        toTask = tasks.get(i + 1);
+                        launchOpts = ActivityOptions.makeCustomAnimation(mContext,
+                                R.anim.recents_launch_next_affiliated_task_target,
+                                R.anim.recents_launch_next_affiliated_task_source);
+                    }
                 } else {
-                    toTaskKey = group.getPrevTaskInGroup(task);
-                    launchOpts = ActivityOptions.makeCustomAnimation(mContext,
-                            R.anim.recents_launch_prev_affiliated_task_target,
-                            R.anim.recents_launch_prev_affiliated_task_source);
+                    if ((i - 1) >= 0) {
+                        toTask = tasks.get(i - 1);
+                        launchOpts = ActivityOptions.makeCustomAnimation(mContext,
+                                R.anim.recents_launch_prev_affiliated_task_target,
+                                R.anim.recents_launch_prev_affiliated_task_source);
+                    }
                 }
-                if (toTaskKey != null) {
-                    toTask = focusedStack.findTaskWithId(toTaskKey.id);
-                }
-                numAffiliatedTasks = group.getTaskCount();
                 break;
             }
         }
 
         // Return early if there is no next task
         if (toTask == null) {
-            if (numAffiliatedTasks > 1) {
-                if (showNextTask) {
-                    ssp.startInPlaceAnimationOnFrontMostApplication(
-                            ActivityOptions.makeCustomInPlaceAnimation(mContext,
-                                    R.anim.recents_launch_next_affiliated_task_bounce));
-                } else {
-                    ssp.startInPlaceAnimationOnFrontMostApplication(
-                            ActivityOptions.makeCustomInPlaceAnimation(mContext,
-                                    R.anim.recents_launch_prev_affiliated_task_bounce));
-                }
+            if (showNextTask) {
+                ssp.startInPlaceAnimationOnFrontMostApplication(
+                        ActivityOptions.makeCustomInPlaceAnimation(mContext,
+                                R.anim.recents_launch_next_affiliated_task_bounce));
+            } else {
+                ssp.startInPlaceAnimationOnFrontMostApplication(
+                        ActivityOptions.makeCustomInPlaceAnimation(mContext,
+                                R.anim.recents_launch_prev_affiliated_task_bounce));
             }
             return;
         }
@@ -753,8 +738,7 @@
             stackLayout.getTaskStackBounds(displayRect, windowRect, systemInsets.top,
                     systemInsets.left, systemInsets.right, mTmpBounds);
             stackLayout.reset();
-            stackLayout.initialize(displayRect, windowRect, mTmpBounds,
-                    TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack));
+            stackLayout.initialize(displayRect, windowRect, mTmpBounds);
         }
     }
 
@@ -843,7 +827,7 @@
         launchOpts.runningTaskId = runningTaskId;
         launchOpts.loadThumbnails = false;
         launchOpts.onlyLoadForCache = true;
-        Recents.getTaskLoader().loadTasks(mContext, sInstanceLoadPlan, launchOpts);
+        Recents.getTaskLoader().loadTasks(sInstanceLoadPlan, launchOpts);
     }
 
     /**
@@ -873,61 +857,29 @@
             getThumbnailTransitionActivityOptions(ActivityManager.RunningTaskInfo runningTask,
                     Rect windowOverrideRect) {
         final boolean isLowRamDevice = Recents.getConfiguration().isLowRamDevice;
-        if (runningTask != null
-                && runningTask.configuration.windowConfiguration.getWindowingMode()
-                == WINDOWING_MODE_FREEFORM) {
-            ArrayList<AppTransitionAnimationSpec> specs = new ArrayList<>();
-            ArrayList<Task> tasks = mDummyStackView.getStack().getStackTasks();
-            TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm();
-            TaskStackViewScroller stackScroller = mDummyStackView.getScroller();
 
-            mDummyStackView.updateLayoutAlgorithm(true /* boundScroll */);
-            mDummyStackView.updateToInitialState();
+        // Update the destination rect
+        Task toTask = new Task();
+        TaskViewTransform toTransform = getThumbnailTransitionTransform(mDummyStackView, toTask,
+                windowOverrideRect);
 
-            for (int i = tasks.size() - 1; i >= 0; i--) {
-                Task task = tasks.get(i);
-                if (task.isFreeformTask()) {
-                    mTmpTransform = stackLayout.getStackTransformScreenCoordinates(task,
-                            stackScroller.getStackScroll(), mTmpTransform, null,
-                            windowOverrideRect);
-                    GraphicBuffer thumbnail = drawThumbnailTransitionBitmap(task, mTmpTransform);
-                    Rect toTaskRect = new Rect();
-                    mTmpTransform.rect.round(toTaskRect);
-                    specs.add(new AppTransitionAnimationSpec(task.key.id, thumbnail, toTaskRect));
-                }
-            }
-            AppTransitionAnimationSpec[] specsArray = new AppTransitionAnimationSpec[specs.size()];
-            specs.toArray(specsArray);
+        RectF toTaskRect = toTransform.rect;
+        AppTransitionAnimationSpecsFuture future =
+                new RecentsTransitionHelper(mContext).getAppTransitionFuture(
+                        () -> {
+                    Rect rect = new Rect();
+                    toTaskRect.round(rect);
+                    GraphicBuffer thumbnail = drawThumbnailTransitionBitmap(toTask,
+                            toTransform);
+                    return Lists.newArrayList(new AppTransitionAnimationSpec(
+                            toTask.key.id, thumbnail, rect));
+                });
 
-            // For low end ram devices, wait for transition flag is reset when Recents entrance
-            // animation is complete instead of when the transition animation starts
-            return new Pair<>(ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
-                    specsArray, mHandler, isLowRamDevice ? null : mResetToggleFlagListener, this),
-                    null);
-        } else {
-            // Update the destination rect
-            Task toTask = new Task();
-            TaskViewTransform toTransform = getThumbnailTransitionTransform(mDummyStackView, toTask,
-                    windowOverrideRect);
-
-            RectF toTaskRect = toTransform.rect;
-            AppTransitionAnimationSpecsFuture future =
-                    new RecentsTransitionHelper(mContext).getAppTransitionFuture(
-                            () -> {
-                        Rect rect = new Rect();
-                        toTaskRect.round(rect);
-                        GraphicBuffer thumbnail = drawThumbnailTransitionBitmap(toTask,
-                                toTransform);
-                        return Lists.newArrayList(new AppTransitionAnimationSpec(
-                                toTask.key.id, thumbnail, rect));
-                    });
-
-            // For low end ram devices, wait for transition flag is reset when Recents entrance
-            // animation is complete instead of when the transition animation starts
-            return new Pair<>(ActivityOptions.makeMultiThumbFutureAspectScaleAnimation(mContext,
-                    mHandler, future.getFuture(), isLowRamDevice ? null : mResetToggleFlagListener,
-                    false /* scaleUp */), future);
-        }
+        // For low end ram devices, wait for transition flag is reset when Recents entrance
+        // animation is complete instead of when the transition animation starts
+        return new Pair<>(ActivityOptions.makeMultiThumbFutureAspectScaleAnimation(mContext,
+                mHandler, future.getFuture(), isLowRamDevice ? null : mResetToggleFlagListener,
+                false /* scaleUp */), future);
     }
 
     /**
@@ -942,7 +894,7 @@
             runningTaskOut.copyFrom(launchTask);
         } else {
             // If no task is specified or we can not find the task just use the front most one
-            launchTask = stack.getStackFrontMostTask(true /* includeFreeform */);
+            launchTask = stack.getStackFrontMostTask();
             runningTaskOut.copyFrom(launchTask);
         }
 
@@ -995,12 +947,8 @@
             boolean isHomeStackVisible, boolean animate, int growTarget) {
         RecentsTaskLoader loader = Recents.getTaskLoader();
         RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        boolean isBlacklisted = (runningTask != null)
-                ? ssp.isBlackListedActivity(runningTask.baseActivity.getClassName())
-                : false;
 
-        int runningTaskId = !mLaunchedWhileDocking && !isBlacklisted && (runningTask != null)
+        int runningTaskId = !mLaunchedWhileDocking && (runningTask != null)
                 ? runningTask.id
                 : -1;
 
@@ -1009,10 +957,10 @@
         // the stacks might have changed.
         if (mLaunchedWhileDocking || mTriggeredFromAltTab || sInstanceLoadPlan == null) {
             // Create a new load plan if preloadRecents() was never triggered
-            sInstanceLoadPlan = loader.createLoadPlan(mContext);
+            sInstanceLoadPlan = new RecentsTaskLoadPlan(mContext);
         }
         if (mLaunchedWhileDocking || mTriggeredFromAltTab || !sInstanceLoadPlan.hasTasks()) {
-            loader.preloadTasks(sInstanceLoadPlan, runningTaskId, !isHomeStackVisible);
+            loader.preloadTasks(sInstanceLoadPlan, runningTaskId);
         }
 
         TaskStack stack = sInstanceLoadPlan.getTaskStack();
@@ -1023,7 +971,6 @@
         // Update the launch state that we need in updateHeaderBarLayout()
         launchState.launchedFromHome = !useThumbnailTransition && !mLaunchedWhileDocking;
         launchState.launchedFromApp = useThumbnailTransition || mLaunchedWhileDocking;
-        launchState.launchedFromBlacklistedApp = launchState.launchedFromApp && isBlacklisted;
         launchState.launchedFromPipApp = false;
         launchState.launchedWithNextPipApp =
                 stack.isNextLaunchTargetPip(RecentsImpl.getLastPipTime());
@@ -1059,9 +1006,7 @@
         }
 
         Pair<ActivityOptions, AppTransitionAnimationSpecsFuture> pair;
-        if (isBlacklisted) {
-            pair = new Pair<>(getUnknownTransitionActivityOptions(), null);
-        } else if (useThumbnailTransition) {
+        if (useThumbnailTransition) {
             // Try starting with a thumbnail transition
             pair = getThumbnailTransitionActivityOptions(runningTask, windowOverrideRect);
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
index 1285626..ff1f7dc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
@@ -27,6 +27,7 @@
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
 import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
 import com.android.systemui.recents.events.component.SetWaitingForTransitionStartEvent;
@@ -108,6 +109,11 @@
     }
 
     @Override
+    public void sendDockedFirstAnimationFrameEvent() throws RemoteException {
+        EventBus.getDefault().post(new DockedFirstAnimationFrameEvent());
+    }
+
+    @Override
     public void setWaitingForTransitionStartEvent(boolean waitingForTransitionStart) {
         EventBus.getDefault().post(new SetWaitingForTransitionStartEvent(
                 waitingForTransitionStart));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/CancelEnterRecentsWindowAnimationEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/CancelEnterRecentsWindowAnimationEvent.java
index 7604de1..fec34e3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/CancelEnterRecentsWindowAnimationEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/CancelEnterRecentsWindowAnimationEvent.java
@@ -17,7 +17,7 @@
 package com.android.systemui.recents.events.activity;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task;
 
 /**
  * This is sent when we want to cancel the enter-recents window animation for the launch task.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DebugFlagsChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DebugFlagsChangedEvent.java
deleted file mode 100644
index fe3bf26..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DebugFlagsChangedEvent.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 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.systemui.recents.events.activity;
-
-import com.android.systemui.recents.events.EventBus;
-
-/**
- * This is sent when the SystemUI tuner changes a flag.
- */
-public class DebugFlagsChangedEvent extends EventBus.Event {
-    // Simple event
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/IterateRecentsEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/IterateRecentsEvent.java
deleted file mode 100644
index f7b2706..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/IterateRecentsEvent.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 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.systemui.recents.events.activity;
-
-import com.android.systemui.recents.events.EventBus;
-
-/**
- * This is sent when the user taps on the Overview button to iterate to the next item in the
- * Recents list.
- */
-public class IterateRecentsEvent extends EventBus.Event {
-    // Simple event
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
index 862a1ee..2409f39 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
@@ -22,7 +22,7 @@
 import android.graphics.Rect;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.recents.views.TaskView;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
index 64eeafa..e4972b1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
@@ -17,7 +17,7 @@
 package com.android.systemui.recents.events.activity;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.model.TaskStack;
 
 /**
  * This is sent by the activity whenever the multi-window state has changed.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/PackagesChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/PackagesChangedEvent.java
index 3b68574..47670e0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/PackagesChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/PackagesChangedEvent.java
@@ -17,22 +17,20 @@
 package com.android.systemui.recents.events.activity;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.RecentsPackageMonitor;
 import com.android.systemui.recents.views.TaskStackView;
+import com.android.systemui.recents.RecentsActivity;
 
 /**
- * This event is sent by {@link RecentsPackageMonitor} when a package on the the system changes.
+ * This event is sent by {@link RecentsActivity} when a package on the the system changes.
  * {@link TaskStackView}s listen for this event, and remove the tasks associated with the removed
  * packages.
  */
 public class PackagesChangedEvent extends EventBus.Event {
 
-    public final RecentsPackageMonitor monitor;
     public final String packageName;
     public final int userId;
 
-    public PackagesChangedEvent(RecentsPackageMonitor monitor, String packageName, int userId) {
-        this.monitor = monitor;
+    public PackagesChangedEvent(String packageName, int userId) {
         this.packageName = packageName;
         this.userId = userId;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
index 0d614e8c..51d02b5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
@@ -17,7 +17,7 @@
 package com.android.systemui.recents.events.activity;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.model.TaskStack;
 
 /**
  * This is sent by the activity whenever the task stach has changed.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DeleteTaskDataEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DeleteTaskDataEvent.java
index 4ed0270..b52e83b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DeleteTaskDataEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DeleteTaskDataEvent.java
@@ -17,7 +17,7 @@
 package com.android.systemui.recents.events.ui;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task;
 
 /**
  * This is sent when the data associated with a given {@link Task} should be deleted from the
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java
index 40c30b8..da19384 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java
@@ -17,7 +17,7 @@
 package com.android.systemui.recents.events.ui;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task;
 
 /**
  * This is sent when a user wants to show the application info for a {@link Task}.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java
index e0ed7a9..f082928 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java
@@ -17,7 +17,7 @@
 package com.android.systemui.recents.events.ui;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.ThumbnailData;
+import com.android.systemui.shared.recents.model.ThumbnailData;
 
 /**
  * Sent when a task snapshot has changed.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java
index 0628c50..881a64a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java
@@ -17,8 +17,8 @@
 package com.android.systemui.recents.events.ui;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.views.AnimationProps;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.utilities.AnimationProps;
 import com.android.systemui.recents.views.TaskView;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/UpdateFreeformTaskViewVisibilityEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/UpdateFreeformTaskViewVisibilityEvent.java
deleted file mode 100644
index b42da9c..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/UpdateFreeformTaskViewVisibilityEvent.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 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.systemui.recents.events.ui;
-
-import com.android.systemui.recents.events.EventBus;
-
-/**
- * This is sent to update the visibility of all visible freeform task views.
- */
-public class UpdateFreeformTaskViewVisibilityEvent extends EventBus.Event {
-
-    public final boolean visible;
-
-    public UpdateFreeformTaskViewVisibilityEvent(boolean visible) {
-        this.visible = visible;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java
index 216be61..cf61b1e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java
@@ -17,7 +17,7 @@
 package com.android.systemui.recents.events.ui.dragndrop;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.recents.views.DropTarget;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java
index edd7995..297afc5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java
@@ -17,9 +17,8 @@
 package com.android.systemui.recents.events.ui.dragndrop;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.recents.views.DropTarget;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.TaskStack;
 import com.android.systemui.recents.views.TaskView;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java
index 73c282f..73cbde9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java
@@ -17,7 +17,7 @@
 package com.android.systemui.recents.events.ui.dragndrop;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.recents.views.DropTarget;
 import com.android.systemui.recents.views.TaskView;
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java
index e57fa2d..021be77 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java
@@ -19,7 +19,7 @@
 import android.graphics.Point;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.recents.views.TaskView;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartInitializeDropTargetsEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartInitializeDropTargetsEvent.java
index 7030729..64ba574 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartInitializeDropTargetsEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartInitializeDropTargetsEvent.java
@@ -17,7 +17,7 @@
 package com.android.systemui.recents.events.ui.dragndrop;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.recents.views.RecentsViewTouchHandler;
 import com.android.systemui.recents.views.TaskView;
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java
index a1e4957..171ab5e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java
@@ -22,10 +22,5 @@
  * Focuses the next task view in the stack.
  */
 public class FocusNextTaskViewEvent extends EventBus.Event {
-
-    public final int timerIndicatorDuration;
-
-    public FocusNextTaskViewEvent(int timerIndicatorDuration) {
-        this.timerIndicatorDuration = timerIndicatorDuration;
-    }
+    // Simple event
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/NamedCounter.java b/packages/SystemUI/src/com/android/systemui/recents/misc/NamedCounter.java
deleted file mode 100644
index ec3c39c..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/NamedCounter.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.misc;
-
-/**
- * Used to generate successive incremented names.
- */
-public class NamedCounter {
-
-    int mCount;
-    String mPrefix = "";
-    String mSuffix = "";
-
-    public NamedCounter(String prefix, String suffix) {
-        mPrefix = prefix;
-        mSuffix = suffix;
-    }
-
-    /** Returns the next name. */
-    public String nextName() {
-        String name = mPrefix + mCount + mSuffix;
-        mCount++;
-        return name;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/RectFEvaluator.java b/packages/SystemUI/src/com/android/systemui/recents/misc/RectFEvaluator.java
deleted file mode 100644
index 72511de..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/RectFEvaluator.java
+++ /dev/null
@@ -1,52 +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 com.android.systemui.recents.misc;
-
-import android.animation.TypeEvaluator;
-import android.graphics.RectF;
-
-/**
- * This evaluator can be used to perform type interpolation between <code>RectF</code> values.
- */
-public class RectFEvaluator implements TypeEvaluator<RectF> {
-
-    private RectF mRect = new RectF();
-
-    /**
-     * This function returns the result of linearly interpolating the start and
-     * end Rect values, with <code>fraction</code> representing the proportion
-     * between the start and end values. The calculation is a simple parametric
-     * calculation on each of the separate components in the Rect objects
-     * (left, top, right, and bottom).
-     *
-     * <p>The object returned will be the <code>reuseRect</code> passed into the constructor.</p>
-     *
-     * @param fraction   The fraction from the starting to the ending values
-     * @param startValue The start Rect
-     * @param endValue   The end Rect
-     * @return A linear interpolation between the start and end values, given the
-     *         <code>fraction</code> parameter.
-     */
-    @Override
-    public RectF evaluate(float fraction, RectF startValue, RectF endValue) {
-        float left = startValue.left + ((endValue.left - startValue.left) * fraction);
-        float top = startValue.top + ((endValue.top - startValue.top) * fraction);
-        float right = startValue.right + ((endValue.right - startValue.right) * fraction);
-        float bottom = startValue.bottom + ((endValue.bottom - startValue.bottom) * fraction);
-        mRect.set(left, top, right, bottom);
-        return mRect;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index bddf9a5..87f24fd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -25,27 +25,20 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManager.StackInfo;
-import android.app.ActivityManager.TaskSnapshot;
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
 import android.app.IActivityManager;
-import android.app.KeyguardManager;
 import android.app.WindowConfiguration;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -55,24 +48,18 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.IRemoteCallback;
-import android.os.Message;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
-import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.provider.Settings.Secure;
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
-import android.util.ArraySet;
-import android.util.IconDrawableFactory;
 import android.util.Log;
 import android.util.MutableBoolean;
 import android.view.Display;
@@ -89,19 +76,12 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.UiOffloadThread;
-import com.android.systemui.pip.tv.PipMenuActivity;
 import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsDebugFlags;
 import com.android.systemui.recents.RecentsImpl;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.ThumbnailData;
+import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.statusbar.policy.UserInfoController;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
 import java.util.List;
-import java.util.Random;
 
 /**
  * Acts as a shim around the real system services that we need to access data from, and provides
@@ -117,42 +97,32 @@
         sBitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565;
     }
 
-    final static List<String> sRecentsBlacklist;
-    static {
-        sRecentsBlacklist = new ArrayList<>();
-        sRecentsBlacklist.add(PipMenuActivity.class.getName());
-    }
-
     private static SystemServicesProxy sSystemServicesProxy;
 
     AccessibilityManager mAccm;
     ActivityManager mAm;
     IActivityManager mIam;
     PackageManager mPm;
-    IconDrawableFactory mDrawableFactory;
     IPackageManager mIpm;
     private final IDreamManager mDreamManager;
     private final Context mContext;
     AssistUtils mAssistUtils;
     WindowManager mWm;
     IWindowManager mIwm;
-    KeyguardManager mKgm;
     UserManager mUm;
     Display mDisplay;
     String mRecentsPackage;
-    ComponentName mAssistComponent;
+    private TaskStackChangeListeners mTaskStackChangeListeners;
     private int mCurrentUserId;
 
     boolean mIsSafeMode;
-    boolean mHasFreeformWorkspaceSupport;
 
-    Bitmap mDummyIcon;
     int mDummyThumbnailWidth;
     int mDummyThumbnailHeight;
     Paint mBgProtectionPaint;
     Canvas mBgProtectionCanvas;
 
-    private final Handler mHandler = new H();
+    private final Handler mHandler = new Handler();
     private final Runnable mGcRunnable = new Runnable() {
         @Override
         public void run() {
@@ -163,144 +133,10 @@
 
     private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
 
-    /**
-     * An abstract class to track task stack changes.
-     * Classes should implement this instead of {@link android.app.ITaskStackListener}
-     * to reduce IPC calls from system services. These callbacks will be called on the main thread.
-     */
-    public abstract static class TaskStackListener {
-        /**
-         * NOTE: This call is made of the thread that the binder call comes in on.
-         */
-        public void onTaskStackChangedBackground() { }
-        public void onTaskStackChanged() { }
-        public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) { }
-        public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { }
-        public void onActivityUnpinned() { }
-        public void onPinnedActivityRestartAttempt(boolean clearedTask) { }
-        public void onPinnedStackAnimationStarted() { }
-        public void onPinnedStackAnimationEnded() { }
-        public void onActivityForcedResizable(String packageName, int taskId, int reason) { }
-        public void onActivityDismissingDockedStack() { }
-        public void onActivityLaunchOnSecondaryDisplayFailed() { }
-        public void onTaskProfileLocked(int taskId, int userId) { }
-
-        /**
-         * Checks that the current user matches the user's SystemUI process. Since
-         * {@link android.app.ITaskStackListener} is not multi-user aware, handlers of
-         * TaskStackListener should make this call to verify that we don't act on events from other
-         * user's processes.
-         */
-        protected final boolean checkCurrentUserId(Context context, boolean debug) {
-            int processUserId = UserHandle.myUserId();
-            int currentUserId = SystemServicesProxy.getInstance(context).getCurrentUser();
-            if (processUserId != currentUserId) {
-                if (debug) {
-                    Log.d(TAG, "UID mismatch. SystemUI is running uid=" + processUserId
-                            + " and the current user is uid=" + currentUserId);
-                }
-                return false;
-            }
-            return true;
-        }
-    }
-
-    /**
-     * Implementation of {@link android.app.ITaskStackListener} to listen task stack changes from
-     * ActivityManagerService.
-     * This simply passes callbacks to listeners through {@link H}.
-     * */
-    private android.app.TaskStackListener mTaskStackListener = new android.app.TaskStackListener() {
-
-        private final List<SystemServicesProxy.TaskStackListener> mTmpListeners = new ArrayList<>();
-
-        @Override
-        public void onTaskStackChanged() throws RemoteException {
-            // Call the task changed callback for the non-ui thread listeners first
-            synchronized (mTaskStackListeners) {
-                mTmpListeners.clear();
-                mTmpListeners.addAll(mTaskStackListeners);
-            }
-            for (int i = mTmpListeners.size() - 1; i >= 0; i--) {
-                mTmpListeners.get(i).onTaskStackChangedBackground();
-            }
-
-            mHandler.removeMessages(H.ON_TASK_STACK_CHANGED);
-            mHandler.sendEmptyMessage(H.ON_TASK_STACK_CHANGED);
-        }
-
-        @Override
-        public void onActivityPinned(String packageName, int userId, int taskId, int stackId)
-                throws RemoteException {
-            mHandler.removeMessages(H.ON_ACTIVITY_PINNED);
-            mHandler.obtainMessage(H.ON_ACTIVITY_PINNED,
-                    new PinnedActivityInfo(packageName, userId, taskId, stackId)).sendToTarget();
-        }
-
-        @Override
-        public void onActivityUnpinned() throws RemoteException {
-            mHandler.removeMessages(H.ON_ACTIVITY_UNPINNED);
-            mHandler.sendEmptyMessage(H.ON_ACTIVITY_UNPINNED);
-        }
-
-        @Override
-        public void onPinnedActivityRestartAttempt(boolean clearedTask)
-                throws RemoteException{
-            mHandler.removeMessages(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT);
-            mHandler.obtainMessage(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT, clearedTask ? 1 : 0, 0)
-                    .sendToTarget();
-        }
-
-        @Override
-        public void onPinnedStackAnimationStarted() throws RemoteException {
-            mHandler.removeMessages(H.ON_PINNED_STACK_ANIMATION_STARTED);
-            mHandler.sendEmptyMessage(H.ON_PINNED_STACK_ANIMATION_STARTED);
-        }
-
-        @Override
-        public void onPinnedStackAnimationEnded() throws RemoteException {
-            mHandler.removeMessages(H.ON_PINNED_STACK_ANIMATION_ENDED);
-            mHandler.sendEmptyMessage(H.ON_PINNED_STACK_ANIMATION_ENDED);
-        }
-
-        @Override
-        public void onActivityForcedResizable(String packageName, int taskId, int reason)
-                throws RemoteException {
-            mHandler.obtainMessage(H.ON_ACTIVITY_FORCED_RESIZABLE, taskId, reason, packageName)
-                    .sendToTarget();
-        }
-
-        @Override
-        public void onActivityDismissingDockedStack() throws RemoteException {
-            mHandler.sendEmptyMessage(H.ON_ACTIVITY_DISMISSING_DOCKED_STACK);
-        }
-
-        @Override
-        public void onActivityLaunchOnSecondaryDisplayFailed() throws RemoteException {
-            mHandler.sendEmptyMessage(H.ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED);
-        }
-
-        @Override
-        public void onTaskProfileLocked(int taskId, int userId) {
-            mHandler.obtainMessage(H.ON_TASK_PROFILE_LOCKED, taskId, userId).sendToTarget();
-        }
-
-        @Override
-        public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot)
-                throws RemoteException {
-            mHandler.obtainMessage(H.ON_TASK_SNAPSHOT_CHANGED, taskId, 0, snapshot).sendToTarget();
-        }
-    };
-
     private final UserInfoController.OnUserInfoChangedListener mOnUserInfoChangedListener =
             (String name, Drawable picture, String userAccount) ->
                     mCurrentUserId = mAm.getCurrentUser();
 
-    /**
-     * List of {@link TaskStackListener} registered from {@link #registerTaskStackListener}.
-     */
-    private List<TaskStackListener> mTaskStackListeners = new ArrayList<>();
-
     /** Private constructor */
     private SystemServicesProxy(Context context) {
         mContext = context.getApplicationContext();
@@ -308,23 +144,18 @@
         mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
         mIam = ActivityManager.getService();
         mPm = context.getPackageManager();
-        mDrawableFactory = IconDrawableFactory.newInstance(context);
         mIpm = AppGlobals.getPackageManager();
         mAssistUtils = new AssistUtils(context);
         mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
         mIwm = WindowManagerGlobal.getWindowManagerService();
-        mKgm = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
         mUm = UserManager.get(context);
         mDreamManager = IDreamManager.Stub.asInterface(
                 ServiceManager.checkService(DreamService.DREAM_SERVICE));
         mDisplay = mWm.getDefaultDisplay();
         mRecentsPackage = context.getPackageName();
-        mHasFreeformWorkspaceSupport =
-                mPm.hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT) ||
-                        Settings.Global.getInt(context.getContentResolver(),
-                                DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
         mIsSafeMode = mPm.isSafeMode();
         mCurrentUserId = mAm.getCurrentUser();
+        mTaskStackChangeListeners = new TaskStackChangeListeners(Looper.getMainLooper());
 
         // Get the dummy thumbnail width/heights
         Resources res = context.getResources();
@@ -339,23 +170,11 @@
         mBgProtectionPaint.setColor(0xFFffffff);
         mBgProtectionCanvas = new Canvas();
 
-        // Resolve the assist intent
-        mAssistComponent = mAssistUtils.getAssistComponentForUser(UserHandle.myUserId());
-
         // Since SystemServicesProxy can be accessed from a per-SysUI process component, create a
         // per-process listener to keep track of the current user id to reduce the number of binder
         // calls to fetch it.
         UserInfoController userInfoController = Dependency.get(UserInfoController.class);
         userInfoController.addCallback(mOnUserInfoChangedListener);
-
-        if (RecentsDebugFlags.Static.EnableMockTasks) {
-            // Create a dummy icon
-            mDummyIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
-            mDummyIcon.eraseColor(0xFF999999);
-        }
-
-        Collections.addAll(sRecentsBlacklist,
-                res.getStringArray(R.array.recents_blacklist_array));
     }
 
     /**
@@ -377,110 +196,6 @@
     }
 
     /**
-     * @return whether the provided {@param className} is blacklisted
-     */
-    public boolean isBlackListedActivity(String className) {
-        return sRecentsBlacklist.contains(className);
-    }
-
-    /**
-     * Returns a list of the recents tasks.
-     *
-     * @param includeFrontMostExcludedTask if set, will ensure that the front most excluded task
-     *                                     will be visible, otherwise no excluded tasks will be
-     *                                     visible.
-     */
-    public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numLatestTasks, int userId,
-            boolean includeFrontMostExcludedTask, ArraySet<Integer> quietProfileIds) {
-        if (mAm == null) return null;
-
-        // If we are mocking, then create some recent tasks
-        if (RecentsDebugFlags.Static.EnableMockTasks) {
-            ArrayList<ActivityManager.RecentTaskInfo> tasks =
-                    new ArrayList<ActivityManager.RecentTaskInfo>();
-            int count = Math.min(numLatestTasks, RecentsDebugFlags.Static.MockTaskCount);
-            for (int i = 0; i < count; i++) {
-                // Create a dummy component name
-                int packageIndex = i % RecentsDebugFlags.Static.MockTasksPackageCount;
-                ComponentName cn = new ComponentName("com.android.test" + packageIndex,
-                        "com.android.test" + i + ".Activity");
-                String description = "" + i + " - " +
-                        Long.toString(Math.abs(new Random().nextLong()), 36);
-                // Create the recent task info
-                ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
-                rti.id = rti.persistentId = rti.affiliatedTaskId = i;
-                rti.baseIntent = new Intent();
-                rti.baseIntent.setComponent(cn);
-                rti.description = description;
-                rti.firstActiveTime = rti.lastActiveTime = i;
-                if (i % 2 == 0) {
-                    rti.taskDescription = new ActivityManager.TaskDescription(description,
-                            Bitmap.createBitmap(mDummyIcon), null,
-                            0xFF000000 | (0xFFFFFF & new Random().nextInt()),
-                            0xFF000000 | (0xFFFFFF & new Random().nextInt()),
-                            0, 0);
-                } else {
-                    rti.taskDescription = new ActivityManager.TaskDescription();
-                }
-                tasks.add(rti);
-            }
-            return tasks;
-        }
-
-        // Remove home/recents/excluded tasks
-        int minNumTasksToQuery = 10;
-        int numTasksToQuery = Math.max(minNumTasksToQuery, numLatestTasks);
-        int flags = ActivityManager.RECENT_IGNORE_HOME_AND_RECENTS_STACK_TASKS |
-                ActivityManager.RECENT_INGORE_DOCKED_STACK_TOP_TASK |
-                ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS |
-                ActivityManager.RECENT_IGNORE_UNAVAILABLE |
-                ActivityManager.RECENT_INCLUDE_PROFILES;
-        if (includeFrontMostExcludedTask) {
-            flags |= ActivityManager.RECENT_WITH_EXCLUDED;
-        }
-        List<ActivityManager.RecentTaskInfo> tasks = null;
-        try {
-            tasks = mAm.getRecentTasksForUser(numTasksToQuery, flags, userId);
-        } catch (Exception e) {
-            Log.e(TAG, "Failed to get recent tasks", e);
-        }
-
-        // Break early if we can't get a valid set of tasks
-        if (tasks == null) {
-            return new ArrayList<>();
-        }
-
-        boolean isFirstValidTask = true;
-        Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
-        while (iter.hasNext()) {
-            ActivityManager.RecentTaskInfo t = iter.next();
-
-            // NOTE: The order of these checks happens in the expected order of the traversal of the
-            // tasks
-
-            // Remove the task if it or it's package are blacklsited
-            if (sRecentsBlacklist.contains(t.realActivity.getClassName()) ||
-                    sRecentsBlacklist.contains(t.realActivity.getPackageName())) {
-                iter.remove();
-                continue;
-            }
-
-            // Remove the task if it is marked as excluded, unless it is the first most task and we
-            // are requested to include it
-            boolean isExcluded = (t.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
-                    == Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
-            isExcluded |= quietProfileIds.contains(t.userId);
-            if (isExcluded && (!isFirstValidTask || !includeFrontMostExcludedTask)) {
-                iter.remove();
-            }
-
-            isFirstValidTask = false;
-        }
-
-        return tasks.subList(0, Math.min(tasks.size(), numLatestTasks));
-    }
-
-    /**
      * Returns the top running task.
      */
     public ActivityManager.RunningTaskInfo getRunningTask() {
@@ -572,13 +287,6 @@
     }
 
     /**
-     * Returns whether this device has freeform workspaces.
-     */
-    public boolean hasFreeformWorkspaceSupport() {
-        return mHasFreeformWorkspaceSupport;
-    }
-
-    /**
      * Returns whether this device is in the safe mode.
      */
     public boolean isInSafeMode() {
@@ -646,7 +354,7 @@
      */
     public boolean hasSoftNavigationBar() {
         try {
-            return WindowManagerGlobal.getWindowManagerService().hasNavigationBar();
+            return mIwm.hasNavigationBar();
         } catch (RemoteException e) {
             e.printStackTrace();
         }
@@ -689,43 +397,6 @@
         }
     }
 
-    /** Returns the top task thumbnail for the given task id */
-    public ThumbnailData getTaskThumbnail(int taskId, boolean reduced) {
-        if (mAm == null) return null;
-
-        // If we are mocking, then just return a dummy thumbnail
-        if (RecentsDebugFlags.Static.EnableMockTasks) {
-            ThumbnailData thumbnailData = new ThumbnailData();
-            thumbnailData.thumbnail = Bitmap.createBitmap(mDummyThumbnailWidth,
-                    mDummyThumbnailHeight, Bitmap.Config.ARGB_8888);
-            thumbnailData.thumbnail.eraseColor(0xff333333);
-            return thumbnailData;
-        }
-
-        return getThumbnail(taskId, reduced);
-    }
-
-    /**
-     * Returns a task thumbnail from the activity manager
-     */
-    public @NonNull ThumbnailData getThumbnail(int taskId, boolean reducedResolution) {
-        if (mAm == null) {
-            return new ThumbnailData();
-        }
-
-        ActivityManager.TaskSnapshot snapshot = null;
-        try {
-            snapshot = ActivityManager.getService().getTaskSnapshot(taskId, reducedResolution);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Failed to retrieve snapshot", e);
-        }
-        if (snapshot != null) {
-            return ThumbnailData.createFromTaskSnapshot(snapshot);
-        } else {
-            return new ThumbnailData();
-        }
-    }
-
     /** Set the task's windowing mode. */
     public void setTaskWindowingMode(int taskId, int windowingMode) {
         if (mIam == null) return;
@@ -740,11 +411,14 @@
     /** Removes the task */
     public void removeTask(final int taskId) {
         if (mAm == null) return;
-        if (RecentsDebugFlags.Static.EnableMockTasks) return;
 
         // Remove the task.
         mUiOffloadThread.submit(() -> {
-            mAm.removeTask(taskId);
+            try {
+                mIam.removeTask(taskId);
+            } catch (RemoteException e) {
+                e.printStackTrace();
+            }
         });
     }
 
@@ -760,145 +434,6 @@
         });
     }
 
-    /**
-     * Returns the activity info for a given component name.
-     *
-     * @param cn The component name of the activity.
-     * @param userId The userId of the user that this is for.
-     */
-    public ActivityInfo getActivityInfo(ComponentName cn, int userId) {
-        if (mIpm == null) return null;
-        if (RecentsDebugFlags.Static.EnableMockTasks) return new ActivityInfo();
-
-        try {
-            return mIpm.getActivityInfo(cn, PackageManager.GET_META_DATA, userId);
-        } catch (RemoteException e) {
-            e.printStackTrace();
-            return null;
-        }
-    }
-
-    /**
-     * Returns the activity info for a given component name.
-     *
-     * @param cn The component name of the activity.
-     */
-    public ActivityInfo getActivityInfo(ComponentName cn) {
-        if (mPm == null) return null;
-        if (RecentsDebugFlags.Static.EnableMockTasks) return new ActivityInfo();
-
-        try {
-            return mPm.getActivityInfo(cn, PackageManager.GET_META_DATA);
-        } catch (PackageManager.NameNotFoundException e) {
-            e.printStackTrace();
-            return null;
-        }
-    }
-
-    /**
-     * Returns the activity label, badging if necessary.
-     */
-    public String getBadgedActivityLabel(ActivityInfo info, int userId) {
-        if (mPm == null) return null;
-
-        // If we are mocking, then return a mock label
-        if (RecentsDebugFlags.Static.EnableMockTasks) {
-            return "Recent Task: " + userId;
-        }
-
-        return getBadgedLabel(info.loadLabel(mPm).toString(), userId);
-    }
-
-    /**
-     * Returns the application label, badging if necessary.
-     */
-    public String getBadgedApplicationLabel(ApplicationInfo appInfo, int userId) {
-        if (mPm == null) return null;
-
-        // If we are mocking, then return a mock label
-        if (RecentsDebugFlags.Static.EnableMockTasks) {
-            return "Recent Task App: " + userId;
-        }
-
-        return getBadgedLabel(appInfo.loadLabel(mPm).toString(), userId);
-    }
-
-    /**
-     * Returns the content description for a given task, badging it if necessary.  The content
-     * description joins the app and activity labels.
-     */
-    public String getBadgedContentDescription(ActivityInfo info, int userId,
-            ActivityManager.TaskDescription td, Resources res) {
-        // If we are mocking, then return a mock label
-        if (RecentsDebugFlags.Static.EnableMockTasks) {
-            return "Recent Task Content Description: " + userId;
-        }
-
-        String activityLabel;
-        if (td != null && td.getLabel() != null) {
-            activityLabel = td.getLabel();
-        } else {
-            activityLabel = info.loadLabel(mPm).toString();
-        }
-        String applicationLabel = info.applicationInfo.loadLabel(mPm).toString();
-        String badgedApplicationLabel = getBadgedLabel(applicationLabel, userId);
-        return applicationLabel.equals(activityLabel) ? badgedApplicationLabel
-                : res.getString(R.string.accessibility_recents_task_header,
-                        badgedApplicationLabel, activityLabel);
-    }
-
-    /**
-     * Returns the activity icon for the ActivityInfo for a user, badging if
-     * necessary.
-     */
-    public Drawable getBadgedActivityIcon(ActivityInfo info, int userId) {
-        if (mPm == null) return null;
-
-        // If we are mocking, then return a mock label
-        if (RecentsDebugFlags.Static.EnableMockTasks) {
-            return new ColorDrawable(0xFF666666);
-        }
-
-        return mDrawableFactory.getBadgedIcon(info, info.applicationInfo, userId);
-    }
-
-    /**
-     * Returns the application icon for the ApplicationInfo for a user, badging if
-     * necessary.
-     */
-    public Drawable getBadgedApplicationIcon(ApplicationInfo appInfo, int userId) {
-        if (mPm == null) return null;
-
-        // If we are mocking, then return a mock label
-        if (RecentsDebugFlags.Static.EnableMockTasks) {
-            return new ColorDrawable(0xFF666666);
-        }
-
-        return mDrawableFactory.getBadgedIcon(appInfo, userId);
-    }
-
-    /**
-     * Returns the task description icon, loading and badging it if it necessary.
-     */
-    public Drawable getBadgedTaskDescriptionIcon(ActivityManager.TaskDescription taskDescription,
-            int userId, Resources res) {
-
-        // If we are mocking, then return a mock label
-        if (RecentsDebugFlags.Static.EnableMockTasks) {
-            return new ColorDrawable(0xFF666666);
-        }
-
-        Bitmap tdIcon = taskDescription.getInMemoryIcon();
-        if (tdIcon == null) {
-            tdIcon = ActivityManager.TaskDescription.loadTaskDescriptionIcon(
-                    taskDescription.getIconFilename(), userId);
-        }
-        if (tdIcon != null) {
-            return getBadgedIcon(new BitmapDrawable(res, tdIcon), userId);
-        }
-        return null;
-    }
-
     public ActivityManager.TaskDescription getTaskDescription(int taskId) {
         try {
             return mIam.getTaskDescription(taskId);
@@ -908,85 +443,6 @@
     }
 
     /**
-     * Returns the given icon for a user, badging if necessary.
-     */
-    private Drawable getBadgedIcon(Drawable icon, int userId) {
-        if (userId != UserHandle.myUserId()) {
-            icon = mPm.getUserBadgedIcon(icon, new UserHandle(userId));
-        }
-        return icon;
-    }
-
-    /**
-     * Returns a banner used on TV for the specified Activity.
-     */
-    public Drawable getActivityBanner(ActivityInfo info) {
-        if (mPm == null) return null;
-
-        // If we are mocking, then return a mock banner
-        if (RecentsDebugFlags.Static.EnableMockTasks) {
-            return new ColorDrawable(0xFF666666);
-        }
-
-        Drawable banner = info.loadBanner(mPm);
-        return banner;
-    }
-
-    /**
-     * Returns a logo used on TV for the specified Activity.
-     */
-    public Drawable getActivityLogo(ActivityInfo info) {
-        if (mPm == null) return null;
-
-        // If we are mocking, then return a mock logo
-        if (RecentsDebugFlags.Static.EnableMockTasks) {
-            return new ColorDrawable(0xFF666666);
-        }
-
-        Drawable logo = info.loadLogo(mPm);
-        return logo;
-    }
-
-
-    /**
-     * Returns the given label for a user, badging if necessary.
-     */
-    private String getBadgedLabel(String label, int userId) {
-        if (userId != UserHandle.myUserId()) {
-            label = mPm.getUserBadgedLabel(label, new UserHandle(userId)).toString();
-        }
-        return label;
-    }
-
-    /**
-     * Returns whether the provided {@param userId} is currently locked (and showing Keyguard).
-     */
-    public boolean isDeviceLocked(int userId) {
-        if (mKgm == null) {
-            return false;
-        }
-        return mKgm.isDeviceLocked(userId);
-    }
-
-    /** Returns the package name of the home activity. */
-    public String getHomeActivityPackageName() {
-        if (mPm == null) return null;
-        if (RecentsDebugFlags.Static.EnableMockTasks) return null;
-
-        ArrayList<ResolveInfo> homeActivities = new ArrayList<>();
-        ComponentName defaultHomeActivity = mPm.getHomeActivities(homeActivities);
-        if (defaultHomeActivity != null) {
-            return defaultHomeActivity.getPackageName();
-        } else if (homeActivities.size() == 1) {
-            ResolveInfo info = homeActivities.get(0);
-            if (info.activityInfo != null) {
-                return info.activityInfo.packageName;
-            }
-        }
-        return null;
-    }
-
-    /**
      * Returns whether the provided {@param userId} represents the system user.
      */
     public boolean isSystemUser(int userId) {
@@ -1091,7 +547,7 @@
             ActivityManager.StackInfo stackInfo =
                     mIam.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS);
             if (stackInfo == null) {
-                stackInfo = mIam.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD);
+                stackInfo = mIam.getStackInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
             }
             if (stackInfo != null) {
                 windowRect.set(stackInfo.bounds);
@@ -1174,19 +630,11 @@
      * Registers a task stack listener with the system.
      * This should be called on the main thread.
      */
-    public void registerTaskStackListener(TaskStackListener listener) {
+    public void registerTaskStackListener(TaskStackChangeListener listener) {
         if (mIam == null) return;
 
-        synchronized (mTaskStackListeners) {
-            mTaskStackListeners.add(listener);
-            if (mTaskStackListeners.size() == 1) {
-                // Register mTaskStackListener to IActivityManager only once if needed.
-                try {
-                    mIam.registerTaskStackListener(mTaskStackListener);
-                } catch (Exception e) {
-                    Log.w(TAG, "Failed to call registerTaskStackListener", e);
-                }
-            }
+        synchronized (mTaskStackChangeListeners) {
+            mTaskStackChangeListeners.addListener(mIam, listener);
         }
     }
 
@@ -1195,7 +643,7 @@
             return;
         }
         try {
-            WindowManagerGlobal.getWindowManagerService().endProlongedAnimations();
+            mIwm.endProlongedAnimations();
         } catch (Exception e) {
             e.printStackTrace();
         }
@@ -1205,7 +653,7 @@
         if (mWm == null) return;
 
         try {
-            WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(listener);
+            mIwm.registerDockedStackListener(listener);
         } catch (Exception e) {
             e.printStackTrace();
         }
@@ -1232,8 +680,7 @@
         if (mWm == null) return;
 
         try {
-            WindowManagerGlobal.getWindowManagerService().getStableInsets(Display.DEFAULT_DISPLAY,
-                    outStableInsets);
+            mIwm.getStableInsets(Display.DEFAULT_DISPLAY, outStableInsets);
         } catch (Exception e) {
             e.printStackTrace();
         }
@@ -1243,9 +690,7 @@
             IAppTransitionAnimationSpecsFuture future, IRemoteCallback animStartedListener,
             boolean scaleUp) {
         try {
-            WindowManagerGlobal.getWindowManagerService()
-                    .overridePendingAppTransitionMultiThumbFuture(future, animStartedListener,
-                            scaleUp);
+            mIwm.overridePendingAppTransitionMultiThumbFuture(future, animStartedListener, scaleUp);
         } catch (RemoteException e) {
             Log.w(TAG, "Failed to override transition: " + e);
         }
@@ -1254,23 +699,27 @@
     /**
      * Updates the visibility of recents.
      */
-    public void setRecentsVisibility(boolean visible) {
-        try {
-            mIwm.setRecentsVisibility(visible);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Unable to reach window manager", e);
-        }
+    public void setRecentsVisibility(final boolean visible) {
+        mUiOffloadThread.submit(() -> {
+            try {
+                mIwm.setRecentsVisibility(visible);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Unable to reach window manager", e);
+            }
+        });
     }
 
     /**
      * Updates the visibility of the picture-in-picture.
      */
-    public void setPipVisibility(boolean visible) {
-        try {
-            mIwm.setPipVisibility(visible);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Unable to reach window manager", e);
-        }
+    public void setPipVisibility(final boolean visible) {
+        mUiOffloadThread.submit(() -> {
+            try {
+                mIwm.setPipVisibility(visible);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Unable to reach window manager", e);
+            }
+        });
     }
 
     public boolean isDreaming() {
@@ -1292,126 +741,7 @@
         });
     }
 
-    public void updateOverviewLastStackActiveTimeAsync(long newLastStackActiveTime,
-            int currentUserId) {
-        mUiOffloadThread.submit(() -> {
-            Settings.Secure.putLongForUser(mContext.getContentResolver(),
-                    Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, newLastStackActiveTime, currentUserId);
-        });
-    }
-
     public interface StartActivityFromRecentsResultListener {
         void onStartActivityResult(boolean succeeded);
     }
-
-    private class PinnedActivityInfo {
-        final String mPackageName;
-        final int mUserId;
-        final int mTaskId;
-        final int mStackId;
-
-        PinnedActivityInfo(String packageName, int userId, int taskId, int stackId) {
-            mPackageName = packageName;
-            mUserId = userId;
-            mTaskId = taskId;
-            mStackId = stackId;
-        }
-    }
-
-    private final class H extends Handler {
-        private static final int ON_TASK_STACK_CHANGED = 1;
-        private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
-        private static final int ON_ACTIVITY_PINNED = 3;
-        private static final int ON_PINNED_ACTIVITY_RESTART_ATTEMPT = 4;
-        private static final int ON_PINNED_STACK_ANIMATION_ENDED = 5;
-        private static final int ON_ACTIVITY_FORCED_RESIZABLE = 6;
-        private static final int ON_ACTIVITY_DISMISSING_DOCKED_STACK = 7;
-        private static final int ON_TASK_PROFILE_LOCKED = 8;
-        private static final int ON_PINNED_STACK_ANIMATION_STARTED = 9;
-        private static final int ON_ACTIVITY_UNPINNED = 10;
-        private static final int ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED = 11;
-
-        @Override
-        public void handleMessage(Message msg) {
-            synchronized (mTaskStackListeners) {
-                switch (msg.what) {
-                    case ON_TASK_STACK_CHANGED: {
-                    Trace.beginSection("onTaskStackChanged");
-                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
-                            mTaskStackListeners.get(i).onTaskStackChanged();
-                        }
-                    Trace.endSection();
-                        break;
-                    }
-                    case ON_TASK_SNAPSHOT_CHANGED: {
-                    Trace.beginSection("onTaskSnapshotChanged");
-                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
-                            mTaskStackListeners.get(i).onTaskSnapshotChanged(msg.arg1,
-                                    (TaskSnapshot) msg.obj);
-                        }
-                    Trace.endSection();
-                        break;
-                    }
-                    case ON_ACTIVITY_PINNED: {
-                        final PinnedActivityInfo info = (PinnedActivityInfo) msg.obj;
-                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
-                            mTaskStackListeners.get(i).onActivityPinned(
-                                    info.mPackageName, info.mUserId, info.mTaskId, info.mStackId);
-                        }
-                        break;
-                    }
-                    case ON_ACTIVITY_UNPINNED: {
-                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
-                            mTaskStackListeners.get(i).onActivityUnpinned();
-                        }
-                        break;
-                    }
-                    case ON_PINNED_ACTIVITY_RESTART_ATTEMPT: {
-                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
-                            mTaskStackListeners.get(i).onPinnedActivityRestartAttempt(
-                                    msg.arg1 != 0);
-                        }
-                        break;
-                    }
-                    case ON_PINNED_STACK_ANIMATION_STARTED: {
-                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
-                            mTaskStackListeners.get(i).onPinnedStackAnimationStarted();
-                        }
-                        break;
-                    }
-                    case ON_PINNED_STACK_ANIMATION_ENDED: {
-                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
-                            mTaskStackListeners.get(i).onPinnedStackAnimationEnded();
-                        }
-                        break;
-                    }
-                    case ON_ACTIVITY_FORCED_RESIZABLE: {
-                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
-                            mTaskStackListeners.get(i).onActivityForcedResizable(
-                                    (String) msg.obj, msg.arg1, msg.arg2);
-                        }
-                        break;
-                    }
-                    case ON_ACTIVITY_DISMISSING_DOCKED_STACK: {
-                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
-                            mTaskStackListeners.get(i).onActivityDismissingDockedStack();
-                        }
-                        break;
-                    }
-                    case ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED: {
-                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
-                            mTaskStackListeners.get(i).onActivityLaunchOnSecondaryDisplayFailed();
-                        }
-                        break;
-                    }
-                    case ON_TASK_PROFILE_LOCKED: {
-                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
-                            mTaskStackListeners.get(i).onTaskProfileLocked(msg.arg1, msg.arg2);
-                        }
-                        break;
-                    }
-                }
-            }
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/TaskStackChangeListener.java b/packages/SystemUI/src/com/android/systemui/recents/misc/TaskStackChangeListener.java
new file mode 100644
index 0000000..6d0952a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/TaskStackChangeListener.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.misc;
+
+import android.app.ActivityManager.TaskSnapshot;
+import android.content.Context;
+import android.os.UserHandle;
+import android.util.Log;
+
+/**
+ * An abstract class to track task stack changes.
+ * Classes should implement this instead of {@link android.app.ITaskStackListener}
+ * to reduce IPC calls from system services. These callbacks will be called on the main thread.
+ */
+public abstract class TaskStackChangeListener {
+
+    /**
+     * NOTE: This call is made of the thread that the binder call comes in on.
+     */
+    public void onTaskStackChangedBackground() { }
+    public void onTaskStackChanged() { }
+    public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) { }
+    public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { }
+    public void onActivityUnpinned() { }
+    public void onPinnedActivityRestartAttempt(boolean clearedTask) { }
+    public void onPinnedStackAnimationStarted() { }
+    public void onPinnedStackAnimationEnded() { }
+    public void onActivityForcedResizable(String packageName, int taskId, int reason) { }
+    public void onActivityDismissingDockedStack() { }
+    public void onActivityLaunchOnSecondaryDisplayFailed() { }
+    public void onTaskProfileLocked(int taskId, int userId) { }
+
+    /**
+     * Checks that the current user matches the user's SystemUI process. Since
+     * {@link android.app.ITaskStackListener} is not multi-user aware, handlers of
+     * TaskStackChangeListener should make this call to verify that we don't act on events from other
+     * user's processes.
+     */
+    protected final boolean checkCurrentUserId(Context context, boolean debug) {
+        int processUserId = UserHandle.myUserId();
+        int currentUserId = SystemServicesProxy.getInstance(context).getCurrentUser();
+        if (processUserId != currentUserId) {
+            if (debug) {
+                Log.d(SystemServicesProxy.TAG, "UID mismatch. SystemUI is running uid=" + processUserId
+                        + " and the current user is uid=" + currentUserId);
+            }
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/TaskStackChangeListeners.java b/packages/SystemUI/src/com/android/systemui/recents/misc/TaskStackChangeListeners.java
new file mode 100644
index 0000000..8eb70f0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/TaskStackChangeListeners.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.misc;
+
+import android.app.ActivityManager.TaskSnapshot;
+import android.app.IActivityManager;
+import android.app.TaskStackListener;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.Trace;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tracks all the task stack listeners
+ */
+public class TaskStackChangeListeners extends TaskStackListener {
+
+    private static final String TAG = TaskStackChangeListeners.class.getSimpleName();
+
+    /**
+     * List of {@link TaskStackChangeListener} registered from {@link #addListener}.
+     */
+    private final List<TaskStackChangeListener> mTaskStackListeners = new ArrayList<>();
+    private final List<TaskStackChangeListener> mTmpListeners = new ArrayList<>();
+
+    private final Handler mHandler;
+
+    public TaskStackChangeListeners(Looper looper) {
+        mHandler = new H(looper);
+    }
+
+    public void addListener(IActivityManager am, TaskStackChangeListener listener) {
+        mTaskStackListeners.add(listener);
+        if (mTaskStackListeners.size() == 1) {
+            // Register mTaskStackListener to IActivityManager only once if needed.
+            try {
+                am.registerTaskStackListener(this);
+            } catch (Exception e) {
+                Log.w(TAG, "Failed to call registerTaskStackListener", e);
+            }
+        }
+    }
+
+    @Override
+    public void onTaskStackChanged() throws RemoteException {
+        // Call the task changed callback for the non-ui thread listeners first
+        synchronized (mTaskStackListeners) {
+            mTmpListeners.clear();
+            mTmpListeners.addAll(mTaskStackListeners);
+        }
+        for (int i = mTmpListeners.size() - 1; i >= 0; i--) {
+            mTmpListeners.get(i).onTaskStackChangedBackground();
+        }
+
+        mHandler.removeMessages(H.ON_TASK_STACK_CHANGED);
+        mHandler.sendEmptyMessage(H.ON_TASK_STACK_CHANGED);
+    }
+
+    @Override
+    public void onActivityPinned(String packageName, int userId, int taskId, int stackId)
+            throws RemoteException {
+        mHandler.removeMessages(H.ON_ACTIVITY_PINNED);
+        mHandler.obtainMessage(H.ON_ACTIVITY_PINNED,
+                new PinnedActivityInfo(packageName, userId, taskId, stackId)).sendToTarget();
+    }
+
+    @Override
+    public void onActivityUnpinned() throws RemoteException {
+        mHandler.removeMessages(H.ON_ACTIVITY_UNPINNED);
+        mHandler.sendEmptyMessage(H.ON_ACTIVITY_UNPINNED);
+    }
+
+    @Override
+    public void onPinnedActivityRestartAttempt(boolean clearedTask)
+            throws RemoteException{
+        mHandler.removeMessages(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT);
+        mHandler.obtainMessage(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT, clearedTask ? 1 : 0, 0)
+                .sendToTarget();
+    }
+
+    @Override
+    public void onPinnedStackAnimationStarted() throws RemoteException {
+        mHandler.removeMessages(H.ON_PINNED_STACK_ANIMATION_STARTED);
+        mHandler.sendEmptyMessage(H.ON_PINNED_STACK_ANIMATION_STARTED);
+    }
+
+    @Override
+    public void onPinnedStackAnimationEnded() throws RemoteException {
+        mHandler.removeMessages(H.ON_PINNED_STACK_ANIMATION_ENDED);
+        mHandler.sendEmptyMessage(H.ON_PINNED_STACK_ANIMATION_ENDED);
+    }
+
+    @Override
+    public void onActivityForcedResizable(String packageName, int taskId, int reason)
+            throws RemoteException {
+        mHandler.obtainMessage(H.ON_ACTIVITY_FORCED_RESIZABLE, taskId, reason, packageName)
+                .sendToTarget();
+    }
+
+    @Override
+    public void onActivityDismissingDockedStack() throws RemoteException {
+        mHandler.sendEmptyMessage(H.ON_ACTIVITY_DISMISSING_DOCKED_STACK);
+    }
+
+    @Override
+    public void onActivityLaunchOnSecondaryDisplayFailed() throws RemoteException {
+        mHandler.sendEmptyMessage(H.ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED);
+    }
+
+    @Override
+    public void onTaskProfileLocked(int taskId, int userId) throws RemoteException {
+        mHandler.obtainMessage(H.ON_TASK_PROFILE_LOCKED, taskId, userId).sendToTarget();
+    }
+
+    @Override
+    public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot)
+            throws RemoteException {
+        mHandler.obtainMessage(H.ON_TASK_SNAPSHOT_CHANGED, taskId, 0, snapshot).sendToTarget();
+    }
+
+    private final class H extends Handler {
+        private static final int ON_TASK_STACK_CHANGED = 1;
+        private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
+        private static final int ON_ACTIVITY_PINNED = 3;
+        private static final int ON_PINNED_ACTIVITY_RESTART_ATTEMPT = 4;
+        private static final int ON_PINNED_STACK_ANIMATION_ENDED = 5;
+        private static final int ON_ACTIVITY_FORCED_RESIZABLE = 6;
+        private static final int ON_ACTIVITY_DISMISSING_DOCKED_STACK = 7;
+        private static final int ON_TASK_PROFILE_LOCKED = 8;
+        private static final int ON_PINNED_STACK_ANIMATION_STARTED = 9;
+        private static final int ON_ACTIVITY_UNPINNED = 10;
+        private static final int ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED = 11;
+
+        public H(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            synchronized (mTaskStackListeners) {
+                switch (msg.what) {
+                    case ON_TASK_STACK_CHANGED: {
+                        Trace.beginSection("onTaskStackChanged");
+                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                            mTaskStackListeners.get(i).onTaskStackChanged();
+                        }
+                        Trace.endSection();
+                        break;
+                    }
+                    case ON_TASK_SNAPSHOT_CHANGED: {
+                        Trace.beginSection("onTaskSnapshotChanged");
+                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                            mTaskStackListeners.get(i).onTaskSnapshotChanged(msg.arg1,
+                                    (TaskSnapshot) msg.obj);
+                        }
+                        Trace.endSection();
+                        break;
+                    }
+                    case ON_ACTIVITY_PINNED: {
+                        final PinnedActivityInfo info = (PinnedActivityInfo) msg.obj;
+                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                            mTaskStackListeners.get(i).onActivityPinned(
+                                    info.mPackageName, info.mUserId, info.mTaskId, info.mStackId);
+                        }
+                        break;
+                    }
+                    case ON_ACTIVITY_UNPINNED: {
+                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                            mTaskStackListeners.get(i).onActivityUnpinned();
+                        }
+                        break;
+                    }
+                    case ON_PINNED_ACTIVITY_RESTART_ATTEMPT: {
+                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                            mTaskStackListeners.get(i).onPinnedActivityRestartAttempt(
+                                    msg.arg1 != 0);
+                        }
+                        break;
+                    }
+                    case ON_PINNED_STACK_ANIMATION_STARTED: {
+                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                            mTaskStackListeners.get(i).onPinnedStackAnimationStarted();
+                        }
+                        break;
+                    }
+                    case ON_PINNED_STACK_ANIMATION_ENDED: {
+                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                            mTaskStackListeners.get(i).onPinnedStackAnimationEnded();
+                        }
+                        break;
+                    }
+                    case ON_ACTIVITY_FORCED_RESIZABLE: {
+                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                            mTaskStackListeners.get(i).onActivityForcedResizable(
+                                    (String) msg.obj, msg.arg1, msg.arg2);
+                        }
+                        break;
+                    }
+                    case ON_ACTIVITY_DISMISSING_DOCKED_STACK: {
+                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                            mTaskStackListeners.get(i).onActivityDismissingDockedStack();
+                        }
+                        break;
+                    }
+                    case ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED: {
+                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                            mTaskStackListeners.get(i).onActivityLaunchOnSecondaryDisplayFailed();
+                        }
+                        break;
+                    }
+                    case ON_TASK_PROFILE_LOCKED: {
+                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                            mTaskStackListeners.get(i).onTaskProfileLocked(msg.arg1, msg.arg2);
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    private static class PinnedActivityInfo {
+        final String mPackageName;
+        final int mUserId;
+        final int mTaskId;
+        final int mStackId;
+
+        PinnedActivityInfo(String packageName, int userId, int taskId, int stackId) {
+            mPackageName = packageName;
+            mUserId = userId;
+            mTaskId = taskId;
+            mStackId = stackId;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
deleted file mode 100644
index 4349e30..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.misc;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.RectEvaluator;
-import android.annotation.FloatRange;
-import android.app.Activity;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
-import android.os.Trace;
-import android.util.ArraySet;
-import android.util.IntProperty;
-import android.util.Property;
-import android.util.TypedValue;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.ViewStub;
-
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.views.TaskViewTransform;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/* Common code */
-public class Utilities {
-
-    public static final Property<Drawable, Integer> DRAWABLE_ALPHA =
-            new IntProperty<Drawable>("drawableAlpha") {
-                @Override
-                public void setValue(Drawable object, int alpha) {
-                    object.setAlpha(alpha);
-                }
-
-                @Override
-                public Integer get(Drawable object) {
-                    return object.getAlpha();
-                }
-            };
-
-    public static final Property<Drawable, Rect> DRAWABLE_RECT =
-            new Property<Drawable, Rect>(Rect.class, "drawableBounds") {
-                @Override
-                public void set(Drawable object, Rect bounds) {
-                    object.setBounds(bounds);
-                }
-
-                @Override
-                public Rect get(Drawable object) {
-                    return object.getBounds();
-                }
-            };
-
-    public static final RectFEvaluator RECTF_EVALUATOR = new RectFEvaluator();
-    public static final RectEvaluator RECT_EVALUATOR = new RectEvaluator(new Rect());
-    public static final Rect EMPTY_RECT = new Rect();
-
-    /**
-     * @return the first parent walking up the view hierarchy that has the given class type.
-     *
-     * @param parentClass must be a class derived from {@link View}
-     */
-    public static <T extends View> T findParent(View v, Class<T> parentClass) {
-        ViewParent parent = v.getParent();
-        while (parent != null) {
-            if (parentClass.isAssignableFrom(parent.getClass())) {
-                return (T) parent;
-            }
-            parent = parent.getParent();
-        }
-        return null;
-    }
-
-    /**
-     * Initializes the {@param setOut} with the given object.
-     */
-    public static <T> ArraySet<T> objectToSet(T obj, ArraySet<T> setOut) {
-        setOut.clear();
-        if (obj != null) {
-            setOut.add(obj);
-        }
-        return setOut;
-    }
-
-    /**
-     * Replaces the contents of {@param setOut} with the contents of the {@param array}.
-     */
-    public static <T> ArraySet<T> arrayToSet(T[] array, ArraySet<T> setOut) {
-        setOut.clear();
-        if (array != null) {
-            Collections.addAll(setOut, array);
-        }
-        return setOut;
-    }
-
-    /**
-     * @return the clamped {@param value} between the provided {@param min} and {@param max}.
-     */
-    public static float clamp(float value, float min, float max) {
-        return Math.max(min, Math.min(max, value));
-    }
-
-    /**
-     * @return the clamped {@param value} between the provided {@param min} and {@param max}.
-     */
-    public static int clamp(int value, int min, int max) {
-        return Math.max(min, Math.min(max, value));
-    }
-
-    /**
-     * @return the clamped {@param value} between 0 and 1.
-     */
-    public static float clamp01(float value) {
-        return Math.max(0f, Math.min(1f, value));
-    }
-
-    /**
-     * Scales the {@param value} to be proportionally between the {@param min} and
-     * {@param max} values.
-     *
-     * @param value must be between 0 and 1
-     */
-    public static float mapRange(@FloatRange(from=0.0,to=1.0) float value, float min, float max) {
-        return min + (value * (max - min));
-    }
-
-    /**
-     * Scales the {@param value} proportionally from {@param min} and {@param max} to 0 and 1.
-     *
-     * @param value must be between {@param min} and {@param max}
-     */
-    public static float unmapRange(float value, float min, float max) {
-        return (value - min) / (max - min);
-    }
-
-    /** Scales a rect about its centroid */
-    public static void scaleRectAboutCenter(RectF r, float scale) {
-        if (scale != 1.0f) {
-            float cx = r.centerX();
-            float cy = r.centerY();
-            r.offset(-cx, -cy);
-            r.left *= scale;
-            r.top *= scale;
-            r.right *= scale;
-            r.bottom *= scale;
-            r.offset(cx, cy);
-        }
-    }
-
-    /** Calculates the constrast between two colors, using the algorithm provided by the WCAG v2. */
-    public static float computeContrastBetweenColors(int bg, int fg) {
-        float bgR = Color.red(bg) / 255f;
-        float bgG = Color.green(bg) / 255f;
-        float bgB = Color.blue(bg) / 255f;
-        bgR = (bgR < 0.03928f) ? bgR / 12.92f : (float) Math.pow((bgR + 0.055f) / 1.055f, 2.4f);
-        bgG = (bgG < 0.03928f) ? bgG / 12.92f : (float) Math.pow((bgG + 0.055f) / 1.055f, 2.4f);
-        bgB = (bgB < 0.03928f) ? bgB / 12.92f : (float) Math.pow((bgB + 0.055f) / 1.055f, 2.4f);
-        float bgL = 0.2126f * bgR + 0.7152f * bgG + 0.0722f * bgB;
-        
-        float fgR = Color.red(fg) / 255f;
-        float fgG = Color.green(fg) / 255f;
-        float fgB = Color.blue(fg) / 255f;
-        fgR = (fgR < 0.03928f) ? fgR / 12.92f : (float) Math.pow((fgR + 0.055f) / 1.055f, 2.4f);
-        fgG = (fgG < 0.03928f) ? fgG / 12.92f : (float) Math.pow((fgG + 0.055f) / 1.055f, 2.4f);
-        fgB = (fgB < 0.03928f) ? fgB / 12.92f : (float) Math.pow((fgB + 0.055f) / 1.055f, 2.4f);
-        float fgL = 0.2126f * fgR + 0.7152f * fgG + 0.0722f * fgB;
-
-        return Math.abs((fgL + 0.05f) / (bgL + 0.05f));
-    }
-
-    /** Returns the base color overlaid with another overlay color with a specified alpha. */
-    public static int getColorWithOverlay(int baseColor, int overlayColor, float overlayAlpha) {
-        return Color.rgb(
-            (int) (overlayAlpha * Color.red(baseColor) +
-                    (1f - overlayAlpha) * Color.red(overlayColor)),
-            (int) (overlayAlpha * Color.green(baseColor) +
-                    (1f - overlayAlpha) * Color.green(overlayColor)),
-            (int) (overlayAlpha * Color.blue(baseColor) +
-                    (1f - overlayAlpha) * Color.blue(overlayColor)));
-    }
-
-    /**
-     * Cancels an animation ensuring that if it has listeners, onCancel and onEnd
-     * are not called.
-     */
-    public static void cancelAnimationWithoutCallbacks(Animator animator) {
-        if (animator != null && animator.isStarted()) {
-            removeAnimationListenersRecursive(animator);
-            animator.cancel();
-        }
-    }
-
-    /**
-     * Recursively removes all the listeners of all children of this animator
-     */
-    public static void removeAnimationListenersRecursive(Animator animator) {
-        if (animator instanceof AnimatorSet) {
-            ArrayList<Animator> animators = ((AnimatorSet) animator).getChildAnimations();
-            for (int i = animators.size() - 1; i >= 0; i--) {
-                removeAnimationListenersRecursive(animators.get(i));
-            }
-        }
-        animator.removeAllListeners();
-    }
-
-    /**
-     * Sets the given {@link View}'s frame from its current translation.
-     */
-    public static void setViewFrameFromTranslation(View v) {
-        RectF taskViewRect = new RectF(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
-        taskViewRect.offset(v.getTranslationX(), v.getTranslationY());
-        v.setTranslationX(0);
-        v.setTranslationY(0);
-        v.setLeftTopRightBottom((int) taskViewRect.left, (int) taskViewRect.top,
-                (int) taskViewRect.right, (int) taskViewRect.bottom);
-    }
-
-    /**
-     * Returns a view stub for the given view id.
-     */
-    public static ViewStub findViewStubById(View v, int stubId) {
-        return (ViewStub) v.findViewById(stubId);
-    }
-
-    /**
-     * Returns a view stub for the given view id.
-     */
-    public static ViewStub findViewStubById(Activity a, int stubId) {
-        return (ViewStub) a.findViewById(stubId);
-    }
-
-    /**
-     * Updates {@param transforms} to be the same size as {@param tasks}.
-     */
-    public static void matchTaskListSize(List<Task> tasks, List<TaskViewTransform> transforms) {
-        // We can reuse the task transforms where possible to reduce object allocation
-        int taskTransformCount = transforms.size();
-        int taskCount = tasks.size();
-        if (taskTransformCount < taskCount) {
-            // If there are less transforms than tasks, then add as many transforms as necessary
-            for (int i = taskTransformCount; i < taskCount; i++) {
-                transforms.add(new TaskViewTransform());
-            }
-        } else if (taskTransformCount > taskCount) {
-            // If there are more transforms than tasks, then just subset the transform list
-            transforms.subList(taskCount, taskTransformCount).clear();
-        }
-    }
-
-    /**
-     * Used for debugging, converts DP to PX.
-     */
-    public static float dpToPx(Resources res, float dp) {
-        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, res.getDisplayMetrics());
-    }
-
-    /**
-     * Adds a trace event for debugging.
-     */
-    public static void addTraceEvent(String event) {
-        Trace.traceBegin(Trace.TRACE_TAG_VIEW, event);
-        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
-    }
-
-    /**
-     * Returns whether this view, or one of its descendants have accessibility focus.
-     */
-    public static boolean isDescendentAccessibilityFocused(View v) {
-        if (v.isAccessibilityFocused()) {
-            return true;
-        }
-
-        if (v instanceof ViewGroup) {
-            ViewGroup vg = (ViewGroup) v;
-            int childCount = vg.getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                if (isDescendentAccessibilityFocused(vg.getChildAt(i))) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Returns the application configuration, which is independent of the activity's current
-     * configuration in multiwindow.
-     */
-    public static Configuration getAppConfiguration(Context context) {
-        return context.getApplicationContext().getResources().getConfiguration();
-    }
-
-    /**
-     * Returns a lightweight dump of a rect.
-     */
-    public static String dumpRect(Rect r) {
-        if (r == null) {
-            return "N:0,0-0,0";
-        }
-        return r.left + "," + r.top + "-" + r.right + "," + r.bottom;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java
deleted file mode 100644
index 6414ea1..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.recents.model;
-
-import static android.os.Process.setThreadPriority;
-
-import android.os.Handler;
-import android.os.Looper;
-import android.os.SystemClock;
-import android.util.ArraySet;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.Task.TaskCallbacks;
-
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-
-/**
- * Loader class that loads full-resolution thumbnails when appropriate.
- */
-public class HighResThumbnailLoader implements TaskCallbacks {
-
-    @GuardedBy("mLoadQueue")
-    private final ArrayDeque<Task> mLoadQueue = new ArrayDeque<>();
-    @GuardedBy("mLoadQueue")
-    private final ArraySet<Task> mLoadingTasks = new ArraySet<>();
-    @GuardedBy("mLoadQueue")
-    private boolean mLoaderIdling;
-
-    private final ArrayList<Task> mVisibleTasks = new ArrayList<>();
-    private final Thread mLoadThread;
-    private final Handler mMainThreadHandler;
-    private final SystemServicesProxy mSystemServicesProxy;
-    private final boolean mIsLowRamDevice;
-    private boolean mLoading;
-    private boolean mVisible;
-    private boolean mFlingingFast;
-    private boolean mTaskLoadQueueIdle;
-
-    public HighResThumbnailLoader(SystemServicesProxy ssp, Looper looper, boolean isLowRamDevice) {
-        mMainThreadHandler = new Handler(looper);
-        mLoadThread = new Thread(mLoader, "Recents-HighResThumbnailLoader");
-        mLoadThread.start();
-        mSystemServicesProxy = ssp;
-        mIsLowRamDevice = isLowRamDevice;
-    }
-
-    public void setVisible(boolean visible) {
-        if (mIsLowRamDevice) {
-            return;
-        }
-        mVisible = visible;
-        updateLoading();
-    }
-
-    public void setFlingingFast(boolean flingingFast) {
-        if (mFlingingFast == flingingFast || mIsLowRamDevice) {
-            return;
-        }
-        mFlingingFast = flingingFast;
-        updateLoading();
-    }
-
-    /**
-     * Sets whether the other task load queue is idling. Avoid double-loading bitmaps by not
-     * starting this queue until the other queue is idling.
-     */
-    public void setTaskLoadQueueIdle(boolean idle) {
-        if (mIsLowRamDevice) {
-            return;
-        }
-        mTaskLoadQueueIdle = idle;
-        updateLoading();
-    }
-
-    @VisibleForTesting
-    boolean isLoading() {
-        return mLoading;
-    }
-
-    private void updateLoading() {
-        setLoading(mVisible && !mFlingingFast && mTaskLoadQueueIdle);
-    }
-
-    private void setLoading(boolean loading) {
-        if (loading == mLoading) {
-            return;
-        }
-        synchronized (mLoadQueue) {
-            mLoading = loading;
-            if (!loading) {
-                stopLoading();
-            } else {
-                startLoading();
-            }
-        }
-    }
-
-    @GuardedBy("mLoadQueue")
-    private void startLoading() {
-        for (int i = mVisibleTasks.size() - 1; i >= 0; i--) {
-            Task t = mVisibleTasks.get(i);
-            if ((t.thumbnail == null || t.thumbnail.reducedResolution)
-                    && !mLoadQueue.contains(t) && !mLoadingTasks.contains(t)) {
-                mLoadQueue.add(t);
-            }
-        }
-        mLoadQueue.notifyAll();
-    }
-
-    @GuardedBy("mLoadQueue")
-    private void stopLoading() {
-        mLoadQueue.clear();
-        mLoadQueue.notifyAll();
-    }
-
-    /**
-     * Needs to be called when a task becomes visible. Note that this is different from
-     * {@link TaskCallbacks#onTaskDataLoaded} as this method should only be called once when it
-     * becomes visible, whereas onTaskDataLoaded can be called multiple times whenever some data
-     * has been updated.
-     */
-    public void onTaskVisible(Task t) {
-        t.addCallback(this);
-        mVisibleTasks.add(t);
-        if ((t.thumbnail == null || t.thumbnail.reducedResolution) && mLoading) {
-            synchronized (mLoadQueue) {
-                mLoadQueue.add(t);
-                mLoadQueue.notifyAll();
-            }
-        }
-    }
-
-    /**
-     * Needs to be called when a task becomes visible. See {@link #onTaskVisible} why this is
-     * different from {@link TaskCallbacks#onTaskDataUnloaded()}
-     */
-    public void onTaskInvisible(Task t) {
-        t.removeCallback(this);
-        mVisibleTasks.remove(t);
-        synchronized (mLoadQueue) {
-            mLoadQueue.remove(t);
-        }
-    }
-
-    @VisibleForTesting
-    void waitForLoaderIdle() {
-        while (true) {
-            synchronized (mLoadQueue) {
-                if (mLoadQueue.isEmpty() && mLoaderIdling) {
-                    return;
-                }
-            }
-            SystemClock.sleep(100);
-        }
-    }
-
-    @Override
-    public void onTaskDataLoaded(Task task, ThumbnailData thumbnailData) {
-        if (thumbnailData != null && !thumbnailData.reducedResolution) {
-            synchronized (mLoadQueue) {
-                mLoadQueue.remove(task);
-            }
-        }
-    }
-
-    @Override
-    public void onTaskDataUnloaded() {
-    }
-
-    @Override
-    public void onTaskWindowingModeChanged() {
-    }
-
-    private final Runnable mLoader = new Runnable() {
-
-        @Override
-        public void run() {
-            setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND + 1);
-            while (true) {
-                Task next = null;
-                synchronized (mLoadQueue) {
-                    if (!mLoading || mLoadQueue.isEmpty()) {
-                        try {
-                            mLoaderIdling = true;
-                            mLoadQueue.wait();
-                            mLoaderIdling = false;
-                        } catch (InterruptedException e) {
-                            // Don't care.
-                        }
-                    } else {
-                        next = mLoadQueue.poll();
-                        if (next != null) {
-                            mLoadingTasks.add(next);
-                        }
-                    }
-                }
-                if (next != null) {
-                    loadTask(next);
-                }
-            }
-        }
-
-        private void loadTask(Task t) {
-            ThumbnailData thumbnail = mSystemServicesProxy.getTaskThumbnail(t.key.id,
-                    false /* reducedResolution */);
-            mMainThreadHandler.post(() -> {
-                synchronized (mLoadQueue) {
-                    mLoadingTasks.remove(t);
-                }
-                if (mVisibleTasks.contains(t)) {
-                    t.notifyTaskDataLoaded(thumbnail, t.icon);
-                }
-            });
-        }
-    };
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
deleted file mode 100644
index 308cece..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.model;
-
-import android.content.Context;
-import android.os.UserHandle;
-
-import com.android.internal.content.PackageMonitor;
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.PackagesChangedEvent;
-import com.android.systemui.recents.misc.ForegroundThread;
-
-/**
- * The package monitor listens for changes from PackageManager to update the contents of the
- * Recents list.
- */
-public class RecentsPackageMonitor extends PackageMonitor {
-
-    /** Registers the broadcast receivers with the specified callbacks. */
-    public void register(Context context) {
-        try {
-            // We register for events from all users, but will cross-reference them with
-            // packages for the current user and any profiles they have.  Ensure that events are
-            // handled in a background thread.
-            register(context, ForegroundThread.get().getLooper(), UserHandle.ALL, true);
-        } catch (IllegalStateException e) {
-            e.printStackTrace();
-        }
-    }
-
-    /** Unregisters the broadcast receivers. */
-    @Override
-    public void unregister() {
-        try {
-            super.unregister();
-        } catch (IllegalStateException e) {
-            e.printStackTrace();
-        }
-    }
-
-    @Override
-    public void onPackageRemoved(String packageName, int uid) {
-        // Notify callbacks on the main thread that a package has changed
-        final int eventUserId = getChangingUserId();
-        EventBus.getDefault().post(new PackagesChangedEvent(this, packageName, eventUserId));
-    }
-
-    @Override
-    public boolean onPackageChanged(String packageName, int uid, String[] components) {
-        onPackageModified(packageName);
-        return true;
-    }
-
-    @Override
-    public void onPackageModified(String packageName) {
-        // Notify callbacks on the main thread that a package has changed
-        final int eventUserId = getChangingUserId();
-        EventBus.getDefault().post(new PackagesChangedEvent(this, packageName, eventUserId));
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
deleted file mode 100644
index d5e0313..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.model;
-
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.provider.Settings.Secure;
-import android.util.ArraySet;
-import android.util.SparseArray;
-import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
-
-import com.android.systemui.Prefs;
-import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsDebugFlags;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.views.lowram.TaskStackLowRamLayoutAlgorithm;
-import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-
-/**
- * This class stores the loading state as it goes through multiple stages of loading:
- *   1) preloadRawTasks() will load the raw set of recents tasks from the system
- *   2) preloadPlan() will construct a new task stack with all metadata and only icons and
- *      thumbnails that are currently in the cache
- *   3) executePlan() will actually load and fill in the icons and thumbnails according to the load
- *      options specified, such that we can transition into the Recents activity seamlessly
- */
-public class RecentsTaskLoadPlan {
-
-    private static int MIN_NUM_TASKS = 5;
-    private static int SESSION_BEGIN_TIME = 1000 /* ms/s */ * 60 /* s/min */ * 60 /* min/hr */ *
-            6 /* hrs */;
-
-    /** The set of conditions to load tasks. */
-    public static class Options {
-        public int runningTaskId = -1;
-        public boolean loadIcons = true;
-        public boolean loadThumbnails = false;
-        public boolean onlyLoadForCache = false;
-        public boolean onlyLoadPausedActivities = false;
-        public int numVisibleTasks = 0;
-        public int numVisibleTaskThumbnails = 0;
-    }
-
-    Context mContext;
-
-    int mPreloadedUserId;
-    List<ActivityManager.RecentTaskInfo> mRawTasks;
-    TaskStack mStack;
-    ArraySet<Integer> mCurrentQuietProfiles = new ArraySet<Integer>();
-
-    /** Package level ctor */
-    RecentsTaskLoadPlan(Context context) {
-        mContext = context;
-    }
-
-    private void updateCurrentQuietProfilesCache(int currentUserId) {
-        mCurrentQuietProfiles.clear();
-
-        UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        List<UserInfo> profiles = userManager.getProfiles(currentUserId);
-        if (profiles != null) {
-            for (int i = 0; i < profiles.size(); i++) {
-                UserInfo user  = profiles.get(i);
-                if (user.isManagedProfile() && user.isQuietModeEnabled()) {
-                    mCurrentQuietProfiles.add(user.id);
-                }
-            }
-        }
-    }
-
-    /**
-     * An optimization to preload the raw list of tasks. The raw tasks are saved in least-recent
-     * to most-recent order.
-     *
-     * Note: Do not lock, callers should synchronize on the loader before making this call.
-     */
-    void preloadRawTasks(boolean includeFrontMostExcludedTask) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        int currentUserId = ssp.getCurrentUser();
-        updateCurrentQuietProfilesCache(currentUserId);
-        mPreloadedUserId = currentUserId;
-        mRawTasks = ssp.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(),
-                currentUserId, includeFrontMostExcludedTask, mCurrentQuietProfiles);
-
-        // Since the raw tasks are given in most-recent to least-recent order, we need to reverse it
-        Collections.reverse(mRawTasks);
-    }
-
-    /**
-     * Preloads the list of recent tasks from the system. After this call, the TaskStack will
-     * have a list of all the recent tasks with their metadata, not including icons or
-     * thumbnails which were not cached and have to be loaded.
-     *
-     * The tasks will be ordered by:
-     * - least-recent to most-recent stack tasks
-     * - least-recent to most-recent freeform tasks
-     *
-     * Note: Do not lock, since this can be calling back to the loader, which separately also drives
-     * this call (callers should synchronize on the loader before making this call).
-     */
-    void preloadPlan(RecentsTaskLoader loader, int runningTaskId,
-            boolean includeFrontMostExcludedTask) {
-        Resources res = mContext.getResources();
-        ArrayList<Task> allTasks = new ArrayList<>();
-        if (mRawTasks == null) {
-            preloadRawTasks(includeFrontMostExcludedTask);
-        }
-
-        SparseArray<Task.TaskKey> affiliatedTasks = new SparseArray<>();
-        SparseIntArray affiliatedTaskCounts = new SparseIntArray();
-        SparseBooleanArray lockedUsers = new SparseBooleanArray();
-        String dismissDescFormat = mContext.getString(
-                R.string.accessibility_recents_item_will_be_dismissed);
-        String appInfoDescFormat = mContext.getString(
-                R.string.accessibility_recents_item_open_app_info);
-        int currentUserId = mPreloadedUserId;
-        long legacyLastStackActiveTime = migrateLegacyLastStackActiveTime(currentUserId);
-        long lastStackActiveTime = Settings.Secure.getLongForUser(mContext.getContentResolver(),
-                Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, legacyLastStackActiveTime, currentUserId);
-        if (RecentsDebugFlags.Static.EnableMockTasks) {
-            lastStackActiveTime = 0;
-        }
-        long newLastStackActiveTime = -1;
-        int taskCount = mRawTasks.size();
-        for (int i = 0; i < taskCount; i++) {
-            ActivityManager.RecentTaskInfo t = mRawTasks.get(i);
-
-            // Compose the task key
-            final int windowingMode = t.configuration.windowConfiguration.getWindowingMode();
-            Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, windowingMode, t.baseIntent,
-                    t.userId, t.firstActiveTime, t.lastActiveTime);
-
-            // This task is only shown in the stack if it satisfies the historical time or min
-            // number of tasks constraints. Freeform tasks are also always shown.
-            boolean isFreeformTask = windowingMode == WINDOWING_MODE_FREEFORM;
-            boolean isStackTask;
-            if (Recents.getConfiguration().isGridEnabled) {
-                // When grid layout is enabled, we only show the first
-                // TaskGridLayoutAlgorithm.MAX_LAYOUT_FROM_HOME_TASK_COUNT} tasks.
-                isStackTask = t.lastActiveTime >= lastStackActiveTime &&
-                    i >= taskCount - TaskGridLayoutAlgorithm.MAX_LAYOUT_TASK_COUNT;
-            } else if (Recents.getConfiguration().isLowRamDevice) {
-                // Show a max of 3 items
-                isStackTask = t.lastActiveTime >= lastStackActiveTime &&
-                        i >= taskCount - TaskStackLowRamLayoutAlgorithm.MAX_LAYOUT_TASK_COUNT;
-            } else {
-                isStackTask = isFreeformTask || !isHistoricalTask(t) ||
-                    (t.lastActiveTime >= lastStackActiveTime && i >= (taskCount - MIN_NUM_TASKS));
-            }
-            boolean isLaunchTarget = taskKey.id == runningTaskId;
-
-            // The last stack active time is the baseline for which we show visible tasks.  Since
-            // the system will store all the tasks, we don't want to show the tasks prior to the
-            // last visible ones, otherwise, as you dismiss them, the previous tasks may satisfy
-            // the other stack-task constraints.
-            if (isStackTask && newLastStackActiveTime < 0) {
-                newLastStackActiveTime = t.lastActiveTime;
-            }
-
-            // Load the title, icon, and color
-            ActivityInfo info = loader.getAndUpdateActivityInfo(taskKey);
-            String title = loader.getAndUpdateActivityTitle(taskKey, t.taskDescription);
-            String titleDescription = loader.getAndUpdateContentDescription(taskKey,
-                    t.taskDescription, res);
-            String dismissDescription = String.format(dismissDescFormat, titleDescription);
-            String appInfoDescription = String.format(appInfoDescFormat, titleDescription);
-            Drawable icon = isStackTask
-                    ? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, res, false)
-                    : null;
-            ThumbnailData thumbnail = loader.getAndUpdateThumbnail(taskKey,
-                    false /* loadIfNotCached */, false /* storeInCache */);
-            int activityColor = loader.getActivityPrimaryColor(t.taskDescription);
-            int backgroundColor = loader.getActivityBackgroundColor(t.taskDescription);
-            boolean isSystemApp = (info != null) &&
-                    ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
-            if (lockedUsers.indexOfKey(t.userId) < 0) {
-                lockedUsers.put(t.userId, Recents.getSystemServices().isDeviceLocked(t.userId));
-            }
-            boolean isLocked = lockedUsers.get(t.userId);
-
-            // Add the task to the stack
-            Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, icon,
-                    thumbnail, title, titleDescription, dismissDescription, appInfoDescription,
-                    activityColor, backgroundColor, isLaunchTarget, isStackTask, isSystemApp,
-                    t.supportsSplitScreenMultiWindow, t.bounds, t.taskDescription, t.resizeMode, t.topActivity,
-                    isLocked);
-
-            allTasks.add(task);
-            affiliatedTaskCounts.put(taskKey.id, affiliatedTaskCounts.get(taskKey.id, 0) + 1);
-            affiliatedTasks.put(taskKey.id, taskKey);
-        }
-        if (newLastStackActiveTime != -1) {
-            Recents.getSystemServices().updateOverviewLastStackActiveTimeAsync(
-                    newLastStackActiveTime, currentUserId);
-        }
-
-        // Initialize the stacks
-        mStack = new TaskStack();
-        mStack.setTasks(mContext, allTasks, false /* notifyStackChanges */);
-    }
-
-    /**
-     * Called to apply the actual loading based on the specified conditions.
-     *
-     * Note: Do not lock, since this can be calling back to the loader, which separately also drives
-     * this call (callers should synchronize on the loader before making this call).
-     */
-    void executePlan(Options opts, RecentsTaskLoader loader) {
-        Resources res = mContext.getResources();
-
-        // Iterate through each of the tasks and load them according to the load conditions.
-        ArrayList<Task> tasks = mStack.getStackTasks();
-        int taskCount = tasks.size();
-        for (int i = 0; i < taskCount; i++) {
-            Task task = tasks.get(i);
-            Task.TaskKey taskKey = task.key;
-
-            boolean isRunningTask = (task.key.id == opts.runningTaskId);
-            boolean isVisibleTask = i >= (taskCount - opts.numVisibleTasks);
-            boolean isVisibleThumbnail = i >= (taskCount - opts.numVisibleTaskThumbnails);
-
-            // If requested, skip the running task
-            if (opts.onlyLoadPausedActivities && isRunningTask) {
-                continue;
-            }
-
-            if (opts.loadIcons && (isRunningTask || isVisibleTask)) {
-                if (task.icon == null) {
-                    task.icon = loader.getAndUpdateActivityIcon(taskKey, task.taskDescription, res,
-                            true);
-                }
-            }
-            if (opts.loadThumbnails && isVisibleThumbnail) {
-                task.thumbnail = loader.getAndUpdateThumbnail(taskKey,
-                        true /* loadIfNotCached */, true /* storeInCache */);
-            }
-        }
-    }
-
-    /**
-     * Returns the TaskStack from the preloaded list of recent tasks.
-     */
-    public TaskStack getTaskStack() {
-        return mStack;
-    }
-
-    /**
-     * Returns the raw list of recent tasks.
-     */
-    public List<ActivityManager.RecentTaskInfo> getRawTasks() {
-        return mRawTasks;
-    }
-
-    /** Returns whether there are any tasks in any stacks. */
-    public boolean hasTasks() {
-        if (mStack != null) {
-            return mStack.getTaskCount() > 0;
-        }
-        return false;
-    }
-
-    /**
-     * Returns whether this task is too old to be shown.
-     */
-    private boolean isHistoricalTask(ActivityManager.RecentTaskInfo t) {
-        return t.lastActiveTime < (System.currentTimeMillis() - SESSION_BEGIN_TIME);
-    }
-
-
-    /**
-     * Migrate the last active time from the prefs to the secure settings.
-     *
-     * The first time this runs, it will:
-     * 1) fetch the last stack active time from the prefs
-     * 2) set the prefs to the last stack active time for all users
-     * 3) clear the pref
-     * 4) return the last stack active time
-     *
-     * Subsequent calls to this will return zero.
-     */
-    private long migrateLegacyLastStackActiveTime(int currentUserId) {
-        long legacyLastStackActiveTime = Prefs.getLong(mContext,
-                Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, -1);
-        if (legacyLastStackActiveTime != -1) {
-            Prefs.remove(mContext, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME);
-            UserManager userMgr = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-            List<UserInfo> users = userMgr.getUsers();
-            for (int i = 0; i < users.size(); i++) {
-                int userId = users.get(i).id;
-                if (userId != currentUserId) {
-                    Recents.getSystemServices().updateOverviewLastStackActiveTimeAsync(
-                            legacyLastStackActiveTime, userId);
-                }
-            }
-            return legacyLastStackActiveTime;
-        }
-        return 0;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
deleted file mode 100644
index 1b89386..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ /dev/null
@@ -1,663 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.model;
-
-import android.app.ActivityManager;
-import android.content.ComponentCallbacks2;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.ActivityInfo;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Trace;
-import android.util.Log;
-import android.util.LruCache;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.RecentsDebugFlags;
-import com.android.systemui.recents.events.activity.PackagesChangedEvent;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-
-import java.io.PrintWriter;
-import java.util.Map;
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-
-/**
- * A Task load queue
- */
-class TaskResourceLoadQueue {
-
-    ConcurrentLinkedQueue<Task> mQueue = new ConcurrentLinkedQueue<Task>();
-
-    /** Adds a new task to the load queue */
-    void addTask(Task t) {
-        if (!mQueue.contains(t)) {
-            mQueue.add(t);
-        }
-        synchronized(this) {
-            notifyAll();
-        }
-    }
-
-    /**
-     * Retrieves the next task from the load queue, as well as whether we want that task to be
-     * force reloaded.
-     */
-    Task nextTask() {
-        return mQueue.poll();
-    }
-
-    /** Removes a task from the load queue */
-    void removeTask(Task t) {
-        mQueue.remove(t);
-    }
-
-    /** Clears all the tasks from the load queue */
-    void clearTasks() {
-        mQueue.clear();
-    }
-
-    /** Returns whether the load queue is empty */
-    boolean isEmpty() {
-        return mQueue.isEmpty();
-    }
-}
-
-/**
- * Task resource loader
- */
-class BackgroundTaskLoader implements Runnable {
-    static String TAG = "TaskResourceLoader";
-    static boolean DEBUG = false;
-
-    Context mContext;
-    HandlerThread mLoadThread;
-    Handler mLoadThreadHandler;
-    Handler mMainThreadHandler;
-
-    TaskResourceLoadQueue mLoadQueue;
-    TaskKeyLruCache<Drawable> mIconCache;
-    BitmapDrawable mDefaultIcon;
-
-    boolean mStarted;
-    boolean mCancelled;
-    boolean mWaitingOnLoadQueue;
-
-    private final OnIdleChangedListener mOnIdleChangedListener;
-
-    /** Constructor, creates a new loading thread that loads task resources in the background */
-    public BackgroundTaskLoader(TaskResourceLoadQueue loadQueue,
-            TaskKeyLruCache<Drawable> iconCache, BitmapDrawable defaultIcon,
-            OnIdleChangedListener onIdleChangedListener) {
-        mLoadQueue = loadQueue;
-        mIconCache = iconCache;
-        mDefaultIcon = defaultIcon;
-        mMainThreadHandler = new Handler();
-        mOnIdleChangedListener = onIdleChangedListener;
-        mLoadThread = new HandlerThread("Recents-TaskResourceLoader",
-                android.os.Process.THREAD_PRIORITY_BACKGROUND);
-        mLoadThread.start();
-        mLoadThreadHandler = new Handler(mLoadThread.getLooper());
-    }
-
-    /** Restarts the loader thread */
-    void start(Context context) {
-        mContext = context;
-        mCancelled = false;
-        if (!mStarted) {
-            // Start loading on the load thread
-            mStarted = true;
-            mLoadThreadHandler.post(this);
-        } else {
-            // Notify the load thread to start loading again
-            synchronized (mLoadThread) {
-                mLoadThread.notifyAll();
-            }
-        }
-    }
-
-    /** Requests the loader thread to stop after the current iteration */
-    void stop() {
-        // Mark as cancelled for the thread to pick up
-        mCancelled = true;
-        // If we are waiting for the load queue for more tasks, then we can just reset the
-        // Context now, since nothing is using it
-        if (mWaitingOnLoadQueue) {
-            mContext = null;
-        }
-    }
-
-    @Override
-    public void run() {
-        while (true) {
-            if (mCancelled) {
-                // We have to unset the context here, since the background thread may be using it
-                // when we call stop()
-                mContext = null;
-                // If we are cancelled, then wait until we are started again
-                synchronized(mLoadThread) {
-                    try {
-                        mLoadThread.wait();
-                    } catch (InterruptedException ie) {
-                        ie.printStackTrace();
-                    }
-                }
-            } else {
-                SystemServicesProxy ssp = Recents.getSystemServices();
-                // If we've stopped the loader, then fall through to the above logic to wait on
-                // the load thread
-                if (ssp != null) {
-                    processLoadQueueItem(ssp);
-                }
-
-                // If there are no other items in the list, then just wait until something is added
-                if (!mCancelled && mLoadQueue.isEmpty()) {
-                    synchronized(mLoadQueue) {
-                        try {
-                            mWaitingOnLoadQueue = true;
-                            mMainThreadHandler.post(
-                                    () -> mOnIdleChangedListener.onIdleChanged(true));
-                            mLoadQueue.wait();
-                            mMainThreadHandler.post(
-                                    () -> mOnIdleChangedListener.onIdleChanged(false));
-                            mWaitingOnLoadQueue = false;
-                        } catch (InterruptedException ie) {
-                            ie.printStackTrace();
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * This needs to be in a separate method to work around an surprising interpreter behavior:
-     * The register will keep the local reference to cachedThumbnailData even if it falls out of
-     * scope. Putting it into a method fixes this issue.
-     */
-    private void processLoadQueueItem(SystemServicesProxy ssp) {
-        // Load the next item from the queue
-        final Task t = mLoadQueue.nextTask();
-        if (t != null) {
-            Drawable cachedIcon = mIconCache.get(t.key);
-
-            // Load the icon if it is stale or we haven't cached one yet
-            if (cachedIcon == null) {
-                cachedIcon = ssp.getBadgedTaskDescriptionIcon(t.taskDescription,
-                        t.key.userId, mContext.getResources());
-
-                if (cachedIcon == null) {
-                    ActivityInfo info = ssp.getActivityInfo(
-                            t.key.getComponent(), t.key.userId);
-                    if (info != null) {
-                        if (DEBUG) Log.d(TAG, "Loading icon: " + t.key);
-                        cachedIcon = ssp.getBadgedActivityIcon(info, t.key.userId);
-                    }
-                }
-
-                if (cachedIcon == null) {
-                    cachedIcon = mDefaultIcon;
-                }
-
-                // At this point, even if we can't load the icon, we will set the
-                // default icon.
-                mIconCache.put(t.key, cachedIcon);
-            }
-
-            if (DEBUG) Log.d(TAG, "Loading thumbnail: " + t.key);
-            final ThumbnailData thumbnailData = ssp.getTaskThumbnail(t.key.id,
-                    true /* reducedResolution */);
-
-            if (!mCancelled) {
-                // Notify that the task data has changed
-                final Drawable finalIcon = cachedIcon;
-                mMainThreadHandler.post(
-                        () -> t.notifyTaskDataLoaded(thumbnailData, finalIcon));
-            }
-        }
-    }
-
-    interface OnIdleChangedListener {
-        void onIdleChanged(boolean idle);
-    }
-}
-
-/**
- * Recents task loader
- */
-public class RecentsTaskLoader {
-
-    private static final String TAG = "RecentsTaskLoader";
-    private static final boolean DEBUG = false;
-
-    // This activity info LruCache is useful because it can be expensive to retrieve ActivityInfos
-    // for many tasks, which we use to get the activity labels and icons.  Unlike the other caches
-    // below, this is per-package so we can't invalidate the items in the cache based on the last
-    // active time.  Instead, we rely on the RecentsPackageMonitor to keep us informed whenever a
-    // package in the cache has been updated, so that we may remove it.
-    private final LruCache<ComponentName, ActivityInfo> mActivityInfoCache;
-    private final TaskKeyLruCache<Drawable> mIconCache;
-    private final TaskKeyLruCache<String> mActivityLabelCache;
-    private final TaskKeyLruCache<String> mContentDescriptionCache;
-    private final TaskResourceLoadQueue mLoadQueue;
-    private final BackgroundTaskLoader mLoader;
-    private final HighResThumbnailLoader mHighResThumbnailLoader;
-    @GuardedBy("this")
-    private final TaskKeyStrongCache<ThumbnailData> mThumbnailCache = new TaskKeyStrongCache<>();
-    @GuardedBy("this")
-    private final TaskKeyStrongCache<ThumbnailData> mTempCache = new TaskKeyStrongCache<>();
-    private final int mMaxThumbnailCacheSize;
-    private final int mMaxIconCacheSize;
-    private int mNumVisibleTasksLoaded;
-
-    int mDefaultTaskBarBackgroundColor;
-    int mDefaultTaskViewBackgroundColor;
-    BitmapDrawable mDefaultIcon;
-
-    private TaskKeyLruCache.EvictionCallback mClearActivityInfoOnEviction =
-            new TaskKeyLruCache.EvictionCallback() {
-        @Override
-        public void onEntryEvicted(Task.TaskKey key) {
-            if (key != null) {
-                mActivityInfoCache.remove(key.getComponent());
-            }
-        }
-    };
-
-    public RecentsTaskLoader(Context context) {
-        Resources res = context.getResources();
-        mDefaultTaskBarBackgroundColor =
-                context.getColor(R.color.recents_task_bar_default_background_color);
-        mDefaultTaskViewBackgroundColor =
-                context.getColor(R.color.recents_task_view_default_background_color);
-        mMaxThumbnailCacheSize = res.getInteger(R.integer.config_recents_max_thumbnail_count);
-        mMaxIconCacheSize = res.getInteger(R.integer.config_recents_max_icon_count);
-        int iconCacheSize = RecentsDebugFlags.Static.DisableBackgroundCache ? 1 :
-                mMaxIconCacheSize;
-
-        // Create the default assets
-        Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
-        icon.eraseColor(0);
-        mDefaultIcon = new BitmapDrawable(context.getResources(), icon);
-
-        // Initialize the proxy, cache and loaders
-        int numRecentTasks = ActivityManager.getMaxRecentTasksStatic();
-        mHighResThumbnailLoader = new HighResThumbnailLoader(Recents.getSystemServices(),
-                Looper.getMainLooper(), Recents.getConfiguration().isLowRamDevice);
-        mLoadQueue = new TaskResourceLoadQueue();
-        mIconCache = new TaskKeyLruCache<>(iconCacheSize, mClearActivityInfoOnEviction);
-        mActivityLabelCache = new TaskKeyLruCache<>(numRecentTasks, mClearActivityInfoOnEviction);
-        mContentDescriptionCache = new TaskKeyLruCache<>(numRecentTasks,
-                mClearActivityInfoOnEviction);
-        mActivityInfoCache = new LruCache(numRecentTasks);
-        mLoader = new BackgroundTaskLoader(mLoadQueue, mIconCache, mDefaultIcon,
-                mHighResThumbnailLoader::setTaskLoadQueueIdle);
-    }
-
-    /** Returns the size of the app icon cache. */
-    public int getIconCacheSize() {
-        return mMaxIconCacheSize;
-    }
-
-    /** Returns the size of the thumbnail cache. */
-    public int getThumbnailCacheSize() {
-        return mMaxThumbnailCacheSize;
-    }
-
-    public HighResThumbnailLoader getHighResThumbnailLoader() {
-        return mHighResThumbnailLoader;
-    }
-
-    /** Creates a new plan for loading the recent tasks. */
-    public RecentsTaskLoadPlan createLoadPlan(Context context) {
-        RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(context);
-        return plan;
-    }
-
-    /** Preloads raw recents tasks using the specified plan to store the output. */
-    public synchronized void preloadRawTasks(RecentsTaskLoadPlan plan,
-            boolean includeFrontMostExcludedTask) {
-        plan.preloadRawTasks(includeFrontMostExcludedTask);
-    }
-
-    /** Preloads recents tasks using the specified plan to store the output. */
-    public synchronized void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId,
-            boolean includeFrontMostExcludedTask) {
-        try {
-            Trace.beginSection("preloadPlan");
-            plan.preloadPlan(this, runningTaskId, includeFrontMostExcludedTask);
-        } finally {
-            Trace.endSection();
-        }
-    }
-
-    /** Begins loading the heavy task data according to the specified options. */
-    public synchronized void loadTasks(Context context, RecentsTaskLoadPlan plan,
-            RecentsTaskLoadPlan.Options opts) {
-        if (opts == null) {
-            throw new RuntimeException("Requires load options");
-        }
-        if (opts.onlyLoadForCache && opts.loadThumbnails) {
-
-            // If we are loading for the cache, we'd like to have the real cache only include the
-            // visible thumbnails. However, we also don't want to reload already cached thumbnails.
-            // Thus, we copy over the current entries into a second cache, and clear the real cache,
-            // such that the real cache only contains visible thumbnails.
-            mTempCache.copyEntries(mThumbnailCache);
-            mThumbnailCache.evictAll();
-        }
-        plan.executePlan(opts, this);
-        mTempCache.evictAll();
-        if (!opts.onlyLoadForCache) {
-            mNumVisibleTasksLoaded = opts.numVisibleTasks;
-        }
-    }
-
-    /**
-     * Acquires the task resource data directly from the cache, loading if necessary.
-     */
-    public void loadTaskData(Task t) {
-        Drawable icon = mIconCache.getAndInvalidateIfModified(t.key);
-        icon = icon != null ? icon : mDefaultIcon;
-        mLoadQueue.addTask(t);
-        t.notifyTaskDataLoaded(t.thumbnail, icon);
-    }
-
-    /** Releases the task resource data back into the pool. */
-    public void unloadTaskData(Task t) {
-        mLoadQueue.removeTask(t);
-        t.notifyTaskDataUnloaded(mDefaultIcon);
-    }
-
-    /** Completely removes the resource data from the pool. */
-    public void deleteTaskData(Task t, boolean notifyTaskDataUnloaded) {
-        mLoadQueue.removeTask(t);
-        mIconCache.remove(t.key);
-        mActivityLabelCache.remove(t.key);
-        mContentDescriptionCache.remove(t.key);
-        if (notifyTaskDataUnloaded) {
-            t.notifyTaskDataUnloaded(mDefaultIcon);
-        }
-    }
-
-    /**
-     * Handles signals from the system, trimming memory when requested to prevent us from running
-     * out of memory.
-     */
-    public synchronized void onTrimMemory(int level) {
-        switch (level) {
-            case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
-                // Stop the loader immediately when the UI is no longer visible
-                stopLoader();
-                mIconCache.trimToSize(Math.max(mNumVisibleTasksLoaded,
-                        mMaxIconCacheSize / 2));
-                break;
-            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
-            case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
-                // We are leaving recents, so trim the data a bit
-                mIconCache.trimToSize(Math.max(1, mMaxIconCacheSize / 2));
-                mActivityInfoCache.trimToSize(Math.max(1,
-                        ActivityManager.getMaxRecentTasksStatic() / 2));
-                break;
-            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
-            case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
-                // We are going to be low on memory
-                mIconCache.trimToSize(Math.max(1, mMaxIconCacheSize / 4));
-                mActivityInfoCache.trimToSize(Math.max(1,
-                        ActivityManager.getMaxRecentTasksStatic() / 4));
-                break;
-            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
-            case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
-                // We are low on memory, so release everything
-                mIconCache.evictAll();
-                mActivityInfoCache.evictAll();
-                // The cache is small, only clear the label cache when we are critical
-                mActivityLabelCache.evictAll();
-                mContentDescriptionCache.evictAll();
-                mThumbnailCache.evictAll();
-                break;
-            default:
-                break;
-        }
-    }
-
-    /**
-     * Returns the cached task label if the task key is not expired, updating the cache if it is.
-     */
-    String getAndUpdateActivityTitle(Task.TaskKey taskKey, ActivityManager.TaskDescription td) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
-
-        // Return the task description label if it exists
-        if (td != null && td.getLabel() != null) {
-            return td.getLabel();
-        }
-        // Return the cached activity label if it exists
-        String label = mActivityLabelCache.getAndInvalidateIfModified(taskKey);
-        if (label != null) {
-            return label;
-        }
-        // All short paths failed, load the label from the activity info and cache it
-        ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey);
-        if (activityInfo != null) {
-            label = ssp.getBadgedActivityLabel(activityInfo, taskKey.userId);
-            mActivityLabelCache.put(taskKey, label);
-            return label;
-        }
-        // If the activity info does not exist or fails to load, return an empty label for now,
-        // but do not cache it
-        return "";
-    }
-
-    /**
-     * Returns the cached task content description if the task key is not expired, updating the
-     * cache if it is.
-     */
-    String getAndUpdateContentDescription(Task.TaskKey taskKey, ActivityManager.TaskDescription td,
-            Resources res) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
-
-        // Return the cached content description if it exists
-        String label = mContentDescriptionCache.getAndInvalidateIfModified(taskKey);
-        if (label != null) {
-            return label;
-        }
-
-        // All short paths failed, load the label from the activity info and cache it
-        ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey);
-        if (activityInfo != null) {
-            label = ssp.getBadgedContentDescription(activityInfo, taskKey.userId, td, res);
-            if (td == null) {
-                // Only add to the cache if the task description is null, otherwise, it is possible
-                // for the task description to change between calls without the last active time
-                // changing (ie. between preloading and Overview starting) which would lead to stale
-                // content descriptions
-                // TODO: Investigate improving this
-                mContentDescriptionCache.put(taskKey, label);
-            }
-            return label;
-        }
-        // If the content description does not exist, return an empty label for now, but do not
-        // cache it
-        return "";
-    }
-
-    /**
-     * Returns the cached task icon if the task key is not expired, updating the cache if it is.
-     */
-    Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey, ActivityManager.TaskDescription td,
-            Resources res, boolean loadIfNotCached) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
-
-        // Return the cached activity icon if it exists
-        Drawable icon = mIconCache.getAndInvalidateIfModified(taskKey);
-        if (icon != null) {
-            return icon;
-        }
-
-        if (loadIfNotCached) {
-            // Return and cache the task description icon if it exists
-            icon = ssp.getBadgedTaskDescriptionIcon(td, taskKey.userId, res);
-            if (icon != null) {
-                mIconCache.put(taskKey, icon);
-                return icon;
-            }
-
-            // Load the icon from the activity info and cache it
-            ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey);
-            if (activityInfo != null) {
-                icon = ssp.getBadgedActivityIcon(activityInfo, taskKey.userId);
-                if (icon != null) {
-                    mIconCache.put(taskKey, icon);
-                    return icon;
-                }
-            }
-        }
-        // We couldn't load any icon
-        return null;
-    }
-
-    /**
-     * Returns the cached thumbnail if the task key is not expired, updating the cache if it is.
-     */
-    synchronized ThumbnailData getAndUpdateThumbnail(Task.TaskKey taskKey, boolean loadIfNotCached,
-            boolean storeInCache) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
-
-        ThumbnailData cached = mThumbnailCache.getAndInvalidateIfModified(taskKey);
-        if (cached != null) {
-            return cached;
-        }
-
-        cached = mTempCache.getAndInvalidateIfModified(taskKey);
-        if (cached != null) {
-            mThumbnailCache.put(taskKey, cached);
-            return cached;
-        }
-
-        if (loadIfNotCached) {
-            RecentsConfiguration config = Recents.getConfiguration();
-            if (config.svelteLevel < RecentsConfiguration.SVELTE_DISABLE_LOADING) {
-                // Load the thumbnail from the system
-                ThumbnailData thumbnailData = ssp.getTaskThumbnail(taskKey.id,
-                        true /* reducedResolution */);
-                if (thumbnailData.thumbnail != null) {
-                    if (storeInCache) {
-                        mThumbnailCache.put(taskKey, thumbnailData);
-                    }
-                    return thumbnailData;
-                }
-            }
-        }
-
-        // We couldn't load any thumbnail
-        return null;
-    }
-
-    /**
-     * Returns the task's primary color if possible, defaulting to the default color if there is
-     * no specified primary color.
-     */
-    int getActivityPrimaryColor(ActivityManager.TaskDescription td) {
-        if (td != null && td.getPrimaryColor() != 0) {
-            return td.getPrimaryColor();
-        }
-        return mDefaultTaskBarBackgroundColor;
-    }
-
-    /**
-     * Returns the task's background color if possible.
-     */
-    int getActivityBackgroundColor(ActivityManager.TaskDescription td) {
-        if (td != null && td.getBackgroundColor() != 0) {
-            return td.getBackgroundColor();
-        }
-        return mDefaultTaskViewBackgroundColor;
-    }
-
-    /**
-     * Returns the activity info for the given task key, retrieving one from the system if the
-     * task key is expired.
-     */
-    ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        ComponentName cn = taskKey.getComponent();
-        ActivityInfo activityInfo = mActivityInfoCache.get(cn);
-        if (activityInfo == null) {
-            activityInfo = ssp.getActivityInfo(cn, taskKey.userId);
-            if (cn == null || activityInfo == null) {
-                Log.e(TAG, "Unexpected null component name or activity info: " + cn + ", " +
-                        activityInfo);
-                return null;
-            }
-            mActivityInfoCache.put(cn, activityInfo);
-        }
-        return activityInfo;
-    }
-
-    /**
-     * Starts loading tasks.
-     */
-    public void startLoader(Context ctx) {
-        mLoader.start(ctx);
-    }
-
-    /**
-     * Stops the task loader and clears all queued, pending task loads.
-     */
-    private void stopLoader() {
-        mLoader.stop();
-        mLoadQueue.clearTasks();
-    }
-
-    /**** Event Bus Events ****/
-
-    public final void onBusEvent(PackagesChangedEvent event) {
-        // Remove all the cached activity infos for this package.  The other caches do not need to
-        // be pruned at this time, as the TaskKey expiration checks will flush them next time their
-        // cached contents are requested
-        Map<ComponentName, ActivityInfo> activityInfoCache = mActivityInfoCache.snapshot();
-        for (ComponentName cn : activityInfoCache.keySet()) {
-            if (cn.getPackageName().equals(event.packageName)) {
-                if (DEBUG) {
-                    Log.d(TAG, "Removing activity info from cache: " + cn);
-                }
-                mActivityInfoCache.remove(cn);
-            }
-        }
-    }
-
-    public synchronized void dump(String prefix, PrintWriter writer) {
-        String innerPrefix = prefix + "  ";
-
-        writer.print(prefix); writer.println(TAG);
-        writer.print(prefix); writer.println("Icon Cache");
-        mIconCache.dump(innerPrefix, writer);
-        writer.print(prefix); writer.println("Thumbnail Cache");
-        mThumbnailCache.dump(innerPrefix, writer);
-        writer.print(prefix); writer.println("Temp Thumbnail Cache");
-        mTempCache.dump(innerPrefix, writer);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
deleted file mode 100644
index abdb5cb..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.model;
-
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-
-import android.app.ActivityManager;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.view.ViewDebug;
-
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Objects;
-
-/**
- * A task represents the top most task in the system's task stack.
- */
-public class Task {
-
-    public static final String TAG = "Task";
-
-    /* Task callbacks */
-    public interface TaskCallbacks {
-        /* Notifies when a task has been bound */
-        public void onTaskDataLoaded(Task task, ThumbnailData thumbnailData);
-        /* Notifies when a task has been unbound */
-        public void onTaskDataUnloaded();
-        /* Notifies when a task's windowing mode has changed. */
-        public void onTaskWindowingModeChanged();
-    }
-
-    /* The Task Key represents the unique primary key for the task */
-    public static class TaskKey {
-        @ViewDebug.ExportedProperty(category="recents")
-        public final int id;
-        @ViewDebug.ExportedProperty(category="recents")
-        public int windowingMode;
-        @ViewDebug.ExportedProperty(category="recents")
-        public final Intent baseIntent;
-        @ViewDebug.ExportedProperty(category="recents")
-        public final int userId;
-        @ViewDebug.ExportedProperty(category="recents")
-        public long firstActiveTime;
-        @ViewDebug.ExportedProperty(category="recents")
-        public long lastActiveTime;
-
-        private int mHashCode;
-
-        public TaskKey(int id, int windowingMode, Intent intent, int userId, long firstActiveTime,
-                long lastActiveTime) {
-            this.id = id;
-            this.windowingMode = windowingMode;
-            this.baseIntent = intent;
-            this.userId = userId;
-            this.firstActiveTime = firstActiveTime;
-            this.lastActiveTime = lastActiveTime;
-            updateHashCode();
-        }
-
-        public void setWindowingMode(int windowingMode) {
-            this.windowingMode = windowingMode;
-            updateHashCode();
-        }
-
-        public ComponentName getComponent() {
-            return this.baseIntent.getComponent();
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (!(o instanceof TaskKey)) {
-                return false;
-            }
-            TaskKey otherKey = (TaskKey) o;
-            return id == otherKey.id
-                    && windowingMode == otherKey.windowingMode
-                    && userId == otherKey.userId;
-        }
-
-        @Override
-        public int hashCode() {
-            return mHashCode;
-        }
-
-        @Override
-        public String toString() {
-            return "id=" + id + " windowingMode=" + windowingMode + " user=" + userId
-                    + " lastActiveTime=" + lastActiveTime;
-        }
-
-        private void updateHashCode() {
-            mHashCode = Objects.hash(id, windowingMode, userId);
-        }
-    }
-
-    @ViewDebug.ExportedProperty(deepExport=true, prefix="key_")
-    public TaskKey key;
-
-    /**
-     * The temporary sort index in the stack, used when ordering the stack.
-     */
-    public int temporarySortIndexInStack;
-
-    /**
-     * The group will be computed separately from the initialization of the task
-     */
-    @ViewDebug.ExportedProperty(deepExport=true, prefix="group_")
-    public TaskGrouping group;
-    /**
-     * The affiliationTaskId is the task id of the parent task or itself if it is not affiliated
-     * with any task.
-     */
-    @ViewDebug.ExportedProperty(category="recents")
-    public int affiliationTaskId;
-    @ViewDebug.ExportedProperty(category="recents")
-    public int affiliationColor;
-
-    /**
-     * The icon is the task description icon (if provided), which falls back to the activity icon,
-     * which can then fall back to the application icon.
-     */
-    public Drawable icon;
-    public ThumbnailData thumbnail;
-    @ViewDebug.ExportedProperty(category="recents")
-    public String title;
-    @ViewDebug.ExportedProperty(category="recents")
-    public String titleDescription;
-    @ViewDebug.ExportedProperty(category="recents")
-    public String dismissDescription;
-    @ViewDebug.ExportedProperty(category="recents")
-    public String appInfoDescription;
-    @ViewDebug.ExportedProperty(category="recents")
-    public int colorPrimary;
-    @ViewDebug.ExportedProperty(category="recents")
-    public int colorBackground;
-    @ViewDebug.ExportedProperty(category="recents")
-    public boolean useLightOnPrimaryColor;
-
-    /**
-     * The bounds of the task, used only if it is a freeform task.
-     */
-    @ViewDebug.ExportedProperty(category="recents")
-    public Rect bounds;
-
-    /**
-     * The task description for this task, only used to reload task icons.
-     */
-    public ActivityManager.TaskDescription taskDescription;
-
-    /**
-     * The state isLaunchTarget will be set for the correct task upon launching Recents.
-     */
-    @ViewDebug.ExportedProperty(category="recents")
-    public boolean isLaunchTarget;
-    @ViewDebug.ExportedProperty(category="recents")
-    public boolean isStackTask;
-    @ViewDebug.ExportedProperty(category="recents")
-    public boolean isSystemApp;
-    @ViewDebug.ExportedProperty(category="recents")
-    public boolean isDockable;
-
-    /**
-     * Resize mode. See {@link ActivityInfo#resizeMode}.
-     */
-    @ViewDebug.ExportedProperty(category="recents")
-    public int resizeMode;
-
-    @ViewDebug.ExportedProperty(category="recents")
-    public ComponentName topActivity;
-
-    @ViewDebug.ExportedProperty(category="recents")
-    public boolean isLocked;
-
-    private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>();
-
-    public Task() {
-        // Do nothing
-    }
-
-    public Task(TaskKey key, int affiliationTaskId, int affiliationColor, Drawable icon,
-            ThumbnailData thumbnail, String title, String titleDescription,
-            String dismissDescription, String appInfoDescription, int colorPrimary,
-            int colorBackground, boolean isLaunchTarget, boolean isStackTask, boolean isSystemApp,
-            boolean isDockable, Rect bounds, ActivityManager.TaskDescription taskDescription,
-            int resizeMode, ComponentName topActivity, boolean isLocked) {
-        boolean isInAffiliationGroup = (affiliationTaskId != key.id);
-        boolean hasAffiliationGroupColor = isInAffiliationGroup && (affiliationColor != 0);
-        this.key = key;
-        this.affiliationTaskId = affiliationTaskId;
-        this.affiliationColor = affiliationColor;
-        this.icon = icon;
-        this.thumbnail = thumbnail;
-        this.title = title;
-        this.titleDescription = titleDescription;
-        this.dismissDescription = dismissDescription;
-        this.appInfoDescription = appInfoDescription;
-        this.colorPrimary = hasAffiliationGroupColor ? affiliationColor : colorPrimary;
-        this.colorBackground = colorBackground;
-        this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(this.colorPrimary,
-                Color.WHITE) > 3f;
-        this.bounds = bounds;
-        this.taskDescription = taskDescription;
-        this.isLaunchTarget = isLaunchTarget;
-        this.isStackTask = isStackTask;
-        this.isSystemApp = isSystemApp;
-        this.isDockable = isDockable;
-        this.resizeMode = resizeMode;
-        this.topActivity = topActivity;
-        this.isLocked = isLocked;
-    }
-
-    /**
-     * Copies the metadata from another task, but retains the current callbacks.
-     */
-    public void copyFrom(Task o) {
-        this.key = o.key;
-        this.group = o.group;
-        this.affiliationTaskId = o.affiliationTaskId;
-        this.affiliationColor = o.affiliationColor;
-        this.icon = o.icon;
-        this.thumbnail = o.thumbnail;
-        this.title = o.title;
-        this.titleDescription = o.titleDescription;
-        this.dismissDescription = o.dismissDescription;
-        this.appInfoDescription = o.appInfoDescription;
-        this.colorPrimary = o.colorPrimary;
-        this.colorBackground = o.colorBackground;
-        this.useLightOnPrimaryColor = o.useLightOnPrimaryColor;
-        this.bounds = o.bounds;
-        this.taskDescription = o.taskDescription;
-        this.isLaunchTarget = o.isLaunchTarget;
-        this.isStackTask = o.isStackTask;
-        this.isSystemApp = o.isSystemApp;
-        this.isDockable = o.isDockable;
-        this.resizeMode = o.resizeMode;
-        this.isLocked = o.isLocked;
-        this.topActivity = o.topActivity;
-    }
-
-    /**
-     * Add a callback.
-     */
-    public void addCallback(TaskCallbacks cb) {
-        if (!mCallbacks.contains(cb)) {
-            mCallbacks.add(cb);
-        }
-    }
-
-    /**
-     * Remove a callback.
-     */
-    public void removeCallback(TaskCallbacks cb) {
-        mCallbacks.remove(cb);
-    }
-
-    /** Set the grouping */
-    public void setGroup(TaskGrouping group) {
-        this.group = group;
-    }
-
-    /** Updates the task's windowing mode. */
-    public void setWindowingMode(int windowingMode) {
-        key.setWindowingMode(windowingMode);
-        int callbackCount = mCallbacks.size();
-        for (int i = 0; i < callbackCount; i++) {
-            mCallbacks.get(i).onTaskWindowingModeChanged();
-        }
-    }
-
-    /**
-     * Returns whether this task is on the freeform task stack.
-     */
-    public boolean isFreeformTask() {
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        return ssp.hasFreeformWorkspaceSupport() && key.windowingMode == WINDOWING_MODE_FREEFORM;
-    }
-
-    /** Notifies the callback listeners that this task has been loaded */
-    public void notifyTaskDataLoaded(ThumbnailData thumbnailData, Drawable applicationIcon) {
-        this.icon = applicationIcon;
-        this.thumbnail = thumbnailData;
-        int callbackCount = mCallbacks.size();
-        for (int i = 0; i < callbackCount; i++) {
-            mCallbacks.get(i).onTaskDataLoaded(this, thumbnailData);
-        }
-    }
-
-    /** Notifies the callback listeners that this task has been unloaded */
-    public void notifyTaskDataUnloaded(Drawable defaultApplicationIcon) {
-        icon = defaultApplicationIcon;
-        thumbnail = null;
-        for (int i = mCallbacks.size() - 1; i >= 0; i--) {
-            mCallbacks.get(i).onTaskDataUnloaded();
-        }
-    }
-
-    /**
-     * Returns whether this task is affiliated with another task.
-     */
-    public boolean isAffiliatedTask() {
-        return key.id != affiliationTaskId;
-    }
-
-    /**
-     * Returns the top activity component.
-     */
-    public ComponentName getTopComponent() {
-        return topActivity != null
-                ? topActivity
-                : key.baseIntent.getComponent();
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        // Check that the id matches
-        Task t = (Task) o;
-        return key.equals(t.key);
-    }
-
-    @Override
-    public String toString() {
-        return "[" + key.toString() + "] " + title;
-    }
-
-    public void dump(String prefix, PrintWriter writer) {
-        writer.print(prefix); writer.print(key);
-        if (isAffiliatedTask()) {
-            writer.print(" "); writer.print("affTaskId=" + affiliationTaskId);
-        }
-        if (!isDockable) {
-            writer.print(" dockable=N");
-        }
-        if (isLaunchTarget) {
-            writer.print(" launchTarget=Y");
-        }
-        if (isFreeformTask()) {
-            writer.print(" freeform=Y");
-        }
-        if (isLocked) {
-            writer.print(" locked=Y");
-        }
-        writer.print(" "); writer.print(title);
-        writer.println();
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskGrouping.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskGrouping.java
deleted file mode 100644
index 2109376..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskGrouping.java
+++ /dev/null
@@ -1,106 +0,0 @@
-package com.android.systemui.recents.model;
-
-import android.util.ArrayMap;
-
-import java.util.ArrayList;
-
-/** Represents a grouping of tasks witihin a stack. */
-public class TaskGrouping {
-
-    int affiliation;
-    long latestActiveTimeInGroup;
-
-    Task.TaskKey mFrontMostTaskKey;
-    ArrayList<Task.TaskKey> mTaskKeys = new ArrayList<Task.TaskKey>();
-    ArrayMap<Task.TaskKey, Integer> mTaskKeyIndices = new ArrayMap<>();
-
-    /** Creates a group with a specified affiliation. */
-    public TaskGrouping(int affiliation) {
-        this.affiliation = affiliation;
-    }
-
-    /** Adds a new task to this group. */
-    void addTask(Task t) {
-        mTaskKeys.add(t.key);
-        if (t.key.lastActiveTime > latestActiveTimeInGroup) {
-            latestActiveTimeInGroup = t.key.lastActiveTime;
-        }
-        t.setGroup(this);
-        updateTaskIndices();
-    }
-
-    /** Removes a task from this group. */
-    void removeTask(Task t) {
-        mTaskKeys.remove(t.key);
-        latestActiveTimeInGroup = 0;
-        int taskCount = mTaskKeys.size();
-        for (int i = 0; i < taskCount; i++) {
-            long lastActiveTime = mTaskKeys.get(i).lastActiveTime;
-            if (lastActiveTime > latestActiveTimeInGroup) {
-                latestActiveTimeInGroup = lastActiveTime;
-            }
-        }
-        t.setGroup(null);
-        updateTaskIndices();
-    }
-
-    /** Returns the key of the next task in the group. */
-    public Task.TaskKey getNextTaskInGroup(Task t) {
-        int i = indexOf(t);
-        if ((i + 1) < getTaskCount()) {
-            return mTaskKeys.get(i + 1);
-        }
-        return null;
-    }
-
-    /** Returns the key of the previous task in the group. */
-    public Task.TaskKey getPrevTaskInGroup(Task t) {
-        int i = indexOf(t);
-        if ((i - 1) >= 0) {
-            return mTaskKeys.get(i - 1);
-        }
-        return null;
-    }
-
-    /** Gets the front task */
-    public boolean isFrontMostTask(Task t) {
-        return (t.key == mFrontMostTaskKey);
-    }
-
-    /** Finds the index of a given task in a group. */
-    public int indexOf(Task t) {
-        return mTaskKeyIndices.get(t.key);
-    }
-
-    /** Returns whether a task is in this grouping. */
-    public boolean containsTask(Task t) {
-        return mTaskKeyIndices.containsKey(t.key);
-    }
-
-    /** Returns whether one task is above another in the group.  If they are not in the same group,
-     * this returns false. */
-    public boolean isTaskAboveTask(Task t, Task below) {
-        return mTaskKeyIndices.containsKey(t.key) && mTaskKeyIndices.containsKey(below.key) &&
-                mTaskKeyIndices.get(t.key) > mTaskKeyIndices.get(below.key);
-    }
-
-    /** Returns the number of tasks in this group. */
-    public int getTaskCount() { return mTaskKeys.size(); }
-
-    /** Updates the mapping of tasks to indices. */
-    private void updateTaskIndices() {
-        if (mTaskKeys.isEmpty()) {
-            mFrontMostTaskKey = null;
-            mTaskKeyIndices.clear();
-            return;
-        }
-
-        int taskCount = mTaskKeys.size();
-        mFrontMostTaskKey = mTaskKeys.get(mTaskKeys.size() - 1);
-        mTaskKeyIndices.clear();
-        for (int i = 0; i < taskCount; i++) {
-            Task.TaskKey k = mTaskKeys.get(i);
-            mTaskKeyIndices.put(k, i);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyCache.java
deleted file mode 100644
index 247a654..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyCache.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.recents.model;
-
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.systemui.recents.model.Task.TaskKey;
-
-/**
- * Base class for both strong and LRU task key cache.
- */
-public abstract class TaskKeyCache<V> {
-
-    protected static final String TAG = "TaskKeyCache";
-
-    protected final SparseArray<TaskKey> mKeys = new SparseArray<>();
-
-    /**
-     * Gets a specific entry in the cache with the specified key, regardless of whether the cached
-     * value is valid or not.
-     */
-    final V get(Task.TaskKey key) {
-        return getCacheEntry(key.id);
-    }
-
-    /**
-     * Returns the value only if the key is valid (has not been updated since the last time it was
-     * in the cache)
-     */
-    final V getAndInvalidateIfModified(Task.TaskKey key) {
-        Task.TaskKey lastKey = mKeys.get(key.id);
-        if (lastKey != null) {
-            if ((lastKey.windowingMode != key.windowingMode) ||
-                    (lastKey.lastActiveTime != key.lastActiveTime)) {
-                // The task has updated (been made active since the last time it was put into the
-                // LRU cache) or the stack id for the task has changed, invalidate that cache item
-                remove(key);
-                return null;
-            }
-        }
-        // Either the task does not exist in the cache, or the last active time is the same as
-        // the key specified, so return what is in the cache
-        return getCacheEntry(key.id);
-    }
-
-    /** Puts an entry in the cache for a specific key. */
-    final void put(Task.TaskKey key, V value) {
-        if (key == null || value == null) {
-            Log.e(TAG, "Unexpected null key or value: " + key + ", " + value);
-            return;
-        }
-        mKeys.put(key.id, key);
-        putCacheEntry(key.id, value);
-    }
-
-
-    /** Removes a cache entry for a specific key. */
-    final void remove(Task.TaskKey key) {
-        // Remove the key after the cache value because we need it to make the callback
-        removeCacheEntry(key.id);
-        mKeys.remove(key.id);
-    }
-
-    /** Removes all the entries in the cache. */
-    final void evictAll() {
-        evictAllCache();
-        mKeys.clear();
-    }
-
-    protected abstract V getCacheEntry(int id);
-    protected abstract void putCacheEntry(int id, V value);
-    protected abstract void removeCacheEntry(int id);
-    protected abstract void evictAllCache();
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java
deleted file mode 100644
index 778df6b..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.model;
-
-import android.util.LruCache;
-
-import java.io.PrintWriter;
-
-/**
- * A mapping of {@link Task.TaskKey} to value, with additional LRU functionality where the least
- * recently referenced key/values will be evicted as more values than the given cache size are
- * inserted.
- *
- * In addition, this also allows the caller to invalidate cached values for keys that have since
- * changed.
- */
-public class TaskKeyLruCache<V> extends TaskKeyCache<V> {
-
-    public interface EvictionCallback {
-        public void onEntryEvicted(Task.TaskKey key);
-    }
-
-    private final LruCache<Integer, V> mCache;
-    private final EvictionCallback mEvictionCallback;
-
-    public TaskKeyLruCache(int cacheSize) {
-        this(cacheSize, null);
-    }
-
-    public TaskKeyLruCache(int cacheSize, EvictionCallback evictionCallback) {
-        mEvictionCallback = evictionCallback;
-        mCache = new LruCache<Integer, V>(cacheSize) {
-
-            @Override
-            protected void entryRemoved(boolean evicted, Integer taskId, V oldV, V newV) {
-                if (mEvictionCallback != null) {
-                    mEvictionCallback.onEntryEvicted(mKeys.get(taskId));
-                }
-                mKeys.remove(taskId);
-            }
-        };
-    }
-
-    /** Trims the cache to a specific size */
-    final void trimToSize(int cacheSize) {
-        mCache.trimToSize(cacheSize);
-    }
-
-    public void dump(String prefix, PrintWriter writer) {
-        String innerPrefix = prefix + "  ";
-
-        writer.print(prefix); writer.print(TAG);
-        writer.print(" numEntries="); writer.print(mKeys.size());
-        writer.println();
-        int keyCount = mKeys.size();
-        for (int i = 0; i < keyCount; i++) {
-            writer.print(innerPrefix); writer.println(mKeys.get(mKeys.keyAt(i)));
-        }
-    }
-
-    @Override
-    protected V getCacheEntry(int id) {
-        return mCache.get(id);
-    }
-
-    @Override
-    protected void putCacheEntry(int id, V value) {
-        mCache.put(id, value);
-    }
-
-    @Override
-    protected void removeCacheEntry(int id) {
-        mCache.remove(id);
-    }
-
-    @Override
-    protected void evictAllCache() {
-        mCache.evictAll();
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyStrongCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyStrongCache.java
deleted file mode 100644
index c84df8a..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyStrongCache.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.recents.model;
-
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.systemui.recents.model.Task.TaskKey;
-
-import java.io.PrintWriter;
-
-/**
- * Like {@link TaskKeyLruCache}, but without LRU functionality.
- */
-public class TaskKeyStrongCache<V> extends TaskKeyCache<V> {
-
-    private static final String TAG = "TaskKeyCache";
-
-    private final ArrayMap<Integer, V> mCache = new ArrayMap<>();
-
-    final void copyEntries(TaskKeyStrongCache<V> other) {
-        for (int i = other.mKeys.size() - 1; i >= 0; i--) {
-            TaskKey key = other.mKeys.valueAt(i);
-            put(key, other.mCache.get(key.id));
-        }
-    }
-
-    public void dump(String prefix, PrintWriter writer) {
-        String innerPrefix = prefix + "  ";
-        writer.print(prefix); writer.print(TAG);
-        writer.print(" numEntries="); writer.print(mKeys.size());
-        writer.println();
-        int keyCount = mKeys.size();
-        for (int i = 0; i < keyCount; i++) {
-            writer.print(innerPrefix); writer.println(mKeys.get(mKeys.keyAt(i)));
-        }
-    }
-
-    @Override
-    protected V getCacheEntry(int id) {
-        return mCache.get(id);
-    }
-
-    @Override
-    protected void putCacheEntry(int id, V value) {
-        mCache.put(id, value);
-    }
-
-    @Override
-    protected void removeCacheEntry(int id) {
-        mCache.remove(id);
-    }
-
-    @Override
-    protected void evictAllCache() {
-        mCache.clear();
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
deleted file mode 100644
index fdae917..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ /dev/null
@@ -1,1140 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.model;
-
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.view.WindowManager.DOCKED_BOTTOM;
-import static android.view.WindowManager.DOCKED_INVALID;
-import static android.view.WindowManager.DOCKED_LEFT;
-import static android.view.WindowManager.DOCKED_RIGHT;
-import static android.view.WindowManager.DOCKED_TOP;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.annotation.IntDef;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.ColorDrawable;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.IntProperty;
-import android.util.SparseArray;
-import android.view.animation.Interpolator;
-
-import com.android.internal.policy.DockedDividerUtils;
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsDebugFlags;
-import com.android.systemui.recents.misc.NamedCounter;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.views.AnimationProps;
-import com.android.systemui.recents.views.DropTarget;
-import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
-
-import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Random;
-
-
-/**
- * An interface for a task filter to query whether a particular task should show in a stack.
- */
-interface TaskFilter {
-    /** Returns whether the filter accepts the specified task */
-    public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index);
-}
-
-/**
- * A list of filtered tasks.
- */
-class FilteredTaskList {
-
-    ArrayList<Task> mTasks = new ArrayList<>();
-    ArrayList<Task> mFilteredTasks = new ArrayList<>();
-    ArrayMap<Task.TaskKey, Integer> mTaskIndices = new ArrayMap<>();
-    TaskFilter mFilter;
-
-    /** Sets the task filter, saving the current touch state */
-    boolean setFilter(TaskFilter filter) {
-        ArrayList<Task> prevFilteredTasks = new ArrayList<>(mFilteredTasks);
-        mFilter = filter;
-        updateFilteredTasks();
-        if (!prevFilteredTasks.equals(mFilteredTasks)) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    /** Removes the task filter and returns the previous touch state */
-    void removeFilter() {
-        mFilter = null;
-        updateFilteredTasks();
-    }
-
-    /** Adds a new task to the task list */
-    void add(Task t) {
-        mTasks.add(t);
-        updateFilteredTasks();
-    }
-
-    /**
-     * Moves the given task.
-     */
-    public void setTaskWindowingMode(Task task, int insertIndex, int windowingMode) {
-        int taskIndex = indexOf(task);
-        if (taskIndex != insertIndex) {
-            mTasks.remove(taskIndex);
-            if (taskIndex < insertIndex) {
-                insertIndex--;
-            }
-            mTasks.add(insertIndex, task);
-        }
-
-        // Update the stack id now, after we've moved the task, and before we update the
-        // filtered tasks
-        task.setWindowingMode(windowingMode);
-        updateFilteredTasks();
-    }
-
-    /** Sets the list of tasks */
-    void set(List<Task> tasks) {
-        mTasks.clear();
-        mTasks.addAll(tasks);
-        updateFilteredTasks();
-    }
-
-    /** Removes a task from the base list only if it is in the filtered list */
-    boolean remove(Task t) {
-        if (mFilteredTasks.contains(t)) {
-            boolean removed = mTasks.remove(t);
-            updateFilteredTasks();
-            return removed;
-        }
-        return false;
-    }
-
-    /** Returns the index of this task in the list of filtered tasks */
-    int indexOf(Task t) {
-        if (t != null && mTaskIndices.containsKey(t.key)) {
-            return mTaskIndices.get(t.key);
-        }
-        return -1;
-    }
-
-    /** Returns the size of the list of filtered tasks */
-    int size() {
-        return mFilteredTasks.size();
-    }
-
-    /** Returns whether the filtered list contains this task */
-    boolean contains(Task t) {
-        return mTaskIndices.containsKey(t.key);
-    }
-
-    /** Updates the list of filtered tasks whenever the base task list changes */
-    private void updateFilteredTasks() {
-        mFilteredTasks.clear();
-        if (mFilter != null) {
-            // Create a sparse array from task id to Task
-            SparseArray<Task> taskIdMap = new SparseArray<>();
-            int taskCount = mTasks.size();
-            for (int i = 0; i < taskCount; i++) {
-                Task t = mTasks.get(i);
-                taskIdMap.put(t.key.id, t);
-            }
-
-            for (int i = 0; i < taskCount; i++) {
-                Task t = mTasks.get(i);
-                if (mFilter.acceptTask(taskIdMap, t, i)) {
-                    mFilteredTasks.add(t);
-                }
-            }
-        } else {
-            mFilteredTasks.addAll(mTasks);
-        }
-        updateFilteredTaskIndices();
-    }
-
-    /** Updates the mapping of tasks to indices. */
-    private void updateFilteredTaskIndices() {
-        int taskCount = mFilteredTasks.size();
-        mTaskIndices.clear();
-        for (int i = 0; i < taskCount; i++) {
-            Task t = mFilteredTasks.get(i);
-            mTaskIndices.put(t.key, i);
-        }
-    }
-
-    /** Returns whether this task list is filtered */
-    boolean hasFilter() {
-        return (mFilter != null);
-    }
-
-    /** Returns the list of filtered tasks */
-    ArrayList<Task> getTasks() {
-        return mFilteredTasks;
-    }
-}
-
-/**
- * The task stack contains a list of multiple tasks.
- */
-public class TaskStack {
-
-    private static final String TAG = "TaskStack";
-
-    /** Task stack callbacks */
-    public interface TaskStackCallbacks {
-        /**
-         * Notifies when a new task has been added to the stack.
-         */
-        void onStackTaskAdded(TaskStack stack, Task newTask);
-
-        /**
-         * Notifies when a task has been removed from the stack.
-         */
-        void onStackTaskRemoved(TaskStack stack, Task removedTask, Task newFrontMostTask,
-                AnimationProps animation, boolean fromDockGesture,
-                boolean dismissRecentsIfAllRemoved);
-
-        /**
-         * Notifies when all tasks have been removed from the stack.
-         */
-        void onStackTasksRemoved(TaskStack stack);
-
-        /**
-         * Notifies when tasks in the stack have been updated.
-         */
-        void onStackTasksUpdated(TaskStack stack);
-    }
-
-    /**
-     * The various possible dock states when dragging and dropping a task.
-     */
-    public static class DockState implements DropTarget {
-
-        public static final int DOCK_AREA_BG_COLOR = 0xFFffffff;
-        public static final int DOCK_AREA_GRID_BG_COLOR = 0xFF000000;
-
-        // The rotation to apply to the hint text
-        @Retention(RetentionPolicy.SOURCE)
-        @IntDef({HORIZONTAL, VERTICAL})
-        public @interface TextOrientation {}
-        private static final int HORIZONTAL = 0;
-        private static final int VERTICAL = 1;
-
-        private static final int DOCK_AREA_ALPHA = 80;
-        public static final DockState NONE = new DockState(DOCKED_INVALID, -1, 80, 255, HORIZONTAL,
-                null, null, null);
-        public static final DockState LEFT = new DockState(DOCKED_LEFT,
-                DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA, 0, VERTICAL,
-                new RectF(0, 0, 0.125f, 1), new RectF(0, 0, 0.125f, 1),
-                new RectF(0, 0, 0.5f, 1));
-        public static final DockState TOP = new DockState(DOCKED_TOP,
-                DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA, 0, HORIZONTAL,
-                new RectF(0, 0, 1, 0.125f), new RectF(0, 0, 1, 0.125f),
-                new RectF(0, 0, 1, 0.5f));
-        public static final DockState RIGHT = new DockState(DOCKED_RIGHT,
-                DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA, 0, VERTICAL,
-                new RectF(0.875f, 0, 1, 1), new RectF(0.875f, 0, 1, 1),
-                new RectF(0.5f, 0, 1, 1));
-        public static final DockState BOTTOM = new DockState(DOCKED_BOTTOM,
-                DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA, 0, HORIZONTAL,
-                new RectF(0, 0.875f, 1, 1), new RectF(0, 0.875f, 1, 1),
-                new RectF(0, 0.5f, 1, 1));
-
-        @Override
-        public boolean acceptsDrop(int x, int y, int width, int height, Rect insets,
-                boolean isCurrentTarget) {
-            if (isCurrentTarget) {
-                getMappedRect(expandedTouchDockArea, width, height, mTmpRect);
-                return mTmpRect.contains(x, y);
-            } else {
-                getMappedRect(touchArea, width, height, mTmpRect);
-                updateBoundsWithSystemInsets(mTmpRect, insets);
-                return mTmpRect.contains(x, y);
-            }
-        }
-
-        // Represents the view state of this dock state
-        public static class ViewState {
-            private static final IntProperty<ViewState> HINT_ALPHA =
-                    new IntProperty<ViewState>("drawableAlpha") {
-                        @Override
-                        public void setValue(ViewState object, int alpha) {
-                            object.mHintTextAlpha = alpha;
-                            object.dockAreaOverlay.invalidateSelf();
-                        }
-
-                        @Override
-                        public Integer get(ViewState object) {
-                            return object.mHintTextAlpha;
-                        }
-                    };
-
-            public final int dockAreaAlpha;
-            public final ColorDrawable dockAreaOverlay;
-            public final int hintTextAlpha;
-            public final int hintTextOrientation;
-
-            private final int mHintTextResId;
-            private String mHintText;
-            private Paint mHintTextPaint;
-            private Point mHintTextBounds = new Point();
-            private int mHintTextAlpha = 255;
-            private AnimatorSet mDockAreaOverlayAnimator;
-            private Rect mTmpRect = new Rect();
-
-            private ViewState(int areaAlpha, int hintAlpha, @TextOrientation int hintOrientation,
-                    int hintTextResId) {
-                dockAreaAlpha = areaAlpha;
-                dockAreaOverlay = new ColorDrawable(Recents.getConfiguration().isGridEnabled
-                        ? DOCK_AREA_GRID_BG_COLOR : DOCK_AREA_BG_COLOR);
-                dockAreaOverlay.setAlpha(0);
-                hintTextAlpha = hintAlpha;
-                hintTextOrientation = hintOrientation;
-                mHintTextResId = hintTextResId;
-                mHintTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-                mHintTextPaint.setColor(Color.WHITE);
-            }
-
-            /**
-             * Updates the view state with the given context.
-             */
-            public void update(Context context) {
-                Resources res = context.getResources();
-                mHintText = context.getString(mHintTextResId);
-                mHintTextPaint.setTextSize(res.getDimensionPixelSize(
-                        R.dimen.recents_drag_hint_text_size));
-                mHintTextPaint.getTextBounds(mHintText, 0, mHintText.length(), mTmpRect);
-                mHintTextBounds.set((int) mHintTextPaint.measureText(mHintText), mTmpRect.height());
-            }
-
-            /**
-             * Draws the current view state.
-             */
-            public void draw(Canvas canvas) {
-                // Draw the overlay background
-                if (dockAreaOverlay.getAlpha() > 0) {
-                    dockAreaOverlay.draw(canvas);
-                }
-
-                // Draw the hint text
-                if (mHintTextAlpha > 0) {
-                    Rect bounds = dockAreaOverlay.getBounds();
-                    int x = bounds.left + (bounds.width() - mHintTextBounds.x) / 2;
-                    int y = bounds.top + (bounds.height() + mHintTextBounds.y) / 2;
-                    mHintTextPaint.setAlpha(mHintTextAlpha);
-                    if (hintTextOrientation == VERTICAL) {
-                        canvas.save();
-                        canvas.rotate(-90f, bounds.centerX(), bounds.centerY());
-                    }
-                    canvas.drawText(mHintText, x, y, mHintTextPaint);
-                    if (hintTextOrientation == VERTICAL) {
-                        canvas.restore();
-                    }
-                }
-            }
-
-            /**
-             * Creates a new bounds and alpha animation.
-             */
-            public void startAnimation(Rect bounds, int areaAlpha, int hintAlpha, int duration,
-                    Interpolator interpolator, boolean animateAlpha, boolean animateBounds) {
-                if (mDockAreaOverlayAnimator != null) {
-                    mDockAreaOverlayAnimator.cancel();
-                }
-
-                ObjectAnimator anim;
-                ArrayList<Animator> animators = new ArrayList<>();
-                if (dockAreaOverlay.getAlpha() != areaAlpha) {
-                    if (animateAlpha) {
-                        anim = ObjectAnimator.ofInt(dockAreaOverlay,
-                                Utilities.DRAWABLE_ALPHA, dockAreaOverlay.getAlpha(), areaAlpha);
-                        anim.setDuration(duration);
-                        anim.setInterpolator(interpolator);
-                        animators.add(anim);
-                    } else {
-                        dockAreaOverlay.setAlpha(areaAlpha);
-                    }
-                }
-                if (mHintTextAlpha != hintAlpha) {
-                    if (animateAlpha) {
-                        anim = ObjectAnimator.ofInt(this, HINT_ALPHA, mHintTextAlpha,
-                                hintAlpha);
-                        anim.setDuration(150);
-                        anim.setInterpolator(hintAlpha > mHintTextAlpha
-                                ? Interpolators.ALPHA_IN
-                                : Interpolators.ALPHA_OUT);
-                        animators.add(anim);
-                    } else {
-                        mHintTextAlpha = hintAlpha;
-                        dockAreaOverlay.invalidateSelf();
-                    }
-                }
-                if (bounds != null && !dockAreaOverlay.getBounds().equals(bounds)) {
-                    if (animateBounds) {
-                        PropertyValuesHolder prop = PropertyValuesHolder.ofObject(
-                                Utilities.DRAWABLE_RECT, Utilities.RECT_EVALUATOR,
-                                new Rect(dockAreaOverlay.getBounds()), bounds);
-                        anim = ObjectAnimator.ofPropertyValuesHolder(dockAreaOverlay, prop);
-                        anim.setDuration(duration);
-                        anim.setInterpolator(interpolator);
-                        animators.add(anim);
-                    } else {
-                        dockAreaOverlay.setBounds(bounds);
-                    }
-                }
-                if (!animators.isEmpty()) {
-                    mDockAreaOverlayAnimator = new AnimatorSet();
-                    mDockAreaOverlayAnimator.playTogether(animators);
-                    mDockAreaOverlayAnimator.start();
-                }
-            }
-        }
-
-        public final int dockSide;
-        public final int createMode;
-        public final ViewState viewState;
-        private final RectF touchArea;
-        private final RectF dockArea;
-        private final RectF expandedTouchDockArea;
-        private static final Rect mTmpRect = new Rect();
-
-        /**
-         * @param createMode used to pass to ActivityManager to dock the task
-         * @param touchArea the area in which touch will initiate this dock state
-         * @param dockArea the visible dock area
-         * @param expandedTouchDockArea the area in which touch will continue to dock after entering
-         *                              the initial touch area.  This is also the new dock area to
-         *                              draw.
-         */
-        DockState(int dockSide, int createMode, int dockAreaAlpha, int hintTextAlpha,
-                  @TextOrientation int hintTextOrientation, RectF touchArea, RectF dockArea,
-                  RectF expandedTouchDockArea) {
-            this.dockSide = dockSide;
-            this.createMode = createMode;
-            this.viewState = new ViewState(dockAreaAlpha, hintTextAlpha, hintTextOrientation,
-                    R.string.recents_drag_hint_message);
-            this.dockArea = dockArea;
-            this.touchArea = touchArea;
-            this.expandedTouchDockArea = expandedTouchDockArea;
-        }
-
-        /**
-         * Updates the dock state with the given context.
-         */
-        public void update(Context context) {
-            viewState.update(context);
-        }
-
-        /**
-         * Returns the docked task bounds with the given {@param width} and {@param height}.
-         */
-        public Rect getPreDockedBounds(int width, int height, Rect insets) {
-            getMappedRect(dockArea, width, height, mTmpRect);
-            return updateBoundsWithSystemInsets(mTmpRect, insets);
-        }
-
-        /**
-         * Returns the expanded docked task bounds with the given {@param width} and
-         * {@param height}.
-         */
-        public Rect getDockedBounds(int width, int height, int dividerSize, Rect insets,
-                Resources res) {
-            // Calculate the docked task bounds
-            boolean isHorizontalDivision =
-                    res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
-            int position = DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision,
-                    insets, width, height, dividerSize);
-            Rect newWindowBounds = new Rect();
-            DockedDividerUtils.calculateBoundsForPosition(position, dockSide, newWindowBounds,
-                    width, height, dividerSize);
-            return newWindowBounds;
-        }
-
-        /**
-         * Returns the task stack bounds with the given {@param width} and
-         * {@param height}.
-         */
-        public Rect getDockedTaskStackBounds(Rect displayRect, int width, int height,
-                int dividerSize, Rect insets, TaskStackLayoutAlgorithm layoutAlgorithm,
-                Resources res, Rect windowRectOut) {
-            // Calculate the inverse docked task bounds
-            boolean isHorizontalDivision =
-                    res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
-            int position = DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision,
-                    insets, width, height, dividerSize);
-            DockedDividerUtils.calculateBoundsForPosition(position,
-                    DockedDividerUtils.invertDockSide(dockSide), windowRectOut, width, height,
-                    dividerSize);
-
-            // Calculate the task stack bounds from the new window bounds
-            Rect taskStackBounds = new Rect();
-            // If the task stack bounds is specifically under the dock area, then ignore the top
-            // inset
-            int top = dockArea.bottom < 1f
-                    ? 0
-                    : insets.top;
-            // For now, ignore the left insets since we always dock on the left and show Recents
-            // on the right
-            layoutAlgorithm.getTaskStackBounds(displayRect, windowRectOut, top, 0, insets.right,
-                    taskStackBounds);
-            return taskStackBounds;
-        }
-
-        /**
-         * Returns the expanded bounds in certain dock sides such that the bounds account for the
-         * system insets (namely the vertical nav bar).  This call modifies and returns the given
-         * {@param bounds}.
-         */
-        private Rect updateBoundsWithSystemInsets(Rect bounds, Rect insets) {
-            if (dockSide == DOCKED_LEFT) {
-                bounds.right += insets.left;
-            } else if (dockSide == DOCKED_RIGHT) {
-                bounds.left -= insets.right;
-            }
-            return bounds;
-        }
-
-        /**
-         * Returns the mapped rect to the given dimensions.
-         */
-        private void getMappedRect(RectF bounds, int width, int height, Rect out) {
-            out.set((int) (bounds.left * width), (int) (bounds.top * height),
-                    (int) (bounds.right * width), (int) (bounds.bottom * height));
-        }
-    }
-
-    // A comparator that sorts tasks by their freeform state
-    private Comparator<Task> FREEFORM_COMPARATOR = new Comparator<Task>() {
-        @Override
-        public int compare(Task o1, Task o2) {
-            if (o1.isFreeformTask() && !o2.isFreeformTask()) {
-                return 1;
-            } else if (o2.isFreeformTask() && !o1.isFreeformTask()) {
-                return -1;
-            }
-            return Long.compare(o1.temporarySortIndexInStack, o2.temporarySortIndexInStack);
-        }
-    };
-
-
-    // The task offset to apply to a task id as a group affiliation
-    static final int IndividualTaskIdOffset = 1 << 16;
-
-    ArrayList<Task> mRawTaskList = new ArrayList<>();
-    FilteredTaskList mStackTaskList = new FilteredTaskList();
-    TaskStackCallbacks mCb;
-
-    ArrayList<TaskGrouping> mGroups = new ArrayList<>();
-    ArrayMap<Integer, TaskGrouping> mAffinitiesGroups = new ArrayMap<>();
-
-    public TaskStack() {
-        // Ensure that we only show non-docked tasks
-        mStackTaskList.setFilter(new TaskFilter() {
-            @Override
-            public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index) {
-                if (RecentsDebugFlags.Static.EnableAffiliatedTaskGroups) {
-                    if (t.isAffiliatedTask()) {
-                        // If this task is affiliated with another parent in the stack, then the
-                        // historical state of this task depends on the state of the parent task
-                        Task parentTask = taskIdMap.get(t.affiliationTaskId);
-                        if (parentTask != null) {
-                            t = parentTask;
-                        }
-                    }
-                }
-                return t.isStackTask;
-            }
-        });
-    }
-
-    /** Sets the callbacks for this task stack. */
-    public void setCallbacks(TaskStackCallbacks cb) {
-        mCb = cb;
-    }
-
-    /** Sets the windowing mode for a given task. */
-    public void setTaskWindowingMode(Task task, int windowingMode) {
-        // Find the index to insert into
-        ArrayList<Task> taskList = mStackTaskList.getTasks();
-        int taskCount = taskList.size();
-        if (!task.isFreeformTask() && (windowingMode == WINDOWING_MODE_FREEFORM)) {
-            // Insert freeform tasks at the front
-            mStackTaskList.setTaskWindowingMode(task, taskCount, windowingMode);
-        } else if (task.isFreeformTask() && (windowingMode == WINDOWING_MODE_FULLSCREEN)) {
-            // Insert after the first stacked task
-            int insertIndex = 0;
-            for (int i = taskCount - 1; i >= 0; i--) {
-                if (!taskList.get(i).isFreeformTask()) {
-                    insertIndex = i + 1;
-                    break;
-                }
-            }
-            mStackTaskList.setTaskWindowingMode(task, insertIndex, windowingMode);
-        }
-    }
-
-    /** Does the actual work associated with removing the task. */
-    void removeTaskImpl(FilteredTaskList taskList, Task t) {
-        // Remove the task from the list
-        taskList.remove(t);
-        // Remove it from the group as well, and if it is empty, remove the group
-        TaskGrouping group = t.group;
-        if (group != null) {
-            group.removeTask(t);
-            if (group.getTaskCount() == 0) {
-                removeGroup(group);
-            }
-        }
-    }
-
-    /**
-     * Removes a task from the stack, with an additional {@param animation} hint to the callbacks on
-     * how they should update themselves.
-     */
-    public void removeTask(Task t, AnimationProps animation, boolean fromDockGesture) {
-        removeTask(t, animation, fromDockGesture, true /* dismissRecentsIfAllRemoved */);
-    }
-
-    /**
-     * Removes a task from the stack, with an additional {@param animation} hint to the callbacks on
-     * how they should update themselves.
-     */
-    public void removeTask(Task t, AnimationProps animation, boolean fromDockGesture,
-            boolean dismissRecentsIfAllRemoved) {
-        if (mStackTaskList.contains(t)) {
-            removeTaskImpl(mStackTaskList, t);
-            Task newFrontMostTask = getStackFrontMostTask(false  /* includeFreeform */);
-            if (mCb != null) {
-                // Notify that a task has been removed
-                mCb.onStackTaskRemoved(this, t, newFrontMostTask, animation,
-                        fromDockGesture, dismissRecentsIfAllRemoved);
-            }
-        }
-        mRawTaskList.remove(t);
-    }
-
-    /**
-     * Removes all tasks from the stack.
-     */
-    public void removeAllTasks(boolean notifyStackChanges) {
-        ArrayList<Task> tasks = mStackTaskList.getTasks();
-        for (int i = tasks.size() - 1; i >= 0; i--) {
-            Task t = tasks.get(i);
-            removeTaskImpl(mStackTaskList, t);
-            mRawTaskList.remove(t);
-        }
-        if (mCb != null && notifyStackChanges) {
-            // Notify that all tasks have been removed
-            mCb.onStackTasksRemoved(this);
-        }
-    }
-
-
-    /**
-     * @see #setTasks(Context, List, boolean, boolean)
-     */
-    public void setTasks(Context context, TaskStack stack, boolean notifyStackChanges) {
-        setTasks(context, stack.mRawTaskList, notifyStackChanges);
-    }
-
-    /**
-     * Sets a few tasks in one go, without calling any callbacks.
-     *
-     * @param tasks the new set of tasks to replace the current set.
-     * @param notifyStackChanges whether or not to callback on specific changes to the list of tasks.
-     */
-    public void setTasks(Context context, List<Task> tasks, boolean notifyStackChanges) {
-        // Compute a has set for each of the tasks
-        ArrayMap<Task.TaskKey, Task> currentTasksMap = createTaskKeyMapFromList(mRawTaskList);
-        ArrayMap<Task.TaskKey, Task> newTasksMap = createTaskKeyMapFromList(tasks);
-        ArrayList<Task> addedTasks = new ArrayList<>();
-        ArrayList<Task> removedTasks = new ArrayList<>();
-        ArrayList<Task> allTasks = new ArrayList<>();
-
-        // Disable notifications if there are no callbacks
-        if (mCb == null) {
-            notifyStackChanges = false;
-        }
-
-        // Remove any tasks that no longer exist
-        int taskCount = mRawTaskList.size();
-        for (int i = taskCount - 1; i >= 0; i--) {
-            Task task = mRawTaskList.get(i);
-            if (!newTasksMap.containsKey(task.key)) {
-                if (notifyStackChanges) {
-                    removedTasks.add(task);
-                }
-            }
-            task.setGroup(null);
-        }
-
-        // Add any new tasks
-        taskCount = tasks.size();
-        for (int i = 0; i < taskCount; i++) {
-            Task newTask = tasks.get(i);
-            Task currentTask = currentTasksMap.get(newTask.key);
-            if (currentTask == null && notifyStackChanges) {
-                addedTasks.add(newTask);
-            } else if (currentTask != null) {
-                // The current task has bound callbacks, so just copy the data from the new task
-                // state and add it back into the list
-                currentTask.copyFrom(newTask);
-                newTask = currentTask;
-            }
-            allTasks.add(newTask);
-        }
-
-        // Sort all the tasks to ensure they are ordered correctly
-        for (int i = allTasks.size() - 1; i >= 0; i--) {
-            allTasks.get(i).temporarySortIndexInStack = i;
-        }
-        Collections.sort(allTasks, FREEFORM_COMPARATOR);
-
-        mStackTaskList.set(allTasks);
-        mRawTaskList = allTasks;
-
-        // Update the affiliated groupings
-        createAffiliatedGroupings(context);
-
-        // Only callback for the removed tasks after the stack has updated
-        int removedTaskCount = removedTasks.size();
-        Task newFrontMostTask = getStackFrontMostTask(false);
-        for (int i = 0; i < removedTaskCount; i++) {
-            mCb.onStackTaskRemoved(this, removedTasks.get(i), newFrontMostTask,
-                    AnimationProps.IMMEDIATE, false /* fromDockGesture */,
-                    true /* dismissRecentsIfAllRemoved */);
-        }
-
-        // Only callback for the newly added tasks after this stack has been updated
-        int addedTaskCount = addedTasks.size();
-        for (int i = 0; i < addedTaskCount; i++) {
-            mCb.onStackTaskAdded(this, addedTasks.get(i));
-        }
-
-        // Notify that the task stack has been updated
-        if (notifyStackChanges) {
-            mCb.onStackTasksUpdated(this);
-        }
-    }
-
-    /**
-     * Gets the front-most task in the stack.
-     */
-    public Task getStackFrontMostTask(boolean includeFreeformTasks) {
-        ArrayList<Task> stackTasks = mStackTaskList.getTasks();
-        if (stackTasks.isEmpty()) {
-            return null;
-        }
-        for (int i = stackTasks.size() - 1; i >= 0; i--) {
-            Task task = stackTasks.get(i);
-            if (!task.isFreeformTask() || includeFreeformTasks) {
-                return task;
-            }
-        }
-        return null;
-    }
-
-    /** Gets the task keys */
-    public ArrayList<Task.TaskKey> getTaskKeys() {
-        ArrayList<Task.TaskKey> taskKeys = new ArrayList<>();
-        ArrayList<Task> tasks = computeAllTasksList();
-        int taskCount = tasks.size();
-        for (int i = 0; i < taskCount; i++) {
-            Task task = tasks.get(i);
-            taskKeys.add(task.key);
-        }
-        return taskKeys;
-    }
-
-    /**
-     * Returns the set of "active" (non-historical) tasks in the stack that have been used recently.
-     */
-    public ArrayList<Task> getStackTasks() {
-        return mStackTaskList.getTasks();
-    }
-
-    /**
-     * Returns the set of "freeform" tasks in the stack.
-     */
-    public ArrayList<Task> getFreeformTasks() {
-        ArrayList<Task> freeformTasks = new ArrayList<>();
-        ArrayList<Task> tasks = mStackTaskList.getTasks();
-        int taskCount = tasks.size();
-        for (int i = 0; i < taskCount; i++) {
-            Task task = tasks.get(i);
-            if (task.isFreeformTask()) {
-                freeformTasks.add(task);
-            }
-        }
-        return freeformTasks;
-    }
-
-    /**
-     * Computes a set of all the active and historical tasks.
-     */
-    public ArrayList<Task> computeAllTasksList() {
-        ArrayList<Task> tasks = new ArrayList<>();
-        tasks.addAll(mStackTaskList.getTasks());
-        return tasks;
-    }
-
-    /**
-     * Returns the number of stack and freeform tasks.
-     */
-    public int getTaskCount() {
-        return mStackTaskList.size();
-    }
-
-    /**
-     * Returns the number of stack tasks.
-     */
-    public int getStackTaskCount() {
-        ArrayList<Task> tasks = mStackTaskList.getTasks();
-        int stackCount = 0;
-        int taskCount = tasks.size();
-        for (int i = 0; i < taskCount; i++) {
-            Task task = tasks.get(i);
-            if (!task.isFreeformTask()) {
-                stackCount++;
-            }
-        }
-        return stackCount;
-    }
-
-    /**
-     * Returns the number of freeform tasks.
-     */
-    public int getFreeformTaskCount() {
-        ArrayList<Task> tasks = mStackTaskList.getTasks();
-        int freeformCount = 0;
-        int taskCount = tasks.size();
-        for (int i = 0; i < taskCount; i++) {
-            Task task = tasks.get(i);
-            if (task.isFreeformTask()) {
-                freeformCount++;
-            }
-        }
-        return freeformCount;
-    }
-
-    /**
-     * Returns the task in stack tasks which is the launch target.
-     */
-    public Task getLaunchTarget() {
-        ArrayList<Task> tasks = mStackTaskList.getTasks();
-        int taskCount = tasks.size();
-        for (int i = 0; i < taskCount; i++) {
-            Task task = tasks.get(i);
-            if (task.isLaunchTarget) {
-                return task;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Returns whether the next launch target should actually be the PiP task.
-     */
-    public boolean isNextLaunchTargetPip(long lastPipTime) {
-        Task launchTarget = getLaunchTarget();
-        Task nextLaunchTarget = getNextLaunchTargetRaw();
-        if (nextLaunchTarget != null && lastPipTime > 0) {
-            // If the PiP time is more recent than the next launch target, then launch the PiP task
-            return lastPipTime > nextLaunchTarget.key.lastActiveTime;
-        } else if (launchTarget != null && lastPipTime > 0 && getTaskCount() == 1) {
-            // Otherwise, if there is no next launch target, but there is a PiP, then launch
-            // the PiP task
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Returns the task in stack tasks which should be launched next if Recents are toggled
-     * again, or null if there is no task to be launched. Callers should check
-     * {@link #isNextLaunchTargetPip(long)} before fetching the next raw launch target from the
-     * stack.
-     */
-    public Task getNextLaunchTarget() {
-        Task nextLaunchTarget = getNextLaunchTargetRaw();
-        if (nextLaunchTarget != null) {
-            return nextLaunchTarget;
-        }
-        return getStackTasks().get(getTaskCount() - 1);
-    }
-
-    private Task getNextLaunchTargetRaw() {
-        int taskCount = getTaskCount();
-        if (taskCount == 0) {
-            return null;
-        }
-        int launchTaskIndex = indexOfStackTask(getLaunchTarget());
-        if (launchTaskIndex != -1 && launchTaskIndex > 0) {
-            return getStackTasks().get(launchTaskIndex - 1);
-        }
-        return null;
-    }
-
-    /** Returns the index of this task in this current task stack */
-    public int indexOfStackTask(Task t) {
-        return mStackTaskList.indexOf(t);
-    }
-
-    /** Finds the task with the specified task id. */
-    public Task findTaskWithId(int taskId) {
-        ArrayList<Task> tasks = computeAllTasksList();
-        int taskCount = tasks.size();
-        for (int i = 0; i < taskCount; i++) {
-            Task task = tasks.get(i);
-            if (task.key.id == taskId) {
-                return task;
-            }
-        }
-        return null;
-    }
-
-    /******** Grouping ********/
-
-    /** Adds a group to the set */
-    public void addGroup(TaskGrouping group) {
-        mGroups.add(group);
-        mAffinitiesGroups.put(group.affiliation, group);
-    }
-
-    public void removeGroup(TaskGrouping group) {
-        mGroups.remove(group);
-        mAffinitiesGroups.remove(group.affiliation);
-    }
-
-    /** Returns the group with the specified affiliation. */
-    public TaskGrouping getGroupWithAffiliation(int affiliation) {
-        return mAffinitiesGroups.get(affiliation);
-    }
-
-    /**
-     * Temporary: This method will simulate affiliation groups
-     */
-    void createAffiliatedGroupings(Context context) {
-        mGroups.clear();
-        mAffinitiesGroups.clear();
-
-        if (RecentsDebugFlags.Static.EnableMockTaskGroups) {
-            ArrayMap<Task.TaskKey, Task> taskMap = new ArrayMap<>();
-            // Sort all tasks by increasing firstActiveTime of the task
-            ArrayList<Task> tasks = mStackTaskList.getTasks();
-            Collections.sort(tasks, new Comparator<Task>() {
-                @Override
-                public int compare(Task task, Task task2) {
-                    return Long.compare(task.key.firstActiveTime, task2.key.firstActiveTime);
-                }
-            });
-            // Create groups when sequential packages are the same
-            NamedCounter counter = new NamedCounter("task-group", "");
-            int taskCount = tasks.size();
-            String prevPackage = "";
-            int prevAffiliation = -1;
-            Random r = new Random();
-            int groupCountDown = RecentsDebugFlags.Static.MockTaskGroupsTaskCount;
-            for (int i = 0; i < taskCount; i++) {
-                Task t = tasks.get(i);
-                String packageName = t.key.getComponent().getPackageName();
-                packageName = "pkg";
-                TaskGrouping group;
-                if (packageName.equals(prevPackage) && groupCountDown > 0) {
-                    group = getGroupWithAffiliation(prevAffiliation);
-                    groupCountDown--;
-                } else {
-                    int affiliation = IndividualTaskIdOffset + t.key.id;
-                    group = new TaskGrouping(affiliation);
-                    addGroup(group);
-                    prevAffiliation = affiliation;
-                    prevPackage = packageName;
-                    groupCountDown = RecentsDebugFlags.Static.MockTaskGroupsTaskCount;
-                }
-                group.addTask(t);
-                taskMap.put(t.key, t);
-            }
-            // Sort groups by increasing latestActiveTime of the group
-            Collections.sort(mGroups, new Comparator<TaskGrouping>() {
-                @Override
-                public int compare(TaskGrouping taskGrouping, TaskGrouping taskGrouping2) {
-                    return Long.compare(taskGrouping.latestActiveTimeInGroup,
-                            taskGrouping2.latestActiveTimeInGroup);
-                }
-            });
-            // Sort group tasks by increasing firstActiveTime of the task, and also build a new list
-            // of tasks
-            int taskIndex = 0;
-            int groupCount = mGroups.size();
-            for (int i = 0; i < groupCount; i++) {
-                TaskGrouping group = mGroups.get(i);
-                Collections.sort(group.mTaskKeys, new Comparator<Task.TaskKey>() {
-                    @Override
-                    public int compare(Task.TaskKey taskKey, Task.TaskKey taskKey2) {
-                        return Long.compare(taskKey.firstActiveTime, taskKey2.firstActiveTime);
-                    }
-                });
-                ArrayList<Task.TaskKey> groupTasks = group.mTaskKeys;
-                int groupTaskCount = groupTasks.size();
-                for (int j = 0; j < groupTaskCount; j++) {
-                    tasks.set(taskIndex, taskMap.get(groupTasks.get(j)));
-                    taskIndex++;
-                }
-            }
-            mStackTaskList.set(tasks);
-        } else {
-            // Create the task groups
-            ArrayMap<Task.TaskKey, Task> tasksMap = new ArrayMap<>();
-            ArrayList<Task> tasks = mStackTaskList.getTasks();
-            int taskCount = tasks.size();
-            for (int i = 0; i < taskCount; i++) {
-                Task t = tasks.get(i);
-                TaskGrouping group;
-                if (RecentsDebugFlags.Static.EnableAffiliatedTaskGroups) {
-                    int affiliation = t.affiliationTaskId > 0 ? t.affiliationTaskId :
-                            IndividualTaskIdOffset + t.key.id;
-                    if (mAffinitiesGroups.containsKey(affiliation)) {
-                        group = getGroupWithAffiliation(affiliation);
-                    } else {
-                        group = new TaskGrouping(affiliation);
-                        addGroup(group);
-                    }
-                } else {
-                    group = new TaskGrouping(t.key.id);
-                    addGroup(group);
-                }
-                group.addTask(t);
-                tasksMap.put(t.key, t);
-            }
-            // Update the task colors for each of the groups
-            float minAlpha = context.getResources().getFloat(
-                    R.dimen.recents_task_affiliation_color_min_alpha_percentage);
-            int taskGroupCount = mGroups.size();
-            for (int i = 0; i < taskGroupCount; i++) {
-                TaskGrouping group = mGroups.get(i);
-                taskCount = group.getTaskCount();
-                // Ignore the groups that only have one task
-                if (taskCount <= 1) continue;
-                // Calculate the group color distribution
-                int affiliationColor = tasksMap.get(group.mTaskKeys.get(0)).affiliationColor;
-                float alphaStep = (1f - minAlpha) / taskCount;
-                float alpha = 1f;
-                for (int j = 0; j < taskCount; j++) {
-                    Task t = tasksMap.get(group.mTaskKeys.get(j));
-                    t.colorPrimary = Utilities.getColorWithOverlay(affiliationColor, Color.WHITE,
-                            alpha);
-                    alpha -= alphaStep;
-                }
-            }
-        }
-    }
-
-    /**
-     * Computes the components of tasks in this stack that have been removed as a result of a change
-     * in the specified package.
-     */
-    public ArraySet<ComponentName> computeComponentsRemoved(String packageName, int userId) {
-        // Identify all the tasks that should be removed as a result of the package being removed.
-        // Using a set to ensure that we callback once per unique component.
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        ArraySet<ComponentName> existingComponents = new ArraySet<>();
-        ArraySet<ComponentName> removedComponents = new ArraySet<>();
-        ArrayList<Task.TaskKey> taskKeys = getTaskKeys();
-        int taskKeyCount = taskKeys.size();
-        for (int i = 0; i < taskKeyCount; i++) {
-            Task.TaskKey t = taskKeys.get(i);
-
-            // Skip if this doesn't apply to the current user
-            if (t.userId != userId) continue;
-
-            ComponentName cn = t.getComponent();
-            if (cn.getPackageName().equals(packageName)) {
-                if (existingComponents.contains(cn)) {
-                    // If we know that the component still exists in the package, then skip
-                    continue;
-                }
-                if (ssp.getActivityInfo(cn, userId) != null) {
-                    existingComponents.add(cn);
-                } else {
-                    removedComponents.add(cn);
-                }
-            }
-        }
-        return removedComponents;
-    }
-
-    @Override
-    public String toString() {
-        String str = "Stack Tasks (" + mStackTaskList.size() + "):\n";
-        ArrayList<Task> tasks = mStackTaskList.getTasks();
-        int taskCount = tasks.size();
-        for (int i = 0; i < taskCount; i++) {
-            str += "    " + tasks.get(i).toString() + "\n";
-        }
-        return str;
-    }
-
-    /**
-     * Given a list of tasks, returns a map of each task's key to the task.
-     */
-    private ArrayMap<Task.TaskKey, Task> createTaskKeyMapFromList(List<Task> tasks) {
-        ArrayMap<Task.TaskKey, Task> map = new ArrayMap<>(tasks.size());
-        int taskCount = tasks.size();
-        for (int i = 0; i < taskCount; i++) {
-            Task task = tasks.get(i);
-            map.put(task.key, task);
-        }
-        return map;
-    }
-
-    public void dump(String prefix, PrintWriter writer) {
-        String innerPrefix = prefix + "  ";
-
-        writer.print(prefix); writer.print(TAG);
-        writer.print(" numStackTasks="); writer.print(mStackTaskList.size());
-        writer.println();
-        ArrayList<Task> tasks = mStackTaskList.getTasks();
-        int taskCount = tasks.size();
-        for (int i = 0; i < taskCount; i++) {
-            tasks.get(i).dump(innerPrefix, writer);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java b/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java
deleted file mode 100644
index 33ff1b6..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java
+++ /dev/null
@@ -1,44 +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 com.android.systemui.recents.model;
-
-import android.app.ActivityManager.TaskSnapshot;
-import android.graphics.Bitmap;
-import android.graphics.Rect;
-
-/**
- * Data for a single thumbnail.
- */
-public class ThumbnailData {
-
-    // TODO: Make these final once the non-snapshot path is removed.
-    public Bitmap thumbnail;
-    public int orientation;
-    public final Rect insets = new Rect();
-    public boolean reducedResolution;
-    public float scale;
-
-    public static ThumbnailData createFromTaskSnapshot(TaskSnapshot snapshot) {
-        ThumbnailData out = new ThumbnailData();
-        out.thumbnail = Bitmap.createHardwareBitmap(snapshot.getSnapshot());
-        out.insets.set(snapshot.getContentInsets());
-        out.orientation = snapshot.getOrientation();
-        out.reducedResolution = snapshot.isReducedResolution();
-        out.scale = snapshot.getScale();
-        return out;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
index 7998ecb..b598ec6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
@@ -22,7 +22,7 @@
 import android.view.ViewDebug;
 import android.view.ViewOutlineProvider;
 
-import com.android.systemui.recents.misc.Utilities;
+import com.android.systemui.shared.recents.utilities.Utilities;
 
 /* An outline provider that has a clip and outline that can be animated. */
 public class AnimateableViewBounds extends ViewOutlineProvider {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java
deleted file mode 100644
index 716d1bc..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java
+++ /dev/null
@@ -1,230 +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 com.android.systemui.recents.views;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ValueAnimator;
-import android.annotation.IntDef;
-import android.util.SparseArray;
-import android.util.SparseLongArray;
-import android.view.View;
-import android.view.animation.Interpolator;
-
-import com.android.systemui.Interpolators;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.List;
-
-/**
- * The generic set of animation properties to animate a {@link View}. The animation can have
- * different interpolators, start delays and durations for each of the different properties.
- */
-public class AnimationProps {
-
-    public static final AnimationProps IMMEDIATE = new AnimationProps(0, Interpolators.LINEAR);
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({ALL, TRANSLATION_X, TRANSLATION_Y, TRANSLATION_Z, ALPHA, SCALE, BOUNDS})
-    public @interface PropType {}
-
-    public static final int ALL = 0;
-    public static final int TRANSLATION_X = 1;
-    public static final int TRANSLATION_Y = 2;
-    public static final int TRANSLATION_Z = 3;
-    public static final int ALPHA = 4;
-    public static final int SCALE = 5;
-    public static final int BOUNDS = 6;
-    public static final int DIM_ALPHA = 7;
-    public static final int FOCUS_STATE = 8;
-
-    private SparseLongArray mPropStartDelay;
-    private SparseLongArray mPropDuration;
-    private SparseArray<Interpolator> mPropInterpolators;
-    private Animator.AnimatorListener mListener;
-
-    /**
-     * The builder constructor.
-     */
-    public AnimationProps() {}
-
-    /**
-     * Creates an animation with a default {@param duration} and {@param interpolator} for all
-     * properties in this animation.
-     */
-    public AnimationProps(int duration, Interpolator interpolator) {
-        this(0, duration, interpolator, null);
-    }
-
-    /**
-     * Creates an animation with a default {@param duration} and {@param interpolator} for all
-     * properties in this animation.
-     */
-    public AnimationProps(int duration, Interpolator interpolator,
-            Animator.AnimatorListener listener) {
-        this(0, duration, interpolator, listener);
-    }
-
-    /**
-     * Creates an animation with a default {@param startDelay}, {@param duration} and
-     * {@param interpolator} for all properties in this animation.
-     */
-    public AnimationProps(int startDelay, int duration, Interpolator interpolator) {
-        this(startDelay, duration, interpolator, null);
-    }
-
-    /**
-     * Creates an animation with a default {@param startDelay}, {@param duration} and
-     * {@param interpolator} for all properties in this animation.
-     */
-    public AnimationProps(int startDelay, int duration, Interpolator interpolator,
-            Animator.AnimatorListener listener) {
-        setStartDelay(ALL, startDelay);
-        setDuration(ALL, duration);
-        setInterpolator(ALL, interpolator);
-        setListener(listener);
-    }
-
-    /**
-     * Creates a new {@link AnimatorSet} that will animate the given animators.  Callers need to
-     * manually apply the individual animation properties for each of the animators respectively.
-     */
-    public AnimatorSet createAnimator(List<Animator> animators) {
-        AnimatorSet anim = new AnimatorSet();
-        if (mListener != null) {
-            anim.addListener(mListener);
-        }
-        anim.playTogether(animators);
-        return anim;
-    }
-
-    /**
-     * Applies the specific start delay, duration and interpolator to the given {@param animator}
-     * for the specified {@param propertyType}.
-     */
-    public <T extends ValueAnimator> T apply(@PropType int propertyType, T animator) {
-        animator.setStartDelay(getStartDelay(propertyType));
-        animator.setDuration(getDuration(propertyType));
-        animator.setInterpolator(getInterpolator(propertyType));
-        return animator;
-    }
-
-    /**
-     * Sets a start delay for a specific property.
-     */
-    public AnimationProps setStartDelay(@PropType int propertyType, int startDelay) {
-        if (mPropStartDelay == null) {
-            mPropStartDelay = new SparseLongArray();
-        }
-        mPropStartDelay.append(propertyType, startDelay);
-        return this;
-    }
-
-    /**
-     * Returns the start delay for a specific property.
-     */
-    public long getStartDelay(@PropType int propertyType) {
-        if (mPropStartDelay != null) {
-            long startDelay = mPropStartDelay.get(propertyType, -1);
-            if (startDelay != -1) {
-                return startDelay;
-            }
-            return mPropStartDelay.get(ALL, 0);
-        }
-        return 0;
-    }
-
-    /**
-     * Sets a duration for a specific property.
-     */
-    public AnimationProps setDuration(@PropType int propertyType, int duration) {
-        if (mPropDuration == null) {
-            mPropDuration = new SparseLongArray();
-        }
-        mPropDuration.append(propertyType, duration);
-        return this;
-    }
-
-    /**
-     * Returns the duration for a specific property.
-     */
-    public long getDuration(@PropType int propertyType) {
-        if (mPropDuration != null) {
-            long duration = mPropDuration.get(propertyType, -1);
-            if (duration != -1) {
-                return duration;
-            }
-            return mPropDuration.get(ALL, 0);
-        }
-        return 0;
-    }
-
-    /**
-     * Sets an interpolator for a specific property.
-     */
-    public AnimationProps setInterpolator(@PropType int propertyType, Interpolator interpolator) {
-        if (mPropInterpolators == null) {
-            mPropInterpolators = new SparseArray<>();
-        }
-        mPropInterpolators.append(propertyType, interpolator);
-        return this;
-    }
-
-    /**
-     * Returns the interpolator for a specific property, falling back to the general interpolator
-     * if there is no specific property interpolator.
-     */
-    public Interpolator getInterpolator(@PropType int propertyType) {
-        if (mPropInterpolators != null) {
-            Interpolator interp = mPropInterpolators.get(propertyType);
-            if (interp != null) {
-                return interp;
-            }
-            return mPropInterpolators.get(ALL, Interpolators.LINEAR);
-        }
-        return Interpolators.LINEAR;
-    }
-
-    /**
-     * Sets an animator listener for this animation.
-     */
-    public AnimationProps setListener(Animator.AnimatorListener listener) {
-        mListener = listener;
-        return this;
-    }
-
-    /**
-     * Returns the animator listener for this animation.
-     */
-    public Animator.AnimatorListener getListener() {
-        return mListener;
-    }
-
-    /**
-     * Returns whether this animation has any duration.
-     */
-    public boolean isImmediate() {
-        int count = mPropDuration.size();
-        for (int i = 0; i < count; i++) {
-            if (mPropDuration.valueAt(i) > 0) {
-                return false;
-            }
-        }
-        return true;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/DockState.java b/packages/SystemUI/src/com/android/systemui/recents/views/DockState.java
new file mode 100644
index 0000000..59f2868
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/DockState.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.views;
+
+import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
+import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
+import static android.view.WindowManager.DOCKED_TOP;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.annotation.IntDef;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.ColorDrawable;
+import android.util.IntProperty;
+import android.view.animation.Interpolator;
+
+import com.android.internal.policy.DockedDividerUtils;
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.shared.recents.utilities.Utilities;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+
+/**
+ * The various possible dock states when dragging and dropping a task.
+ */
+public class DockState implements DropTarget {
+
+    public static final int DOCK_AREA_BG_COLOR = 0xFFffffff;
+    public static final int DOCK_AREA_GRID_BG_COLOR = 0xFF000000;
+
+    // The rotation to apply to the hint text
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({HORIZONTAL, VERTICAL})
+    public @interface TextOrientation {}
+    private static final int HORIZONTAL = 0;
+    private static final int VERTICAL = 1;
+
+    private static final int DOCK_AREA_ALPHA = 80;
+    public static final DockState NONE = new DockState(DOCKED_INVALID, -1, 80, 255, HORIZONTAL,
+            null, null, null);
+    public static final DockState LEFT = new DockState(DOCKED_LEFT,
+            DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA, 0, VERTICAL,
+            new RectF(0, 0, 0.125f, 1), new RectF(0, 0, 0.125f, 1),
+            new RectF(0, 0, 0.5f, 1));
+    public static final DockState TOP = new DockState(DOCKED_TOP,
+            DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA, 0, HORIZONTAL,
+            new RectF(0, 0, 1, 0.125f), new RectF(0, 0, 1, 0.125f),
+            new RectF(0, 0, 1, 0.5f));
+    public static final DockState RIGHT = new DockState(DOCKED_RIGHT,
+            DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA, 0, VERTICAL,
+            new RectF(0.875f, 0, 1, 1), new RectF(0.875f, 0, 1, 1),
+            new RectF(0.5f, 0, 1, 1));
+    public static final DockState BOTTOM = new DockState(DOCKED_BOTTOM,
+            DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA, 0, HORIZONTAL,
+            new RectF(0, 0.875f, 1, 1), new RectF(0, 0.875f, 1, 1),
+            new RectF(0, 0.5f, 1, 1));
+
+    @Override
+    public boolean acceptsDrop(int x, int y, int width, int height, Rect insets,
+            boolean isCurrentTarget) {
+        if (isCurrentTarget) {
+            getMappedRect(expandedTouchDockArea, width, height, mTmpRect);
+            return mTmpRect.contains(x, y);
+        } else {
+            getMappedRect(touchArea, width, height, mTmpRect);
+            updateBoundsWithSystemInsets(mTmpRect, insets);
+            return mTmpRect.contains(x, y);
+        }
+    }
+
+    // Represents the view state of this dock state
+    public static class ViewState {
+        private static final IntProperty<ViewState> HINT_ALPHA =
+                new IntProperty<ViewState>("drawableAlpha") {
+                    @Override
+                    public void setValue(ViewState object, int alpha) {
+                        object.mHintTextAlpha = alpha;
+                        object.dockAreaOverlay.invalidateSelf();
+                    }
+
+                    @Override
+                    public Integer get(ViewState object) {
+                        return object.mHintTextAlpha;
+                    }
+                };
+
+        public final int dockAreaAlpha;
+        public final ColorDrawable dockAreaOverlay;
+        public final int hintTextAlpha;
+        public final int hintTextOrientation;
+
+        private final int mHintTextResId;
+        private String mHintText;
+        private Paint mHintTextPaint;
+        private Point mHintTextBounds = new Point();
+        private int mHintTextAlpha = 255;
+        private AnimatorSet mDockAreaOverlayAnimator;
+        private Rect mTmpRect = new Rect();
+
+        private ViewState(int areaAlpha, int hintAlpha, @TextOrientation int hintOrientation,
+                int hintTextResId) {
+            dockAreaAlpha = areaAlpha;
+            dockAreaOverlay = new ColorDrawable(Recents.getConfiguration().isGridEnabled
+                    ? DOCK_AREA_GRID_BG_COLOR : DOCK_AREA_BG_COLOR);
+            dockAreaOverlay.setAlpha(0);
+            hintTextAlpha = hintAlpha;
+            hintTextOrientation = hintOrientation;
+            mHintTextResId = hintTextResId;
+            mHintTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+            mHintTextPaint.setColor(Color.WHITE);
+        }
+
+        /**
+         * Updates the view state with the given context.
+         */
+        public void update(Context context) {
+            Resources res = context.getResources();
+            mHintText = context.getString(mHintTextResId);
+            mHintTextPaint.setTextSize(res.getDimensionPixelSize(
+                    R.dimen.recents_drag_hint_text_size));
+            mHintTextPaint.getTextBounds(mHintText, 0, mHintText.length(), mTmpRect);
+            mHintTextBounds.set((int) mHintTextPaint.measureText(mHintText), mTmpRect.height());
+        }
+
+        /**
+         * Draws the current view state.
+         */
+        public void draw(Canvas canvas) {
+            // Draw the overlay background
+            if (dockAreaOverlay.getAlpha() > 0) {
+                dockAreaOverlay.draw(canvas);
+            }
+
+            // Draw the hint text
+            if (mHintTextAlpha > 0) {
+                Rect bounds = dockAreaOverlay.getBounds();
+                int x = bounds.left + (bounds.width() - mHintTextBounds.x) / 2;
+                int y = bounds.top + (bounds.height() + mHintTextBounds.y) / 2;
+                mHintTextPaint.setAlpha(mHintTextAlpha);
+                if (hintTextOrientation == VERTICAL) {
+                    canvas.save();
+                    canvas.rotate(-90f, bounds.centerX(), bounds.centerY());
+                }
+                canvas.drawText(mHintText, x, y, mHintTextPaint);
+                if (hintTextOrientation == VERTICAL) {
+                    canvas.restore();
+                }
+            }
+        }
+
+        /**
+         * Creates a new bounds and alpha animation.
+         */
+        public void startAnimation(Rect bounds, int areaAlpha, int hintAlpha, int duration,
+                Interpolator interpolator, boolean animateAlpha, boolean animateBounds) {
+            if (mDockAreaOverlayAnimator != null) {
+                mDockAreaOverlayAnimator.cancel();
+            }
+
+            ObjectAnimator anim;
+            ArrayList<Animator> animators = new ArrayList<>();
+            if (dockAreaOverlay.getAlpha() != areaAlpha) {
+                if (animateAlpha) {
+                    anim = ObjectAnimator.ofInt(dockAreaOverlay,
+                            Utilities.DRAWABLE_ALPHA, dockAreaOverlay.getAlpha(), areaAlpha);
+                    anim.setDuration(duration);
+                    anim.setInterpolator(interpolator);
+                    animators.add(anim);
+                } else {
+                    dockAreaOverlay.setAlpha(areaAlpha);
+                }
+            }
+            if (mHintTextAlpha != hintAlpha) {
+                if (animateAlpha) {
+                    anim = ObjectAnimator.ofInt(this, HINT_ALPHA, mHintTextAlpha,
+                            hintAlpha);
+                    anim.setDuration(150);
+                    anim.setInterpolator(hintAlpha > mHintTextAlpha
+                            ? Interpolators.ALPHA_IN
+                            : Interpolators.ALPHA_OUT);
+                    animators.add(anim);
+                } else {
+                    mHintTextAlpha = hintAlpha;
+                    dockAreaOverlay.invalidateSelf();
+                }
+            }
+            if (bounds != null && !dockAreaOverlay.getBounds().equals(bounds)) {
+                if (animateBounds) {
+                    PropertyValuesHolder prop = PropertyValuesHolder.ofObject(
+                            Utilities.DRAWABLE_RECT, Utilities.RECT_EVALUATOR,
+                            new Rect(dockAreaOverlay.getBounds()), bounds);
+                    anim = ObjectAnimator.ofPropertyValuesHolder(dockAreaOverlay, prop);
+                    anim.setDuration(duration);
+                    anim.setInterpolator(interpolator);
+                    animators.add(anim);
+                } else {
+                    dockAreaOverlay.setBounds(bounds);
+                }
+            }
+            if (!animators.isEmpty()) {
+                mDockAreaOverlayAnimator = new AnimatorSet();
+                mDockAreaOverlayAnimator.playTogether(animators);
+                mDockAreaOverlayAnimator.start();
+            }
+        }
+    }
+
+    public final int dockSide;
+    public final int createMode;
+    public final ViewState viewState;
+    private final RectF touchArea;
+    private final RectF dockArea;
+    private final RectF expandedTouchDockArea;
+    private static final Rect mTmpRect = new Rect();
+
+    /**
+     * @param createMode used to pass to ActivityManager to dock the task
+     * @param touchArea the area in which touch will initiate this dock state
+     * @param dockArea the visible dock area
+     * @param expandedTouchDockArea the area in which touch will continue to dock after entering
+     *                              the initial touch area.  This is also the new dock area to
+     *                              draw.
+     */
+    DockState(int dockSide, int createMode, int dockAreaAlpha, int hintTextAlpha,
+            @TextOrientation int hintTextOrientation, RectF touchArea, RectF dockArea,
+            RectF expandedTouchDockArea) {
+        this.dockSide = dockSide;
+        this.createMode = createMode;
+        this.viewState = new ViewState(dockAreaAlpha, hintTextAlpha, hintTextOrientation,
+                R.string.recents_drag_hint_message);
+        this.dockArea = dockArea;
+        this.touchArea = touchArea;
+        this.expandedTouchDockArea = expandedTouchDockArea;
+    }
+
+    /**
+     * Updates the dock state with the given context.
+     */
+    public void update(Context context) {
+        viewState.update(context);
+    }
+
+    /**
+     * Returns the docked task bounds with the given {@param width} and {@param height}.
+     */
+    public Rect getPreDockedBounds(int width, int height, Rect insets) {
+        getMappedRect(dockArea, width, height, mTmpRect);
+        return updateBoundsWithSystemInsets(mTmpRect, insets);
+    }
+
+    /**
+     * Returns the expanded docked task bounds with the given {@param width} and
+     * {@param height}.
+     */
+    public Rect getDockedBounds(int width, int height, int dividerSize, Rect insets,
+            Resources res) {
+        // Calculate the docked task bounds
+        boolean isHorizontalDivision =
+                res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
+        int position = DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision,
+                insets, width, height, dividerSize);
+        Rect newWindowBounds = new Rect();
+        DockedDividerUtils.calculateBoundsForPosition(position, dockSide, newWindowBounds,
+                width, height, dividerSize);
+        return newWindowBounds;
+    }
+
+    /**
+     * Returns the task stack bounds with the given {@param width} and
+     * {@param height}.
+     */
+    public Rect getDockedTaskStackBounds(Rect displayRect, int width, int height,
+            int dividerSize, Rect insets, TaskStackLayoutAlgorithm layoutAlgorithm,
+            Resources res, Rect windowRectOut) {
+        // Calculate the inverse docked task bounds
+        boolean isHorizontalDivision =
+                res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
+        int position = DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision,
+                insets, width, height, dividerSize);
+        DockedDividerUtils.calculateBoundsForPosition(position,
+                DockedDividerUtils.invertDockSide(dockSide), windowRectOut, width, height,
+                dividerSize);
+
+        // Calculate the task stack bounds from the new window bounds
+        Rect taskStackBounds = new Rect();
+        // If the task stack bounds is specifically under the dock area, then ignore the top
+        // inset
+        int top = dockArea.bottom < 1f
+                ? 0
+                : insets.top;
+        // For now, ignore the left insets since we always dock on the left and show Recents
+        // on the right
+        layoutAlgorithm.getTaskStackBounds(displayRect, windowRectOut, top, 0, insets.right,
+                taskStackBounds);
+        return taskStackBounds;
+    }
+
+    /**
+     * Returns the expanded bounds in certain dock sides such that the bounds account for the
+     * system insets (namely the vertical nav bar).  This call modifies and returns the given
+     * {@param bounds}.
+     */
+    private Rect updateBoundsWithSystemInsets(Rect bounds, Rect insets) {
+        if (dockSide == DOCKED_LEFT) {
+            bounds.right += insets.left;
+        } else if (dockSide == DOCKED_RIGHT) {
+            bounds.left -= insets.right;
+        }
+        return bounds;
+    }
+
+    /**
+     * Returns the mapped rect to the given dimensions.
+     */
+    private void getMappedRect(RectF bounds, int width, int height, Rect out) {
+        out.set((int) (bounds.left * width), (int) (bounds.top * height),
+                (int) (bounds.right * width), (int) (bounds.bottom * height));
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
deleted file mode 100644
index 035c058..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.views;
-
-import android.content.Context;
-import android.graphics.RectF;
-import android.util.ArrayMap;
-
-import com.android.systemui.R;
-import com.android.systemui.recents.model.Task;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * The layout logic for the contents of the freeform workspace.
- */
-public class FreeformWorkspaceLayoutAlgorithm {
-
-    // Optimization, allows for quick lookup of task -> rect
-    private ArrayMap<Task.TaskKey, RectF> mTaskRectMap = new ArrayMap<>();
-
-    private int mTaskPadding;
-
-    public FreeformWorkspaceLayoutAlgorithm(Context context) {
-        reloadOnConfigurationChange(context);
-    }
-
-    /**
-     * Reloads the layout for the current configuration.
-     */
-    public void reloadOnConfigurationChange(Context context) {
-        // This is applied to the edges of each task
-        mTaskPadding = context.getResources().getDimensionPixelSize(
-                R.dimen.recents_freeform_layout_task_padding) / 2;
-    }
-
-    /**
-     * Updates the layout for each of the freeform workspace tasks.  This is called after the stack
-     * layout is updated.
-     */
-    public void update(List<Task> freeformTasks, TaskStackLayoutAlgorithm stackLayout) {
-        Collections.reverse(freeformTasks);
-        mTaskRectMap.clear();
-
-        int numFreeformTasks = stackLayout.mNumFreeformTasks;
-        if (!freeformTasks.isEmpty()) {
-
-            // Normalize the widths so that we can calculate the best layout below
-            int workspaceWidth = stackLayout.mFreeformRect.width();
-            int workspaceHeight = stackLayout.mFreeformRect.height();
-            float normalizedWorkspaceWidth = (float) workspaceWidth / workspaceHeight;
-            float normalizedWorkspaceHeight = 1f;
-            float[] normalizedTaskWidths = new float[numFreeformTasks];
-            for (int i = 0; i < numFreeformTasks; i++) {
-                Task task = freeformTasks.get(i);
-                float rowTaskWidth;
-                if (task.bounds != null) {
-                    rowTaskWidth = (float) task.bounds.width() / task.bounds.height();
-                } else {
-                    // If this is a stack task that was dragged into the freeform workspace, then
-                    // the task will not yet have an associated bounds, so assume the full workspace
-                    // width for the time being
-                    rowTaskWidth = normalizedWorkspaceWidth;
-                }
-                // Bound the task width to the workspace width so that at the worst case, it will
-                // fit its own row
-                normalizedTaskWidths[i] = Math.min(rowTaskWidth, normalizedWorkspaceWidth);
-            }
-
-            // Determine the scale to best fit each of the tasks in the workspace
-            float rowScale = 0.85f;
-            float rowWidth = 0f;
-            float maxRowWidth = 0f;
-            int rowCount = 1;
-            for (int i = 0; i < numFreeformTasks;) {
-                float width = normalizedTaskWidths[i] * rowScale;
-                if (rowWidth + width > normalizedWorkspaceWidth) {
-                    // That is too long for this row, create new row
-                    if ((rowCount + 1) * rowScale > normalizedWorkspaceHeight) {
-                        // The new row is too high, so we need to try fitting again.  Update the
-                        // scale to be the smaller of the scale needed to fit the task in the
-                        // previous row, or the scale needed to fit the new row
-                        rowScale = Math.min(normalizedWorkspaceWidth / (rowWidth + width),
-                                normalizedWorkspaceHeight / (rowCount + 1));
-                        rowCount = 1;
-                        rowWidth = 0;
-                        i = 0;
-                    } else {
-                        // The new row fits, so continue
-                        rowWidth = width;
-                        rowCount++;
-                        i++;
-                    }
-                } else {
-                    // Task is OK in this row
-                    rowWidth += width;
-                    i++;
-                }
-                maxRowWidth = Math.max(rowWidth, maxRowWidth);
-            }
-
-            // Normalize each of the actual rects to that scale
-            float defaultRowLeft = ((1f - (maxRowWidth / normalizedWorkspaceWidth)) *
-                    workspaceWidth) / 2f;
-            float rowLeft = defaultRowLeft;
-            float rowTop = ((1f - (rowScale * rowCount)) * workspaceHeight) / 2f;
-            float rowHeight = rowScale * workspaceHeight;
-            for (int i = 0; i < numFreeformTasks; i++) {
-                Task task = freeformTasks.get(i);
-                float width = rowHeight * normalizedTaskWidths[i];
-                if (rowLeft + width > workspaceWidth) {
-                    // This goes on the next line
-                    rowTop += rowHeight;
-                    rowLeft = defaultRowLeft;
-                }
-                RectF rect = new RectF(rowLeft, rowTop, rowLeft + width, rowTop + rowHeight);
-                rect.inset(mTaskPadding, mTaskPadding);
-                rowLeft += width;
-                mTaskRectMap.put(task.key, rect);
-            }
-        }
-    }
-
-    /**
-     * Returns whether the transform is available for the given task.
-     */
-    public boolean isTransformAvailable(Task task, TaskStackLayoutAlgorithm stackLayout) {
-        if (stackLayout.mNumFreeformTasks == 0 || task == null) {
-            return false;
-        }
-        return mTaskRectMap.containsKey(task.key);
-    }
-
-    /**
-     * Returns the transform for the given task.  Any rect returned will be offset by the actual
-     * transform for the freeform workspace.
-     */
-    public TaskViewTransform getTransform(Task task, TaskViewTransform transformOut,
-            TaskStackLayoutAlgorithm stackLayout) {
-        if (mTaskRectMap.containsKey(task.key)) {
-            final RectF ffRect = mTaskRectMap.get(task.key);
-
-            transformOut.scale = 1f;
-            transformOut.alpha = 1f;
-            transformOut.translationZ = stackLayout.mMaxTranslationZ;
-            transformOut.dimAlpha = 0f;
-            transformOut.viewOutlineAlpha = TaskStackLayoutAlgorithm.OUTLINE_ALPHA_MAX_VALUE;
-            transformOut.rect.set(ffRect);
-            transformOut.rect.offset(stackLayout.mFreeformRect.left, stackLayout.mFreeformRect.top);
-            transformOut.visible = true;
-            return transformOut;
-        }
-        return null;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index ee05d81..25c2fc9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -19,7 +19,6 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
@@ -31,8 +30,6 @@
 import android.app.ActivityOptions.OnAnimationStartedListener;
 import android.content.Context;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.GraphicBuffer;
 import android.graphics.Rect;
 import android.os.Bundle;
@@ -59,8 +56,8 @@
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
 import com.android.systemui.recents.events.component.SetWaitingForTransitionStartEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.TaskStack;
 import com.android.systemui.statusbar.phone.StatusBar;
 
 import java.util.ArrayList;
@@ -188,20 +185,9 @@
         } else {
             LaunchTaskStartedEvent launchStartedEvent = new LaunchTaskStartedEvent(taskView,
                     screenPinningRequested);
-            if (task.group != null && !task.group.isFrontMostTask(task)) {
-                launchStartedEvent.addPostAnimationCallback(new Runnable() {
-                    @Override
-                    public void run() {
-                        startTaskActivity(stack, task, taskView, opts, transitionFuture,
-                                windowingMode, activityType);
-                    }
-                });
-                EventBus.getDefault().send(launchStartedEvent);
-            } else {
-                EventBus.getDefault().send(launchStartedEvent);
-                startTaskActivity(stack, task, taskView, opts, transitionFuture,
-                        windowingMode, activityType);
-            }
+            EventBus.getDefault().send(launchStartedEvent);
+            startTaskActivity(stack, task, taskView, opts, transitionFuture, windowingMode,
+                    activityType);
         }
         Recents.getSystemServices().sendCloseSystemWindows(
                 StatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
@@ -329,7 +315,6 @@
 
         // If this is a full screen stack, the transition will be towards the single, full screen
         // task. We only need the transition spec for this task.
-        List<AppTransitionAnimationSpec> specs = new ArrayList<>();
 
         // TODO: Sometimes targetStackId is not initialized after reboot, so we also have to
         // check for INVALID_STACK_ID (now WINDOWING_MODE_UNDEFINED)
@@ -338,6 +323,7 @@
                 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
                 || activityType == ACTIVITY_TYPE_ASSISTANT
                 || windowingMode == WINDOWING_MODE_UNDEFINED) {
+            List<AppTransitionAnimationSpec> specs = new ArrayList<>();
             if (taskView == null) {
                 specs.add(composeOffscreenAnimationSpec(task, offscreenTaskRect));
             } else {
@@ -351,34 +337,7 @@
             }
             return specs;
         }
-
-        // Otherwise, for freeform tasks, create a new animation spec for each task we have to
-        // launch
-        TaskStack stack = stackView.getStack();
-        ArrayList<Task> tasks = stack.getStackTasks();
-        int taskCount = tasks.size();
-        for (int i = taskCount - 1; i >= 0; i--) {
-            Task t = tasks.get(i);
-            if (t.isFreeformTask() || windowingMode == WINDOWING_MODE_FREEFORM) {
-                TaskView tv = stackView.getChildViewForTask(t);
-                if (tv == null) {
-                    // TODO: Create a different animation task rect for this case (though it should
-                    //       never happen)
-                    specs.add(composeOffscreenAnimationSpec(t, offscreenTaskRect));
-                } else {
-                    mTmpTransform.fillIn(taskView);
-                    stackLayout.transformToScreenCoordinates(mTmpTransform,
-                            null /* windowOverrideRect */);
-                    AppTransitionAnimationSpec spec = composeAnimationSpec(stackView, tv,
-                            mTmpTransform, true /* addHeaderBitmap */);
-                    if (spec != null) {
-                        specs.add(spec);
-                    }
-                }
-            }
-        }
-
-        return specs;
+        return Collections.emptyList();
     }
 
     /**
@@ -462,7 +421,7 @@
         // force the task thumbnail to full stackView height immediately causing the transition
         // jarring.
         if (!Recents.getConfiguration().isLowRamDevice && taskView.getTask() !=
-                stackView.getStack().getStackFrontMostTask(false /* includeFreeformTasks */)) {
+                stackView.getStack().getStackFrontMostTask()) {
             taskRect.bottom = taskRect.top + stackView.getMeasuredHeight();
         }
         return new AppTransitionAnimationSpec(taskView.getTask().key.id, b, taskRect);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index e460bf8..5f12a04 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -53,7 +53,6 @@
 import com.android.systemui.recents.RecentsActivity;
 import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.RecentsDebugFlags;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
 import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
@@ -74,9 +73,9 @@
 import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.TaskStack;
 import com.android.systemui.recents.views.RecentsTransitionHelper.AnimationSpecComposer;
 import com.android.systemui.recents.views.RecentsTransitionHelper.AppTransitionAnimationSpecsFuture;
 import com.android.systemui.stackdivider.WindowManagerProxy;
@@ -110,7 +109,6 @@
     private final int mStackButtonShadowColor;
 
     private boolean mAwaitingFirstLayout = true;
-    private boolean mLastTaskLaunchedWasFreeform;
 
     @ViewDebug.ExportedProperty(category="recents")
     Rect mSystemInsets = new Rect();
@@ -161,22 +159,20 @@
         mEmptyView = (TextView) inflater.inflate(R.layout.recents_empty, this, false);
         addView(mEmptyView);
 
-        if (RecentsDebugFlags.Static.EnableStackActionButton) {
-            if (mStackActionButton != null) {
-                removeView(mStackActionButton);
-            }
-            mStackActionButton = (TextView) inflater.inflate(Recents.getConfiguration()
-                            .isLowRamDevice
-                        ? R.layout.recents_low_ram_stack_action_button
-                        : R.layout.recents_stack_action_button,
-                    this, false);
-
-            mStackButtonShadowRadius = mStackActionButton.getShadowRadius();
-            mStackButtonShadowDistance = new PointF(mStackActionButton.getShadowDx(),
-                    mStackActionButton.getShadowDy());
-            mStackButtonShadowColor = mStackActionButton.getShadowColor();
-            addView(mStackActionButton);
+        if (mStackActionButton != null) {
+            removeView(mStackActionButton);
         }
+        mStackActionButton = (TextView) inflater.inflate(Recents.getConfiguration()
+                        .isLowRamDevice
+                    ? R.layout.recents_low_ram_stack_action_button
+                    : R.layout.recents_stack_action_button,
+                this, false);
+
+        mStackButtonShadowRadius = mStackActionButton.getShadowRadius();
+        mStackButtonShadowDistance = new PointF(mStackActionButton.getShadowDx(),
+                mStackActionButton.getShadowDy());
+        mStackButtonShadowColor = mStackActionButton.getShadowColor();
+        addView(mStackActionButton);
 
         reevaluateStyles();
     }
@@ -228,7 +224,6 @@
 
         // Reset the state
         mAwaitingFirstLayout = !isResumingFromVisible;
-        mLastTaskLaunchedWasFreeform = false;
 
         // Update the stack
         mTaskStackView.onReload(isResumingFromVisible);
@@ -315,13 +310,6 @@
         }
     }
 
-    /**
-     * Returns whether the last task launched was in the freeform stack or not.
-     */
-    public boolean isLastTaskLaunchedFreeform() {
-        return mLastTaskLaunchedWasFreeform;
-    }
-
     /** Launches the focused task from the first stack if possible */
     public boolean launchFocusedTask(int logEvent) {
         if (mTaskStackView != null) {
@@ -367,9 +355,7 @@
         mEmptyView.setText(msgResId);
         mEmptyView.setVisibility(View.VISIBLE);
         mEmptyView.bringToFront();
-        if (RecentsDebugFlags.Static.EnableStackActionButton) {
-            mStackActionButton.bringToFront();
-        }
+        mStackActionButton.bringToFront();
     }
 
     /**
@@ -379,9 +365,7 @@
         mEmptyView.setVisibility(View.INVISIBLE);
         mTaskStackView.setVisibility(View.VISIBLE);
         mTaskStackView.bringToFront();
-        if (RecentsDebugFlags.Static.EnableStackActionButton) {
-            mStackActionButton.bringToFront();
-        }
+        mStackActionButton.bringToFront();
     }
 
     /**
@@ -429,13 +413,11 @@
                     MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
         }
 
-        if (RecentsDebugFlags.Static.EnableStackActionButton) {
-            // Measure the stack action button within the constraints of the space above the stack
-            Rect buttonBounds = mTaskStackView.mLayoutAlgorithm.getStackActionButtonRect();
-            measureChild(mStackActionButton,
-                    MeasureSpec.makeMeasureSpec(buttonBounds.width(), MeasureSpec.AT_MOST),
-                    MeasureSpec.makeMeasureSpec(buttonBounds.height(), MeasureSpec.AT_MOST));
-        }
+        // Measure the stack action button within the constraints of the space above the stack
+        Rect buttonBounds = mTaskStackView.mLayoutAlgorithm.getStackActionButtonRect();
+        measureChild(mStackActionButton,
+                MeasureSpec.makeMeasureSpec(buttonBounds.width(), MeasureSpec.AT_MOST),
+                MeasureSpec.makeMeasureSpec(buttonBounds.height(), MeasureSpec.AT_MOST));
 
         setMeasuredDimension(width, height);
     }
@@ -469,13 +451,11 @@
         mBackgroundScrim.setBounds(left, top, right, bottom);
         mMultiWindowBackgroundScrim.setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
 
-        if (RecentsDebugFlags.Static.EnableStackActionButton) {
-            // Layout the stack action button such that its drawable is start-aligned with the
-            // stack, vertically centered in the available space above the stack
-            Rect buttonBounds = getStackActionButtonBoundsFromStackLayout();
-            mStackActionButton.layout(buttonBounds.left, buttonBounds.top, buttonBounds.right,
-                    buttonBounds.bottom);
-        }
+        // Layout the stack action button such that its drawable is start-aligned with the
+        // stack, vertically centered in the available space above the stack
+        Rect buttonBounds = getStackActionButtonBoundsFromStackLayout();
+        mStackActionButton.layout(buttonBounds.left, buttonBounds.top, buttonBounds.right,
+                buttonBounds.bottom);
 
         if (mAwaitingFirstLayout) {
             mAwaitingFirstLayout = false;
@@ -517,7 +497,7 @@
     public void onDrawForeground(Canvas canvas) {
         super.onDrawForeground(canvas);
 
-        ArrayList<TaskStack.DockState> visDockStates = mTouchHandler.getVisibleDockStates();
+        ArrayList<DockState> visDockStates = mTouchHandler.getVisibleDockStates();
         for (int i = visDockStates.size() - 1; i >= 0; i--) {
             visDockStates.get(i).viewState.draw(canvas);
         }
@@ -525,7 +505,7 @@
 
     @Override
     protected boolean verifyDrawable(Drawable who) {
-        ArrayList<TaskStack.DockState> visDockStates = mTouchHandler.getVisibleDockStates();
+        ArrayList<DockState> visDockStates = mTouchHandler.getVisibleDockStates();
         for (int i = visDockStates.size() - 1; i >= 0; i--) {
             Drawable d = visDockStates.get(i).viewState.dockAreaOverlay;
             if (d == who) {
@@ -538,7 +518,6 @@
     /**** EventBus Events ****/
 
     public final void onBusEvent(LaunchTaskEvent event) {
-        mLastTaskLaunchedWasFreeform = event.task.isFreeformTask();
         mTransitionHelper.launchTaskFromRecents(getStack(), event.task, mTaskStackView,
                 event.taskView, event.screenPinningRequested, event.targetWindowingMode,
                 event.targetActivityType);
@@ -549,10 +528,8 @@
 
     public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
         int taskViewExitToHomeDuration = TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION;
-        if (RecentsDebugFlags.Static.EnableStackActionButton) {
-            // Hide the stack action button
-            EventBus.getDefault().send(new HideStackActionButtonEvent());
-        }
+        // Hide the stack action button
+        EventBus.getDefault().send(new HideStackActionButtonEvent());
         animateBackgroundScrim(0f, taskViewExitToHomeDuration);
 
         if (Recents.getConfiguration().isLowRamDevice) {
@@ -562,8 +539,8 @@
 
     public final void onBusEvent(DragStartEvent event) {
         updateVisibleDockRegions(Recents.getConfiguration().getDockStatesForCurrentOrientation(),
-                true /* isDefaultDockState */, TaskStack.DockState.NONE.viewState.dockAreaAlpha,
-                TaskStack.DockState.NONE.viewState.hintTextAlpha,
+                true /* isDefaultDockState */, DockState.NONE.viewState.dockAreaAlpha,
+                DockState.NONE.viewState.hintTextAlpha,
                 true /* animateAlpha */, false /* animateBounds */);
 
         // Temporarily hide the stack action button without changing visibility
@@ -577,15 +554,15 @@
     }
 
     public final void onBusEvent(DragDropTargetChangedEvent event) {
-        if (event.dropTarget == null || !(event.dropTarget instanceof TaskStack.DockState)) {
+        if (event.dropTarget == null || !(event.dropTarget instanceof DockState)) {
             updateVisibleDockRegions(
                     Recents.getConfiguration().getDockStatesForCurrentOrientation(),
-                    true /* isDefaultDockState */, TaskStack.DockState.NONE.viewState.dockAreaAlpha,
-                    TaskStack.DockState.NONE.viewState.hintTextAlpha,
+                    true /* isDefaultDockState */, DockState.NONE.viewState.dockAreaAlpha,
+                    DockState.NONE.viewState.hintTextAlpha,
                     true /* animateAlpha */, true /* animateBounds */);
         } else {
-            final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
-            updateVisibleDockRegions(new TaskStack.DockState[] {dockState},
+            final DockState dockState = (DockState) event.dropTarget;
+            updateVisibleDockRegions(new DockState[] {dockState},
                     false /* isDefaultDockState */, -1, -1, true /* animateAlpha */,
                     true /* animateBounds */);
         }
@@ -604,8 +581,8 @@
 
     public final void onBusEvent(final DragEndEvent event) {
         // Handle the case where we drop onto a dock region
-        if (event.dropTarget instanceof TaskStack.DockState) {
-            final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
+        if (event.dropTarget instanceof DockState) {
+            final DockState dockState = (DockState) event.dropTarget;
 
             // Hide the dock region
             updateVisibleDockRegions(null, false /* isDefaultDockState */, -1, -1,
@@ -727,18 +704,10 @@
     }
 
     public final void onBusEvent(ShowStackActionButtonEvent event) {
-        if (!RecentsDebugFlags.Static.EnableStackActionButton) {
-            return;
-        }
-
         showStackActionButton(SHOW_STACK_ACTION_BUTTON_DURATION, event.translate);
     }
 
     public final void onBusEvent(HideStackActionButtonEvent event) {
-        if (!RecentsDebugFlags.Static.EnableStackActionButton) {
-            return;
-        }
-
         hideStackActionButton(HIDE_STACK_ACTION_BUTTON_DURATION, true /* translate */);
     }
 
@@ -754,10 +723,6 @@
      * Shows the stack action button.
      */
     private void showStackActionButton(final int duration, final boolean translate) {
-        if (!RecentsDebugFlags.Static.EnableStackActionButton) {
-            return;
-        }
-
         final ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger();
         if (mStackActionButton.getVisibility() == View.INVISIBLE) {
             mStackActionButton.setVisibility(View.VISIBLE);
@@ -790,10 +755,6 @@
      * Hides the stack action button.
      */
     private void hideStackActionButton(int duration, boolean translate) {
-        if (!RecentsDebugFlags.Static.EnableStackActionButton) {
-            return;
-        }
-
         final ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger();
         hideStackActionButton(duration, translate, postAnimationTrigger);
         postAnimationTrigger.flushLastDecrementRunnables();
@@ -804,10 +765,6 @@
      */
     private void hideStackActionButton(int duration, boolean translate,
                                        final ReferenceCountedTrigger postAnimationTrigger) {
-        if (!RecentsDebugFlags.Static.EnableStackActionButton) {
-            return;
-        }
-
         if (mStackActionButton.getVisibility() == View.VISIBLE) {
             if (translate) {
                 mStackActionButton.animate().translationY(mStackActionButton.getMeasuredHeight()
@@ -854,15 +811,15 @@
     /**
      * Updates the dock region to match the specified dock state.
      */
-    private void updateVisibleDockRegions(TaskStack.DockState[] newDockStates,
+    private void updateVisibleDockRegions(DockState[] newDockStates,
             boolean isDefaultDockState, int overrideAreaAlpha, int overrideHintAlpha,
             boolean animateAlpha, boolean animateBounds) {
-        ArraySet<TaskStack.DockState> newDockStatesSet = Utilities.arrayToSet(newDockStates,
-                new ArraySet<TaskStack.DockState>());
-        ArrayList<TaskStack.DockState> visDockStates = mTouchHandler.getVisibleDockStates();
+        ArraySet<DockState> newDockStatesSet = Utilities.arrayToSet(newDockStates,
+                new ArraySet<DockState>());
+        ArrayList<DockState> visDockStates = mTouchHandler.getVisibleDockStates();
         for (int i = visDockStates.size() - 1; i >= 0; i--) {
-            TaskStack.DockState dockState = visDockStates.get(i);
-            TaskStack.DockState.ViewState viewState = dockState.viewState;
+            DockState dockState = visDockStates.get(i);
+            DockState.ViewState viewState = dockState.viewState;
             if (newDockStates == null || !newDockStatesSet.contains(dockState)) {
                 // This is no longer visible, so hide it
                 viewState.startAnimation(null, 0, 0, TaskStackView.SLOW_SYNC_STACK_DURATION,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index b6b24bc..0cfdbde 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -17,7 +17,6 @@
 package com.android.systemui.recents.views;
 
 import android.app.ActivityManager;
-import android.content.res.Configuration;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.view.InputDevice;
@@ -32,7 +31,6 @@
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
-import com.android.systemui.recents.events.activity.HideStackActionButtonEvent;
 import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
 import com.android.systemui.recents.events.ui.HideIncompatibleAppOverlayEvent;
 import com.android.systemui.recents.events.ui.ShowIncompatibleAppOverlayEvent;
@@ -41,8 +39,8 @@
 import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragStartInitializeDropTargetsEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.TaskStack;
 
 import java.util.ArrayList;
 
@@ -72,7 +70,7 @@
     private DropTarget mLastDropTarget;
     private DividerSnapAlgorithm mDividerSnapAlgorithm;
     private ArrayList<DropTarget> mDropTargets = new ArrayList<>();
-    private ArrayList<TaskStack.DockState> mVisibleDockStates = new ArrayList<>();
+    private ArrayList<DockState> mVisibleDockStates = new ArrayList<>();
 
     public RecentsViewTouchHandler(RecentsView rv) {
         mRv = rv;
@@ -96,7 +94,7 @@
     /**
      * Returns the set of visible dock states for this current drag.
      */
-    public ArrayList<TaskStack.DockState> getVisibleDockStates() {
+    public ArrayList<DockState> getVisibleDockStates() {
         return mVisibleDockStates;
     }
 
@@ -148,9 +146,9 @@
                 EventBus.getDefault().send(new ShowIncompatibleAppOverlayEvent());
             } else {
                 // Add the dock state drop targets (these take priority)
-                TaskStack.DockState[] dockStates = Recents.getConfiguration()
+                DockState[] dockStates = Recents.getConfiguration()
                         .getDockStatesForCurrentOrientation();
-                for (TaskStack.DockState dockState : dockStates) {
+                for (DockState dockState : dockStates) {
                     registerDropTargetForCurrentDrag(dockState);
                     dockState.update(mRv.getContext());
                     mVisibleDockStates.add(dockState);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 8f784b8..7827c59 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -30,7 +30,7 @@
 import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragEndCancelledEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.utilities.AnimationProps;
 
 /** Manages the scrims for the various system bars. */
 public class SystemBarScrimViews {
@@ -159,7 +159,7 @@
 
     public final void onBusEvent(final DragEndEvent event) {
         // Hide the nav bar scrims once we drop to a dock region
-        if (event.dropTarget instanceof TaskStack.DockState) {
+        if (event.dropTarget instanceof DockState) {
             animateScrimToCurrentNavBarState(false /* hasStackTasks */);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index 81bf6af..26db26f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -18,13 +18,11 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.util.Log;
-import android.view.View;
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
 
@@ -37,9 +35,10 @@
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.component.SetWaitingForTransitionStartEvent;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.TaskStack;
 import com.android.systemui.recents.views.lowram.TaskStackLowRamLayoutAlgorithm;
+import com.android.systemui.shared.recents.utilities.AnimationProps;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -161,20 +160,12 @@
         for (int i = taskViews.size() - 1; i >= 0; i--) {
             TaskView tv = taskViews.get(i);
             Task task = tv.getTask();
-            boolean currentTaskOccludesLaunchTarget = launchTargetTask != null &&
-                    launchTargetTask.group != null &&
-                    launchTargetTask.group.isTaskAboveTask(task, launchTargetTask);
-            boolean hideTask = launchTargetTask != null &&
-                    launchTargetTask.isFreeformTask() &&
-                    task.isFreeformTask();
 
             // Get the current transform for the task, which will be used to position it offscreen
             stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
                     null);
 
-            if (hideTask) {
-                tv.setVisibility(View.INVISIBLE);
-            } else if (launchState.launchedFromApp && !launchState.launchedViaDockGesture) {
+            if (launchState.launchedFromApp && !launchState.launchedViaDockGesture) {
                 if (task.isLaunchTarget) {
                     tv.onPrepareLaunchTargetForEnterAnimation();
                 } else if (isLowRamDevice && i >= taskViews.size() -
@@ -195,13 +186,6 @@
                     // com.android.server.wm.AppTransition#DEFAULT_APP_TRANSITION_DURATION}
                     mStackView.updateTaskViewToTransform(tv, mTmpTransform,
                             new AnimationProps(336, Interpolators.FAST_OUT_SLOW_IN));
-                } else if (currentTaskOccludesLaunchTarget) {
-                    // Move the task view slightly lower so we can animate it in
-                    mTmpTransform.rect.offset(0, taskViewAffiliateGroupEnterOffset);
-                    mTmpTransform.alpha = 0f;
-                    mStackView.updateTaskViewToTransform(tv, mTmpTransform,
-                            AnimationProps.IMMEDIATE);
-                    tv.setClipViewInStack(false);
                 }
             } else if (launchState.launchedFromHome) {
                 if (isLowRamDevice) {
@@ -266,9 +250,6 @@
             int taskIndexFromBack = i;
             final TaskView tv = taskViews.get(i);
             Task task = tv.getTask();
-            boolean currentTaskOccludesLaunchTarget = launchTargetTask != null &&
-                    launchTargetTask.group != null &&
-                    launchTargetTask.group.isTaskAboveTask(task, launchTargetTask);
 
             // Get the current transform for the task, which will be updated to the final transform
             // to animate to depending on how recents was invoked
@@ -280,21 +261,6 @@
                     tv.onStartLaunchTargetEnterAnimation(mTmpTransform,
                             taskViewEnterFromAppDuration, mStackView.mScreenPinningEnabled,
                             postAnimationTrigger);
-                } else {
-                    // Animate the task up if it was occluding the launch target
-                    if (currentTaskOccludesLaunchTarget) {
-                        AnimationProps taskAnimation = new AnimationProps(
-                                taskViewEnterFromAffiliatedAppDuration, Interpolators.ALPHA_IN,
-                                new AnimatorListenerAdapter() {
-                                    @Override
-                                    public void onAnimationEnd(Animator animation) {
-                                        postAnimationTrigger.decrement();
-                                        tv.setClipViewInStack(true);
-                                    }
-                                });
-                        postAnimationTrigger.increment();
-                        mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
-                    }
                 }
 
             } else if (launchState.launchedFromHome) {
@@ -423,9 +389,6 @@
         for (int i = 0; i < taskViewCount; i++) {
             TaskView tv = taskViews.get(i);
             Task task = tv.getTask();
-            boolean currentTaskOccludesLaunchTarget = launchingTask != null &&
-                    launchingTask.group != null &&
-                    launchingTask.group.isTaskAboveTask(task, launchingTask);
 
             if (tv == launchingTaskView) {
                 tv.setClipViewInStack(false);
@@ -437,17 +400,6 @@
                 });
                 tv.onStartLaunchTargetLaunchAnimation(taskViewExitToAppDuration,
                         screenPinningRequested, postAnimationTrigger);
-            } else if (currentTaskOccludesLaunchTarget) {
-                // Animate this task out of view
-                AnimationProps taskAnimation = new AnimationProps(
-                        taskViewExitToAppDuration, Interpolators.ALPHA_OUT,
-                        postAnimationTrigger.decrementOnAnimationEnd());
-                postAnimationTrigger.increment();
-
-                mTmpTransform.fillIn(tv);
-                mTmpTransform.alpha = 0f;
-                mTmpTransform.rect.offset(0, taskViewAffiliateGroupEnterOffset);
-                mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
             }
         }
     }
@@ -611,7 +563,7 @@
                 false /* ignoreTaskOverrides */, mTmpFinalTaskTransforms);
 
         // Hide the front most task view until the scroll is complete
-        Task frontMostTask = newStack.getStackFrontMostTask(false /* includeFreeform */);
+        Task frontMostTask = newStack.getStackFrontMostTask();
         final TaskView frontMostTaskView = mStackView.getChildViewForTask(frontMostTask);
         final TaskViewTransform frontMostTransform = mTmpFinalTaskTransforms.get(
                 stackTasks.indexOf(frontMostTask));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index eaa32ee..acb058c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -24,7 +24,6 @@
 import android.graphics.Rect;
 import android.util.ArraySet;
 import android.util.Log;
-import android.util.MutableFloat;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.view.ViewDebug;
@@ -36,9 +35,9 @@
 import com.android.systemui.recents.RecentsDebugFlags;
 import com.android.systemui.recents.misc.FreePathInterpolator;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.TaskStack;
 import com.android.systemui.recents.views.lowram.TaskStackLowRamLayoutAlgorithm;
 import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
 
@@ -147,75 +146,6 @@
     }
 
     /**
-     * The various stack/freeform states.
-     */
-    public static class StackState {
-
-        public static final StackState FREEFORM_ONLY = new StackState(1f, 255);
-        public static final StackState STACK_ONLY = new StackState(0f, 0);
-        public static final StackState SPLIT = new StackState(0.5f, 255);
-
-        public final float freeformHeightPct;
-        public final int freeformBackgroundAlpha;
-
-        /**
-         * @param freeformHeightPct the percentage of the stack height (not including paddings) to
-         *                          allocate to the freeform workspace
-         * @param freeformBackgroundAlpha the background alpha for the freeform workspace
-         */
-        private StackState(float freeformHeightPct, int freeformBackgroundAlpha) {
-            this.freeformHeightPct = freeformHeightPct;
-            this.freeformBackgroundAlpha = freeformBackgroundAlpha;
-        }
-
-        /**
-         * Resolves the stack state for the layout given a task stack.
-         */
-        public static StackState getStackStateForStack(TaskStack stack) {
-            SystemServicesProxy ssp = Recents.getSystemServices();
-            boolean hasFreeformWorkspaces = ssp.hasFreeformWorkspaceSupport();
-            int freeformCount = stack.getFreeformTaskCount();
-            int stackCount = stack.getStackTaskCount();
-            if (hasFreeformWorkspaces && stackCount > 0 && freeformCount > 0) {
-                return SPLIT;
-            } else if (hasFreeformWorkspaces && freeformCount > 0) {
-                return FREEFORM_ONLY;
-            } else {
-                return STACK_ONLY;
-            }
-        }
-
-        /**
-         * Computes the freeform and stack rect for this state.
-         *
-         * @param freeformRectOut the freeform rect to be written out
-         * @param stackRectOut the stack rect, we only write out the top of the stack
-         * @param taskStackBounds the full rect that the freeform rect can take up
-         */
-        public void computeRects(Rect freeformRectOut, Rect stackRectOut,
-                Rect taskStackBounds, int topMargin, int freeformGap, int stackBottomOffset) {
-            // The freeform height is the visible height (not including system insets) - padding
-            // above freeform and below stack - gap between the freeform and stack
-            int availableHeight = taskStackBounds.height() - topMargin - stackBottomOffset;
-            int ffPaddedHeight = (int) (availableHeight * freeformHeightPct);
-            int ffHeight = Math.max(0, ffPaddedHeight - freeformGap);
-            freeformRectOut.set(taskStackBounds.left,
-                    taskStackBounds.top + topMargin,
-                    taskStackBounds.right,
-                    taskStackBounds.top + topMargin + ffHeight);
-            stackRectOut.set(taskStackBounds.left,
-                    taskStackBounds.top,
-                    taskStackBounds.right,
-                    taskStackBounds.bottom);
-            if (ffPaddedHeight > 0) {
-                stackRectOut.top += ffPaddedHeight;
-            } else {
-                stackRectOut.top += topMargin;
-            }
-        }
-    }
-
-    /**
      * @return True if we should use the grid layout.
      */
     boolean useGridLayout() {
@@ -234,15 +164,11 @@
     }
 
     Context mContext;
-    private StackState mState = StackState.SPLIT;
     private TaskStackLayoutAlgorithmCallbacks mCb;
 
     // The task bounds (untransformed) for layout.  This rect is anchored at mTaskRoot.
     @ViewDebug.ExportedProperty(category="recents")
     public Rect mTaskRect = new Rect();
-    // The freeform workspace bounds, inset by the top system insets and is a fixed height
-    @ViewDebug.ExportedProperty(category="recents")
-    public Rect mFreeformRect = new Rect();
     // The stack bounds, inset from the top system insets, and runs to the bottom of the screen
     @ViewDebug.ExportedProperty(category="recents")
     public Rect mStackRect = new Rect();
@@ -268,10 +194,6 @@
     private int mBaseBottomMargin;
     private int mMinMargin;
 
-    // The gap between the freeform and stack layouts
-    @ViewDebug.ExportedProperty(category="recents")
-    private int mFreeformStackGap;
-
     // The initial offset that the focused task is from the top
     @ViewDebug.ExportedProperty(category="recents")
     private int mInitialTopOffset;
@@ -331,8 +253,6 @@
     // The last computed task counts
     @ViewDebug.ExportedProperty(category="recents")
     int mNumStackTasks;
-    @ViewDebug.ExportedProperty(category="recents")
-    int mNumFreeformTasks;
 
     // The min/max z translations
     @ViewDebug.ExportedProperty(category="recents")
@@ -344,8 +264,6 @@
     private SparseIntArray mTaskIndexMap = new SparseIntArray();
     private SparseArray<Float> mTaskIndexOverrideMap = new SparseArray<>();
 
-    // The freeform workspace layout
-    FreeformWorkspaceLayoutAlgorithm mFreeformLayoutAlgorithm;
     TaskGridLayoutAlgorithm mTaskGridLayoutAlgorithm;
     TaskStackLowRamLayoutAlgorithm mTaskStackLowRamLayoutAlgorithm;
 
@@ -356,7 +274,6 @@
     public TaskStackLayoutAlgorithm(Context context, TaskStackLayoutAlgorithmCallbacks cb) {
         mContext = context;
         mCb = cb;
-        mFreeformLayoutAlgorithm = new FreeformWorkspaceLayoutAlgorithm(context);
         mTaskGridLayoutAlgorithm = new TaskGridLayoutAlgorithm(context);
         mTaskStackLowRamLayoutAlgorithm = new TaskStackLowRamLayoutAlgorithm(context);
         reloadOnConfigurationChange(context);
@@ -393,7 +310,6 @@
                 R.dimen.recents_layout_initial_bottom_offset_tablet,
                 R.dimen.recents_layout_initial_bottom_offset_tablet,
                 R.dimen.recents_layout_initial_bottom_offset_tablet);
-        mFreeformLayoutAlgorithm.reloadOnConfigurationChange(context);
         mTaskGridLayoutAlgorithm.reloadOnConfigurationChange(context);
         mTaskStackLowRamLayoutAlgorithm.reloadOnConfigurationChange(context);
         mMinMargin = res.getDimensionPixelSize(R.dimen.recents_layout_min_margin);
@@ -408,8 +324,6 @@
                 R.dimen.recents_layout_side_margin_tablet_xlarge,
                 R.dimen.recents_layout_side_margin_tablet);
         mBaseBottomMargin = res.getDimensionPixelSize(R.dimen.recents_layout_bottom_margin);
-        mFreeformStackGap =
-                res.getDimensionPixelSize(R.dimen.recents_freeform_layout_bottom_margin);
         mTitleBarHeight = getDimensionForDevice(mContext,
                 R.dimen.recents_task_view_header_height,
                 R.dimen.recents_task_view_header_height,
@@ -462,8 +376,7 @@
      * Computes the stack and task rects.  The given task stack bounds already has the top/right
      * insets and left/right padding already applied.
      */
-    public void initialize(Rect displayRect, Rect windowRect, Rect taskStackBounds,
-            StackState state) {
+    public void initialize(Rect displayRect, Rect windowRect, Rect taskStackBounds) {
         Rect lastStackRect = new Rect(mStackRect);
 
         int topMargin = getScaleForExtent(windowRect, displayRect, mBaseTopMargin, mMinMargin, HEIGHT);
@@ -474,10 +387,9 @@
         mInitialBottomOffset = mBaseInitialBottomOffset;
 
         // Compute the stack bounds
-        mState = state;
         mStackBottomOffset = mSystemInsets.bottom + bottomMargin;
-        state.computeRects(mFreeformRect, mStackRect, taskStackBounds, topMargin,
-                mFreeformStackGap, mStackBottomOffset);
+        mStackRect.set(taskStackBounds);
+        mStackRect.top += topMargin;
 
         // The stack action button will take the full un-padded header space above the stack
         mStackActionButtonRect.set(mStackRect.left, mStackRect.top - topMargin,
@@ -530,26 +442,20 @@
         if (tasks.isEmpty()) {
             mFrontMostTaskP = 0;
             mMinScrollP = mMaxScrollP = mInitialScrollP = 0;
-            mNumStackTasks = mNumFreeformTasks = 0;
+            mNumStackTasks = 0;
             return;
         }
 
-        // Filter the set of freeform and stack tasks
-        ArrayList<Task> freeformTasks = new ArrayList<>();
+        // Filter the set of stack tasks
         ArrayList<Task> stackTasks = new ArrayList<>();
         for (int i = 0; i < tasks.size(); i++) {
             Task task = tasks.get(i);
             if (ignoreTasksSet.contains(task.key)) {
                 continue;
             }
-            if (task.isFreeformTask()) {
-                freeformTasks.add(task);
-            } else {
-                stackTasks.add(task);
-            }
+            stackTasks.add(task);
         }
         mNumStackTasks = stackTasks.size();
-        mNumFreeformTasks = freeformTasks.size();
 
         // Put each of the tasks in the progress map at a fixed index (does not need to actually
         // map to a scroll position, just by index)
@@ -559,11 +465,6 @@
             mTaskIndexMap.put(task.key.id, i);
         }
 
-        // Update the freeform tasks
-        if (!freeformTasks.isEmpty()) {
-            mFreeformLayoutAlgorithm.update(freeformTasks, this);
-        }
-
         // Calculate the min/max/initial scroll
         Task launchTask = stack.getLaunchTarget();
         int launchTaskIndex = launchTask != null
@@ -582,7 +483,7 @@
             } else {
                 mInitialScrollP = Utilities.clamp(launchTaskIndex - 1, mMinScrollP, mMaxScrollP);
             }
-        } else if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1) {
+        } else if (mNumStackTasks == 1) {
             // If there is one stack task, ignore the min/max/initial scroll positions
             mMinScrollP = 0;
             mMaxScrollP = 0;
@@ -603,9 +504,7 @@
             boolean scrollToFront = launchState.launchedFromHome || launchState.launchedFromPipApp
                     || launchState.launchedWithNextPipApp || launchState.launchedViaDockGesture;
 
-            if (launchState.launchedFromBlacklistedApp) {
-                mInitialScrollP = mMaxScrollP;
-            } else if (launchState.launchedWithAltTab) {
+            if (launchState.launchedWithAltTab) {
                 mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
             } else if (Recents.getConfiguration().isLowRamDevice) {
                 mInitialScrollP = mTaskStackLowRamLayoutAlgorithm.getInitialScrollP(mNumStackTasks,
@@ -633,7 +532,6 @@
         boolean scrollToFront = launchState.launchedFromHome ||
                 launchState.launchedFromPipApp ||
                 launchState.launchedWithNextPipApp ||
-                launchState.launchedFromBlacklistedApp ||
                 launchState.launchedViaDockGesture;
         if (getInitialFocusState() == STATE_UNFOCUSED && mNumStackTasks > 1) {
             if (ignoreScrollToFront || (!launchState.launchedWithAltTab && !scrollToFront)) {
@@ -767,7 +665,7 @@
     public int getInitialFocusState() {
         RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
         RecentsDebugFlags debugFlags = Recents.getDebugFlags();
-        if (debugFlags.isPagingEnabled() || launchState.launchedWithAltTab) {
+        if (launchState.launchedWithAltTab) {
             return STATE_FOCUSED;
         } else {
             return STATE_UNFOCUSED;
@@ -794,13 +692,6 @@
     }
 
     /**
-     * Returns the current stack state.
-     */
-    public StackState getStackState() {
-        return mState;
-    }
-
-    /**
      * Returns whether this stack layout has been initialized.
      */
     public boolean isInitialized() {
@@ -825,62 +716,44 @@
             return new VisibilityReport(1, 1);
         }
 
-        // Quick return when there are no stack tasks
-        if (mNumStackTasks == 0) {
-            return new VisibilityReport(mNumFreeformTasks > 0 ? Math.max(mNumFreeformTasks, 1) : 0,
-                    mNumFreeformTasks > 0 ? Math.max(mNumFreeformTasks, 1) : 0);
-        }
-
         // Otherwise, walk backwards in the stack and count the number of tasks and visible
-        // thumbnails and add that to the total freeform task count
+        // thumbnails and add that to the total task count
         TaskViewTransform tmpTransform = new TaskViewTransform();
         Range currentRange = getInitialFocusState() > 0f ? mFocusedRange : mUnfocusedRange;
         currentRange.offset(mInitialScrollP);
         int taskBarHeight = mContext.getResources().getDimensionPixelSize(
                 R.dimen.recents_task_view_header_height);
-        int numVisibleTasks = mNumFreeformTasks > 0 ? Math.max(mNumFreeformTasks, 1) : 0;
-        int numVisibleThumbnails = mNumFreeformTasks > 0 ? Math.max(mNumFreeformTasks, 0) : 0;
+        int numVisibleTasks = 0;
+        int numVisibleThumbnails = 0;
         float prevScreenY = Integer.MAX_VALUE;
         for (int i = tasks.size() - 1; i >= 0; i--) {
             Task task = tasks.get(i);
 
-            // Skip freeform
-            if (task.isFreeformTask()) {
-                continue;
-            }
-
             // Skip invisible
             float taskProgress = getStackScrollForTask(task);
             if (!currentRange.isInRange(taskProgress)) {
                 continue;
             }
 
-            boolean isFrontMostTaskInGroup = task.group == null || task.group.isFrontMostTask(task);
-            if (isFrontMostTaskInGroup) {
-                getStackTransform(taskProgress, taskProgress, mInitialScrollP, mFocusState,
-                        tmpTransform, null, false /* ignoreSingleTaskCase */,
-                        false /* forceUpdate */);
-                float screenY = tmpTransform.rect.top;
-                boolean hasVisibleThumbnail = (prevScreenY - screenY) > taskBarHeight;
-                if (hasVisibleThumbnail) {
-                    numVisibleThumbnails++;
-                    numVisibleTasks++;
-                    prevScreenY = screenY;
-                } else {
-                    // Once we hit the next front most task that does not have a visible thumbnail,
-                    // walk through remaining visible set
-                    for (int j = i; j >= 0; j--) {
-                        taskProgress = getStackScrollForTask(tasks.get(j));
-                        if (!currentRange.isInRange(taskProgress)) {
-                            break;
-                        }
-                        numVisibleTasks++;
-                    }
-                    break;
-                }
-            } else {
-                // Affiliated task, no thumbnail
+            getStackTransform(taskProgress, taskProgress, mInitialScrollP, mFocusState,
+                    tmpTransform, null, false /* ignoreSingleTaskCase */, false /* forceUpdate */);
+            float screenY = tmpTransform.rect.top;
+            boolean hasVisibleThumbnail = (prevScreenY - screenY) > taskBarHeight;
+            if (hasVisibleThumbnail) {
+                numVisibleThumbnails++;
                 numVisibleTasks++;
+                prevScreenY = screenY;
+            } else {
+                // Once we hit the next front most task that does not have a visible thumbnail,
+                // walk through remaining visible set
+                for (int j = i; j >= 0; j--) {
+                    taskProgress = getStackScrollForTask(tasks.get(j));
+                    if (!currentRange.isInRange(taskProgress)) {
+                        break;
+                    }
+                    numVisibleTasks++;
+                }
+                break;
             }
         }
         return new VisibilityReport(numVisibleTasks, numVisibleThumbnails);
@@ -906,10 +779,7 @@
     public TaskViewTransform getStackTransform(Task task, float stackScroll, int focusState,
             TaskViewTransform transformOut, TaskViewTransform frontTransform, boolean forceUpdate,
             boolean ignoreTaskOverrides) {
-        if (mFreeformLayoutAlgorithm.isTransformAvailable(task, this)) {
-            mFreeformLayoutAlgorithm.getTransform(task, transformOut, this);
-            return transformOut;
-        } else if (useGridLayout()) {
+        if (useGridLayout()) {
             int taskIndex = mTaskIndexMap.get(task.key.id);
             int taskCount = mTaskIndexMap.size();
             mTaskGridLayoutAlgorithm.getTransform(taskIndex, taskCount, transformOut, this);
@@ -1024,7 +894,7 @@
         float z;
         float dimAlpha;
         float viewOutlineAlpha;
-        if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1 && !ignoreSingleTaskCase) {
+        if (mNumStackTasks == 1 && !ignoreSingleTaskCase) {
             // When there is exactly one task, then decouple the task from the stack and just move
             // in screen space
             float tmpP = (mMinScrollP - stackScroll) / mNumStackTasks;
@@ -1378,7 +1248,6 @@
         writer.print("insets="); writer.print(Utilities.dumpRect(mSystemInsets));
         writer.print(" stack="); writer.print(Utilities.dumpRect(mStackRect));
         writer.print(" task="); writer.print(Utilities.dumpRect(mTaskRect));
-        writer.print(" freeform="); writer.print(Utilities.dumpRect(mFreeformRect));
         writer.print(" actionButton="); writer.print(Utilities.dumpRect(mStackActionButtonRect));
         writer.println();
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 3160ee0..428113a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -16,22 +16,15 @@
 
 package com.android.systemui.recents.views;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.annotation.IntDef;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.graphics.Canvas;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.GradientDrawable;
 import android.os.Bundle;
 import android.provider.Settings;
 import android.util.ArrayMap;
@@ -64,7 +57,6 @@
 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
 import com.android.systemui.recents.events.activity.HideStackActionButtonEvent;
-import com.android.systemui.recents.events.activity.IterateRecentsEvent;
 import com.android.systemui.recents.events.activity.LaunchMostRecentTaskRequestEvent;
 import com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent;
 import com.android.systemui.recents.events.activity.LaunchTaskEvent;
@@ -83,13 +75,11 @@
 import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
 import com.android.systemui.recents.events.ui.RecentsGrowingEvent;
 import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
-import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
 import com.android.systemui.recents.events.ui.UserInteractionEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragEndCancelledEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
-import com.android.systemui.recents.events.ui.dragndrop.DragStartInitializeDropTargetsEvent;
 import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent;
@@ -97,9 +87,10 @@
 import com.android.systemui.recents.misc.DozeTrigger;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.utilities.AnimationProps;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.TaskStack;
 import com.android.systemui.recents.views.grid.GridTaskView;
 import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
 import com.android.systemui.recents.views.grid.TaskViewFocusFrame;
@@ -153,8 +144,6 @@
     @ViewDebug.ExportedProperty(deepExport=true, prefix="touch_")
     private TaskStackViewTouchHandler mTouchHandler;
     private TaskStackAnimationHelper mAnimationHelper;
-    private GradientDrawable mFreeformWorkspaceBackground;
-    private ObjectAnimator mFreeformWorkspaceBackgroundAnimator;
     private ViewPool<TaskView, Task> mViewPool;
 
     private ArrayList<TaskView> mTaskViews = new ArrayList<>();
@@ -239,20 +228,6 @@
                 }
             };
 
-    // The drop targets for a task drag
-    private DropTarget mFreeformWorkspaceDropTarget = new DropTarget() {
-        @Override
-        public boolean acceptsDrop(int x, int y, int width, int height, Rect insets,
-                boolean isCurrentTarget) {
-            // This drop target has a fixed bounds and should be checked last, so just fall through
-            // if it is the current target
-            if (!isCurrentTarget) {
-                return mLayoutAlgorithm.mFreeformRect.contains(x, y);
-            }
-            return false;
-        }
-    };
-
     private DropTarget mStackDropTarget = new DropTarget() {
         @Override
         public boolean acceptsDrop(int x, int y, int width, int height, Rect insets,
@@ -312,17 +287,6 @@
             }
         });
         setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
-        if (ssp.hasFreeformWorkspaceSupport()) {
-            setWillNotDraw(false);
-        }
-
-        mFreeformWorkspaceBackground = (GradientDrawable) getContext().getDrawable(
-                R.drawable.recents_freeform_workspace_bg);
-        mFreeformWorkspaceBackground.setCallback(this);
-        if (ssp.hasFreeformWorkspaceSupport()) {
-            mFreeformWorkspaceBackground.setColor(
-                    getContext().getColor(R.color.recents_freeform_workspace_bg_color));
-        }
     }
 
     @Override
@@ -359,12 +323,7 @@
         readSystemFlags();
         mTaskViewsClipDirty = true;
         mUIDozeTrigger.stopDozing();
-        if (isResumingFromVisible) {
-            // Animate in the freeform workspace
-            int ffBgAlpha = mLayoutAlgorithm.getStackState().freeformBackgroundAlpha;
-            animateFreeformWorkspaceBackgroundAlpha(ffBgAlpha, new AnimationProps(150,
-                    Interpolators.FAST_OUT_SLOW_IN));
-        } else {
+        if (!isResumingFromVisible) {
             mStackScroller.reset();
             mStableLayoutAlgorithm.reset();
             mLayoutAlgorithm.reset();
@@ -387,7 +346,7 @@
 
         // Only notify if we are already initialized, otherwise, everything will pick up all the
         // new and old tasks when we next layout
-        mStack.setTasks(getContext(), stack, allowNotifyStackChanges && isInitialized);
+        mStack.setTasks(stack, allowNotifyStackChanges && isInitialized);
     }
 
     /** Returns the task stack. */
@@ -422,23 +381,13 @@
 
     /**
      * Returns the front most task view.
-     *
-     * @param stackTasksOnly if set, will return the front most task view in the stack (by default
-     *                       the front most task view will be freeform since they are placed above
-     *                       stack tasks)
      */
-    private TaskView getFrontMostTaskView(boolean stackTasksOnly) {
+    private TaskView getFrontMostTaskView() {
         List<TaskView> taskViews = getTaskViews();
-        int taskViewCount = taskViews.size();
-        for (int i = taskViewCount - 1; i >= 0; i--) {
-            TaskView tv = taskViews.get(i);
-            Task task = tv.getTask();
-            if (stackTasksOnly && task.isFreeformTask()) {
-                continue;
-            }
-            return tv;
+        if (taskViews.isEmpty()) {
+            return null;
         }
-        return null;
+        return taskViews.get(taskViews.size() - 1);
     }
 
     /**
@@ -500,8 +449,6 @@
      * visible range includes all tasks at the target stack scroll. This is useful for ensure that
      * all views necessary for a transition or animation will be visible at the start.
      *
-     * This call ignores freeform tasks.
-     *
      * @param taskTransforms The set of task view transforms to reuse, this list will be sized to
      *                       match the size of {@param tasks}
      * @param tasks The set of tasks for which to generate transforms
@@ -524,7 +471,7 @@
         boolean useTargetStackScroll = Float.compare(curStackScroll, targetStackScroll) != 0;
 
         // We can reuse the task transforms where possible to reduce object allocation
-        Utilities.matchTaskListSize(tasks, taskTransforms);
+        matchTaskListSize(tasks, taskTransforms);
 
         // Update the stack transforms
         TaskViewTransform frontTransform = null;
@@ -554,12 +501,6 @@
                 continue;
             }
 
-            // For freeform tasks, only calculate the stack transform and skip the calculation of
-            // the visible stack indices
-            if (task.isFreeformTask()) {
-                continue;
-            }
-
             frontTransform = transform;
             frontTransformAtTarget = transformAtTarget;
             if (transform.visible) {
@@ -622,7 +563,7 @@
                 transform = mCurrentTaskTransforms.get(taskIndex);
             }
 
-            if (task.isFreeformTask() || (transform != null && transform.visible)) {
+            if (transform != null && transform.visible) {
                 mTmpTaskViewMap.put(task.key, tv);
             } else {
                 if (mTouchExplorationEnabled && Utilities.isDescendentAccessibilityFocused(tv)) {
@@ -643,24 +584,20 @@
                 continue;
             }
 
-            // Skip the invisible non-freeform stack tasks
-            if (!task.isFreeformTask() && !transform.visible) {
+            // Skip the invisible stack tasks
+            if (!transform.visible) {
                 continue;
             }
 
             TaskView tv = mTmpTaskViewMap.get(task.key);
             if (tv == null) {
                 tv = mViewPool.pickUpViewFromPool(task, task);
-                if (task.isFreeformTask()) {
-                    updateTaskViewToTransform(tv, transform, AnimationProps.IMMEDIATE);
+                if (transform.rect.top <= mLayoutAlgorithm.mStackRect.top) {
+                    updateTaskViewToTransform(tv, mLayoutAlgorithm.getBackOfStackTransform(),
+                            AnimationProps.IMMEDIATE);
                 } else {
-                    if (transform.rect.top <= mLayoutAlgorithm.mStackRect.top) {
-                        updateTaskViewToTransform(tv, mLayoutAlgorithm.getBackOfStackTransform(),
-                                AnimationProps.IMMEDIATE);
-                    } else {
-                        updateTaskViewToTransform(tv, mLayoutAlgorithm.getFrontOfStackTransform(),
-                                AnimationProps.IMMEDIATE);
-                    }
+                    updateTaskViewToTransform(tv, mLayoutAlgorithm.getFrontOfStackTransform(),
+                            AnimationProps.IMMEDIATE);
                 }
             } else {
                 // Reattach it in the right z order
@@ -764,7 +701,7 @@
      */
     public void getCurrentTaskTransforms(ArrayList<Task> tasks,
             ArrayList<TaskViewTransform> transformsOut) {
-        Utilities.matchTaskListSize(tasks, transformsOut);
+        matchTaskListSize(tasks, transformsOut);
         int focusState = mLayoutAlgorithm.getFocusState();
         for (int i = tasks.size() - 1; i >= 0; i--) {
             Task task = tasks.get(i);
@@ -787,7 +724,7 @@
      */
     public void getLayoutTaskTransforms(float stackScroll, int focusState, ArrayList<Task> tasks,
             boolean ignoreTaskOverrides, ArrayList<TaskViewTransform> transformsOut) {
-        Utilities.matchTaskListSize(tasks, transformsOut);
+        matchTaskListSize(tasks, transformsOut);
         for (int i = tasks.size() - 1; i >= 0; i--) {
             Task task = tasks.get(i);
             TaskViewTransform transform = transformsOut.get(i);
@@ -887,13 +824,6 @@
         // Compute the min and max scroll values
         mLayoutAlgorithm.update(mStack, mIgnoreTasks, launchState);
 
-        // Update the freeform workspace background
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        if (ssp.hasFreeformWorkspaceSupport()) {
-            mTmpRect.set(mLayoutAlgorithm.mFreeformRect);
-            mFreeformWorkspaceBackground.setBounds(mTmpRect);
-        }
-
         if (boundScrollToNewMinMax) {
             mStackScroller.boundScroll();
         }
@@ -906,8 +836,7 @@
         mWindowRect.set(mStableWindowRect);
         mStackBounds.set(mStableStackBounds);
         mLayoutAlgorithm.setSystemInsets(mStableLayoutAlgorithm.mSystemInsets);
-        mLayoutAlgorithm.initialize(mDisplayRect, mWindowRect, mStackBounds,
-                TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
+        mLayoutAlgorithm.initialize(mDisplayRect, mWindowRect, mStackBounds);
         updateLayoutAlgorithm(true /* boundScroll */);
     }
 
@@ -1028,21 +957,10 @@
         if (focusedTask != null) {
             if (stackTasksOnly) {
                 List<Task> tasks =  mStack.getStackTasks();
-                if (focusedTask.isFreeformTask()) {
-                    // Try and focus the front most stack task
-                    TaskView tv = getFrontMostTaskView(stackTasksOnly);
-                    if (tv != null) {
-                        newIndex = mStack.indexOfStackTask(tv.getTask());
-                    }
-                } else {
-                    // Try the next task if it is a stack task
-                    int tmpNewIndex = newIndex + (forward ? -1 : 1);
-                    if (0 <= tmpNewIndex && tmpNewIndex < tasks.size()) {
-                        Task t = tasks.get(tmpNewIndex);
-                        if (!t.isFreeformTask()) {
-                            newIndex = tmpNewIndex;
-                        }
-                    }
+                // Try the next task if it is a stack task
+                int tmpNewIndex = newIndex + (forward ? -1 : 1);
+                if (0 <= tmpNewIndex && tmpNewIndex < tasks.size()) {
+                    newIndex = tmpNewIndex;
                 }
             } else {
                 // No restrictions, lets just move to the new task (looping forward/backwards if
@@ -1127,7 +1045,7 @@
                 return tv.getTask();
             }
         }
-        TaskView frontTv = getFrontMostTaskView(true /* stackTasksOnly */);
+        TaskView frontTv = getFrontMostTaskView();
         if (frontTv != null) {
             return frontTv.getTask();
         }
@@ -1278,10 +1196,8 @@
         }
 
         // Compute the rects in the stack algorithm
-        mStableLayoutAlgorithm.initialize(mDisplayRect, mStableWindowRect, mStableStackBounds,
-                TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
-        mLayoutAlgorithm.initialize(mDisplayRect, mWindowRect, mStackBounds,
-                TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
+        mStableLayoutAlgorithm.initialize(mDisplayRect, mStableWindowRect, mStableStackBounds);
+        mLayoutAlgorithm.initialize(mDisplayRect, mWindowRect, mStackBounds);
         updateLayoutAlgorithm(false /* boundScroll */);
 
         // If this is the first layout, then scroll to the front of the stack, then update the
@@ -1404,11 +1320,6 @@
         // Setup the view for the enter animation
         mAnimationHelper.prepareForEnterAnimation();
 
-        // Animate in the freeform workspace
-        int ffBgAlpha = mLayoutAlgorithm.getStackState().freeformBackgroundAlpha;
-        animateFreeformWorkspaceBackgroundAlpha(ffBgAlpha, new AnimationProps(150,
-                Interpolators.FAST_OUT_SLOW_IN));
-
         // Set the task focused state without requesting view focus, and leave the focus animations
         // until after the enter-animation
         RecentsConfiguration config = Recents.getConfiguration();
@@ -1456,43 +1367,6 @@
         return null;
     }
 
-    @Override
-    protected void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-
-        // Draw the freeform workspace background
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        if (ssp.hasFreeformWorkspaceSupport()) {
-            if (mFreeformWorkspaceBackground.getAlpha() > 0) {
-                mFreeformWorkspaceBackground.draw(canvas);
-            }
-        }
-    }
-
-    @Override
-    protected boolean verifyDrawable(Drawable who) {
-        if (who == mFreeformWorkspaceBackground) {
-            return true;
-        }
-        return super.verifyDrawable(who);
-    }
-
-    /**
-     * Launches the freeform tasks.
-     */
-    public boolean launchFreeformTasks() {
-        ArrayList<Task> tasks = mStack.getFreeformTasks();
-        if (!tasks.isEmpty()) {
-            Task frontTask = tasks.get(tasks.size() - 1);
-            if (frontTask != null && frontTask.isFreeformTask()) {
-                EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(frontTask),
-                        frontTask, null, false));
-                return true;
-            }
-        }
-        return false;
-    }
-
     /**** TaskStackCallbacks Implementation ****/
 
     @Override
@@ -1671,8 +1545,7 @@
         }
 
         // Restore the action button visibility if it is the front most task view
-        if (mScreenPinningEnabled && tv.getTask() ==
-                mStack.getStackFrontMostTask(false /* includeFreeform */)) {
+        if (mScreenPinningEnabled && tv.getTask() == mStack.getStackFrontMostTask()) {
             tv.showActionButton(false /* fadeIn */, 0 /* fadeInDuration */);
         }
     }
@@ -1688,7 +1561,6 @@
 
         // If the doze trigger has already fired, then update the state for this task view
         if (mUIDozeTrigger.isAsleep() ||
-                Recents.getSystemServices().hasFreeformWorkspaceSupport() ||
                 useGridLayout() || Recents.getConfiguration().isLowRamDevice) {
             tv.setNoUserInteractionState();
         }
@@ -1820,21 +1692,17 @@
 
     public final void onBusEvent(LaunchMostRecentTaskRequestEvent event) {
         if (mStack.getTaskCount() > 0) {
-            Task mostRecentTask = mStack.getStackFrontMostTask(true /* includeFreefromTasks */);
+            Task mostRecentTask = mStack.getStackFrontMostTask();
             launchTask(mostRecentTask);
         }
     }
 
     public final void onBusEvent(ShowStackActionButtonEvent event) {
-        if (RecentsDebugFlags.Static.EnableStackActionButton) {
-            mStackActionButtonVisible = true;
-        }
+        mStackActionButtonVisible = true;
     }
 
     public final void onBusEvent(HideStackActionButtonEvent event) {
-        if (RecentsDebugFlags.Static.EnableStackActionButton) {
-            mStackActionButtonVisible = false;
-        }
+        mStackActionButtonVisible = false;
     }
 
     public final void onBusEvent(LaunchNextTaskRequestEvent event) {
@@ -1891,11 +1759,6 @@
         // Start the task animations
         mAnimationHelper.startExitToHomeAnimation(event.animated, event.getAnimationTrigger());
 
-        // Dismiss the freeform workspace background
-        int taskViewExitToHomeDuration = TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION;
-        animateFreeformWorkspaceBackgroundAlpha(0, new AnimationProps(taskViewExitToHomeDuration,
-                Interpolators.FAST_OUT_SLOW_IN));
-
         // Dismiss the grid task view focus frame
         if (mTaskViewFocusFrame != null) {
             mTaskViewFocusFrame.moveGridTaskViewFocus(null);
@@ -1977,8 +1840,7 @@
         mStackScroller.stopScroller();
         mStackScroller.stopBoundScrollAnimation();
 
-        setRelativeFocusedTask(true, false /* stackTasksOnly */, true /* animated */, false,
-                event.timerIndicatorDuration);
+        setRelativeFocusedTask(true, false /* stackTasksOnly */, true /* animated */, false, 0);
     }
 
     public final void onBusEvent(FocusPreviousTaskViewEvent event) {
@@ -2002,8 +1864,7 @@
                     EventBus.getDefault().send(new FocusPreviousTaskViewEvent());
                     break;
                 case DOWN:
-                    EventBus.getDefault().send(
-                        new FocusNextTaskViewEvent(0 /* timerIndicatorDuration */));
+                    EventBus.getDefault().send(new FocusNextTaskViewEvent());
                     break;
             }
         }
@@ -2014,7 +1875,7 @@
         mUIDozeTrigger.poke();
 
         RecentsDebugFlags debugFlags = Recents.getDebugFlags();
-        if (debugFlags.isFastToggleRecentsEnabled() && mFocusedTask != null) {
+        if (mFocusedTask != null) {
             TaskView tv = getChildViewForTask(mFocusedTask);
             if (tv != null) {
                 tv.getHeaderView().cancelFocusTimerIndicator();
@@ -2026,11 +1887,6 @@
         // Ensure that the drag task is not animated
         addIgnoreTask(event.task);
 
-        if (event.task.isFreeformTask()) {
-            // Animate to the front of the stack
-            mStackScroller.animateScroll(mLayoutAlgorithm.mInitialScrollP, null);
-        }
-
         // Enlarge the dragged view slightly
         float finalScale = event.taskView.getScaleX() * DRAG_SCALE_FACTOR;
         mLayoutAlgorithm.getStackTransform(event.task, getScroller().getStackScroll(),
@@ -2042,22 +1898,14 @@
                 new AnimationProps(DRAG_SCALE_DURATION, Interpolators.FAST_OUT_SLOW_IN));
     }
 
-    public final void onBusEvent(DragStartInitializeDropTargetsEvent event) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        if (ssp.hasFreeformWorkspaceSupport()) {
-            event.handler.registerDropTargetForCurrentDrag(mStackDropTarget);
-            event.handler.registerDropTargetForCurrentDrag(mFreeformWorkspaceDropTarget);
-        }
-    }
-
     public final void onBusEvent(DragDropTargetChangedEvent event) {
         AnimationProps animation = new AnimationProps(SLOW_SYNC_STACK_DURATION,
                 Interpolators.FAST_OUT_SLOW_IN);
         boolean ignoreTaskOverrides = false;
-        if (event.dropTarget instanceof TaskStack.DockState) {
+        if (event.dropTarget instanceof DockState) {
             // Calculate the new task stack bounds that matches the window size that Recents will
             // have after the drop
-            final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
+            final DockState dockState = (DockState) event.dropTarget;
             Rect systemInsets = new Rect(mStableLayoutAlgorithm.mSystemInsets);
             // When docked, the nav bar insets are consumed and the activity is measured without
             // insets.  However, the window bounds include the insets, so we need to subtract them
@@ -2069,8 +1917,7 @@
                     height, mDividerSize, systemInsets,
                     mLayoutAlgorithm, getResources(), mWindowRect));
             mLayoutAlgorithm.setSystemInsets(systemInsets);
-            mLayoutAlgorithm.initialize(mDisplayRect, mWindowRect, mStackBounds,
-                    TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
+            mLayoutAlgorithm.initialize(mDisplayRect, mWindowRect, mStackBounds);
             updateLayoutAlgorithm(true /* boundScroll */);
             ignoreTaskOverrides = true;
         } else {
@@ -2085,39 +1932,13 @@
 
     public final void onBusEvent(final DragEndEvent event) {
         // We don't handle drops on the dock regions
-        if (event.dropTarget instanceof TaskStack.DockState) {
+        if (event.dropTarget instanceof DockState) {
             // However, we do need to reset the overrides, since the last state of this task stack
             // view layout was ignoring task overrides (see DragDropTargetChangedEvent handler)
             mLayoutAlgorithm.clearUnfocusedTaskOverrides();
             return;
         }
 
-        boolean isFreeformTask = event.task.isFreeformTask();
-        boolean hasChangedWindowingMode =
-                (!isFreeformTask && event.dropTarget == mFreeformWorkspaceDropTarget) ||
-                        (isFreeformTask && event.dropTarget == mStackDropTarget);
-
-        if (hasChangedWindowingMode) {
-            // Move the task to the right position in the stack (ie. the front of the stack if
-            // freeform or the front of the stack if fullscreen). Note, we MUST move the tasks
-            // before we update their stack ids, otherwise, the keys will have changed.
-            if (event.dropTarget == mFreeformWorkspaceDropTarget) {
-                mStack.setTaskWindowingMode(event.task, WINDOWING_MODE_FREEFORM);
-            } else if (event.dropTarget == mStackDropTarget) {
-                mStack.setTaskWindowingMode(event.task, WINDOWING_MODE_FULLSCREEN);
-            }
-            updateLayoutAlgorithm(true /* boundScroll */);
-
-            // Move the task to the new stack in the system after the animation completes
-            event.addPostAnimationCallback(new Runnable() {
-                @Override
-                public void run() {
-                    SystemServicesProxy ssp = Recents.getSystemServices();
-                    ssp.setTaskWindowingMode(event.task.key.id, event.task.key.windowingMode);
-                }
-            });
-        }
-
         // Restore the task, so that relayout will apply to it below
         removeIgnoreTask(event.task);
 
@@ -2152,13 +1973,6 @@
         event.getAnimationTrigger().increment();
     }
 
-    public final void onBusEvent(IterateRecentsEvent event) {
-        if (!mEnterAnimationComplete) {
-            // Cancel the previous task's window transition before animating the focused state
-            EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null));
-        }
-    }
-
     public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
         mEnterAnimationComplete = true;
         tryStartEnterAnimation();
@@ -2177,9 +1991,7 @@
             // Add a runnable to the post animation ref counter to clear all the views
             trigger.addLastDecrementRunnable(() -> {
                 // Start the dozer to trigger to trigger any UI that shows after a timeout
-                if (!Recents.getSystemServices().hasFreeformWorkspaceSupport()) {
-                    mUIDozeTrigger.startDozing();
-                }
+                mUIDozeTrigger.startDozing();
 
                 // Update the focused state here -- since we only set the focused task without
                 // requesting view focus in onFirstLayout(), actually request view focus and
@@ -2202,18 +2014,6 @@
         mStackReloaded = false;
     }
 
-    public final void onBusEvent(UpdateFreeformTaskViewVisibilityEvent event) {
-        List<TaskView> taskViews = getTaskViews();
-        int taskViewCount = taskViews.size();
-        for (int i = 0; i < taskViewCount; i++) {
-            TaskView tv = taskViews.get(i);
-            Task task = tv.getTask();
-            if (task.isFreeformTask()) {
-                tv.setVisibility(event.visible ? View.VISIBLE : View.INVISIBLE);
-            }
-        }
-    }
-
     public final void onBusEvent(final MultiWindowStateChangedEvent event) {
         if (event.inMultiWindow || !event.showDeferredAnimation) {
             setTasks(event.stack, true /* allowNotifyStackChanges */);
@@ -2315,27 +2115,6 @@
     }
 
     /**
-     * Starts an alpha animation on the freeform workspace background.
-     */
-    private void animateFreeformWorkspaceBackgroundAlpha(int targetAlpha,
-            AnimationProps animation) {
-        if (mFreeformWorkspaceBackground.getAlpha() == targetAlpha) {
-            return;
-        }
-
-        Utilities.cancelAnimationWithoutCallbacks(mFreeformWorkspaceBackgroundAnimator);
-        mFreeformWorkspaceBackgroundAnimator = ObjectAnimator.ofInt(mFreeformWorkspaceBackground,
-                Utilities.DRAWABLE_ALPHA, mFreeformWorkspaceBackground.getAlpha(), targetAlpha);
-        mFreeformWorkspaceBackgroundAnimator.setStartDelay(
-                animation.getDuration(AnimationProps.ALPHA));
-        mFreeformWorkspaceBackgroundAnimator.setDuration(
-                animation.getDuration(AnimationProps.ALPHA));
-        mFreeformWorkspaceBackgroundAnimator.setInterpolator(
-                animation.getInterpolator(AnimationProps.ALPHA));
-        mFreeformWorkspaceBackgroundAnimator.start();
-    }
-
-    /**
      * Returns the insert index for the task in the current set of task views. If the given task
      * is already in the task view list, then this method returns the insert index assuming it
      * is first removed at the previous index.
@@ -2421,6 +2200,24 @@
         }
     }
 
+    /**
+     * Updates {@param transforms} to be the same size as {@param tasks}.
+     */
+    private void matchTaskListSize(List<Task> tasks, List<TaskViewTransform> transforms) {
+        // We can reuse the task transforms where possible to reduce object allocation
+        int taskTransformCount = transforms.size();
+        int taskCount = tasks.size();
+        if (taskTransformCount < taskCount) {
+            // If there are less transforms than tasks, then add as many transforms as necessary
+            for (int i = taskTransformCount; i < taskCount; i++) {
+                transforms.add(new TaskViewTransform());
+            }
+        } else if (taskTransformCount > taskCount) {
+            // If there are more transforms than tasks, then just subset the transform list
+            transforms.subList(taskCount, taskTransformCount).clear();
+        }
+    }
+
     public void dump(String prefix, PrintWriter writer) {
         String innerPrefix = prefix + "  ";
         String id = Integer.toHexString(System.identityHashCode(this));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index 0b20b10..6b23977 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -24,7 +24,6 @@
 import android.content.Context;
 import android.util.FloatProperty;
 import android.util.Log;
-import android.util.MutableFloat;
 import android.util.Property;
 import android.view.ViewConfiguration;
 import android.view.ViewDebug;
@@ -33,7 +32,8 @@
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.misc.Utilities;
+import com.android.systemui.shared.recents.utilities.AnimationProps;
+import com.android.systemui.shared.recents.utilities.Utilities;
 import com.android.systemui.recents.views.lowram.TaskStackLowRamLayoutAlgorithm;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 32a249c..b9ca248 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Path;
-import android.graphics.Rect;
 import android.util.ArrayMap;
 import android.util.MutableBoolean;
 import android.view.InputDevice;
@@ -45,9 +44,9 @@
 import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
 import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
 import com.android.systemui.recents.misc.FreePathInterpolator;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.utilities.AnimationProps;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 
 import java.util.ArrayList;
@@ -403,18 +402,6 @@
             return;
         }
 
-        // If tapping on the freeform workspace background, just launch the first freeform task
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        if (ssp.hasFreeformWorkspaceSupport()) {
-            Rect freeformRect = mSv.mLayoutAlgorithm.mFreeformRect;
-            if (freeformRect.top <= y && y <= freeformRect.bottom) {
-                if (mSv.launchFreeformTasks()) {
-                    // TODO: Animate Recents away as we launch the freeform tasks
-                    return;
-                }
-            }
-        }
-
         // The user intentionally tapped on the background, which is like a tap on the "desktop".
         // Hide recents and transition to the launcher.
         EventBus.getDefault().send(new HideRecentsEvent(false, true));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 032d966..b440847 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -51,10 +51,10 @@
 import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.recents.model.ThumbnailData;
+import com.android.systemui.shared.recents.utilities.AnimationProps;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.ThumbnailData;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -194,9 +194,7 @@
      * Called from RecentsActivity when it is relaunched.
      */
     void onReload(boolean isResumingFromVisible) {
-        if (!Recents.getSystemServices().hasFreeformWorkspaceSupport()) {
-            resetNoUserInteractionState();
-        }
+        resetNoUserInteractionState();
         if (!isResumingFromVisible) {
             resetViewProperties();
         }
@@ -413,9 +411,7 @@
      * view.
      */
     boolean shouldClipViewInStack() {
-        // Never clip for freeform tasks or if invisible
-        if (mTask.isFreeformTask() || getVisibility() != View.VISIBLE ||
-                Recents.getConfiguration().isLowRamDevice) {
+        if (getVisibility() != View.VISIBLE || Recents.getConfiguration().isLowRamDevice) {
             return false;
         }
         return mClipViewInStack;
@@ -713,7 +709,7 @@
     /**** Events ****/
 
     public final void onBusEvent(DragEndEvent event) {
-        if (!(event.dropTarget instanceof TaskStack.DockState)) {
+        if (!(event.dropTarget instanceof DockState)) {
             event.addPostAnimationCallback(() -> {
                 // Reset the clip state for the drag view after the end animation completes
                 setClipViewInStack(true);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java
index 0c6b6b8..0fc507b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java
@@ -28,11 +28,10 @@
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.TaskStack;
 
 public class TaskViewAccessibilityDelegate extends View.AccessibilityDelegate {
     private static final String TAG = "TaskViewAccessibilityDelegate";
@@ -61,14 +60,14 @@
         super.onInitializeAccessibilityNodeInfo(host, info);
         if (ActivityManager.supportsSplitScreenMultiWindow(mTaskView.getContext())
                 && !Recents.getSystemServices().hasDockedTask()) {
-            TaskStack.DockState[] dockStates = Recents.getConfiguration()
+            DockState[] dockStates = Recents.getConfiguration()
                     .getDockStatesForCurrentOrientation();
-            for (TaskStack.DockState dockState: dockStates) {
-                if (dockState == TaskStack.DockState.TOP) {
+            for (DockState dockState: dockStates) {
+                if (dockState == DockState.TOP) {
                     info.addAction(mActions.get(SPLIT_TASK_TOP));
-                } else if (dockState == TaskStack.DockState.LEFT) {
+                } else if (dockState == DockState.LEFT) {
                     info.addAction(mActions.get(SPLIT_TASK_LEFT));
-                } else if (dockState == TaskStack.DockState.RIGHT) {
+                } else if (dockState == DockState.RIGHT) {
                     info.addAction(mActions.get(SPLIT_TASK_RIGHT));
                 }
             }
@@ -78,11 +77,11 @@
     @Override
     public boolean performAccessibilityAction(View host, int action, Bundle args) {
         if (action == SPLIT_TASK_TOP) {
-            simulateDragIntoMultiwindow(TaskStack.DockState.TOP);
+            simulateDragIntoMultiwindow(DockState.TOP);
         } else if (action == SPLIT_TASK_LEFT) {
-            simulateDragIntoMultiwindow(TaskStack.DockState.LEFT);
+            simulateDragIntoMultiwindow(DockState.LEFT);
         } else if (action == SPLIT_TASK_RIGHT) {
-            simulateDragIntoMultiwindow(TaskStack.DockState.RIGHT);
+            simulateDragIntoMultiwindow(DockState.RIGHT);
         } else {
             return super.performAccessibilityAction(host, action, args);
         }
@@ -90,8 +89,7 @@
     }
 
     /** Simulate a user drag event to split the screen to the respected side */
-    private void simulateDragIntoMultiwindow(TaskStack.DockState dockState) {
-        int orientation = Utilities.getAppConfiguration(mTaskView.getContext()).orientation;
+    private void simulateDragIntoMultiwindow(DockState dockState) {
         EventBus.getDefault().send(new DragStartEvent(mTaskView.getTask(), mTaskView,
                 new Point(0,0), false /* isUserTouchInitiated */));
         EventBus.getDefault().send(new DragEndEvent(mTaskView.getTask(), mTaskView, dockState));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 198ecae..0272a90 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -17,8 +17,6 @@
 package com.android.systemui.recents.views;
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 
 import android.animation.Animator;
@@ -33,7 +31,6 @@
 import android.graphics.ColorFilter;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.RippleDrawable;
@@ -59,8 +56,10 @@
 import com.android.systemui.recents.events.activity.LaunchTaskEvent;
 import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.PackageManagerWrapper;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.Task;
 
 /* The task bar view */
 public class TaskViewHeader extends FrameLayout
@@ -164,8 +163,6 @@
     float mDimAlpha;
     Drawable mLightDismissDrawable;
     Drawable mDarkDismissDrawable;
-    Drawable mLightFreeformIcon;
-    Drawable mDarkFreeformIcon;
     Drawable mLightFullscreenIcon;
     Drawable mDarkFullscreenIcon;
     Drawable mLightInfoIcon;
@@ -173,6 +170,8 @@
     int mTaskBarViewLightTextColor;
     int mTaskBarViewDarkTextColor;
     int mDisabledTaskBarBackgroundColor;
+    String mDismissDescFormat;
+    String mAppInfoDescFormat;
     int mTaskWindowingMode = WINDOWING_MODE_UNDEFINED;
 
     // Header background
@@ -215,14 +214,15 @@
         mHighlightHeight = res.getDimensionPixelSize(R.dimen.recents_task_view_highlight);
         mTaskBarViewLightTextColor = context.getColor(R.color.recents_task_bar_light_text_color);
         mTaskBarViewDarkTextColor = context.getColor(R.color.recents_task_bar_dark_text_color);
-        mLightFreeformIcon = context.getDrawable(R.drawable.recents_move_task_freeform_light);
-        mDarkFreeformIcon = context.getDrawable(R.drawable.recents_move_task_freeform_dark);
         mLightFullscreenIcon = context.getDrawable(R.drawable.recents_move_task_fullscreen_light);
         mDarkFullscreenIcon = context.getDrawable(R.drawable.recents_move_task_fullscreen_dark);
         mLightInfoIcon = context.getDrawable(R.drawable.recents_info_light);
         mDarkInfoIcon = context.getDrawable(R.drawable.recents_info_dark);
         mDisabledTaskBarBackgroundColor =
                 context.getColor(R.color.recents_task_bar_disabled_background_color);
+        mDismissDescFormat = mContext.getString(
+                R.string.accessibility_recents_item_will_be_dismissed);
+        mAppInfoDescFormat = mContext.getString(R.string.accessibility_recents_item_open_app_info);
 
         // Configure the background and dim
         mBackground = new HighlightColorDrawable();
@@ -249,9 +249,6 @@
         mIconView.setOnLongClickListener(this);
         mTitleView = findViewById(R.id.title);
         mDismissButton = findViewById(R.id.dismiss_task);
-        if (ssp.hasFreeformWorkspaceSupport()) {
-            mMoveTaskButton = findViewById(R.id.move_task);
-        }
 
         onConfigurationChanged();
     }
@@ -341,20 +338,6 @@
         boolean showDismissIcon = true;
         int rightInset = width - getMeasuredWidth();
 
-        if (mTask != null && mTask.isFreeformTask()) {
-            // For freeform tasks, we always show the app icon, and only show the title, move-task
-            // icon, and the dismiss icon if there is room
-            int appIconWidth = mIconView.getMeasuredWidth();
-            int titleWidth = (int) mTitleView.getPaint().measureText(mTask.title);
-            int dismissWidth = mDismissButton.getMeasuredWidth();
-            int moveTaskWidth = mMoveTaskButton != null
-                    ? mMoveTaskButton.getMeasuredWidth()
-                    : 0;
-            showTitle = width >= (appIconWidth + dismissWidth + moveTaskWidth + titleWidth);
-            showMoveIcon = width >= (appIconWidth + dismissWidth + moveTaskWidth);
-            showDismissIcon = width >= (appIconWidth + dismissWidth);
-        }
-
         mTitleView.setVisibility(showTitle ? View.VISIBLE : View.INVISIBLE);
         if (mMoveTaskButton != null) {
             mMoveTaskButton.setVisibility(showMoveIcon ? View.VISIBLE : View.INVISIBLE);
@@ -477,44 +460,14 @@
                 mTaskBarViewLightTextColor : mTaskBarViewDarkTextColor);
         mDismissButton.setImageDrawable(t.useLightOnPrimaryColor ?
                 mLightDismissDrawable : mDarkDismissDrawable);
-        mDismissButton.setContentDescription(t.dismissDescription);
+        mDismissButton.setContentDescription(String.format(mDismissDescFormat, t.titleDescription));
         mDismissButton.setOnClickListener(this);
         mDismissButton.setClickable(false);
         ((RippleDrawable) mDismissButton.getBackground()).setForceSoftware(true);
 
-        // When freeform workspaces are enabled, then update the move-task button depending on the
-        // current task
-        if (mMoveTaskButton != null) {
-            if (t.isFreeformTask()) {
-                mTaskWindowingMode = WINDOWING_MODE_FULLSCREEN;
-                mMoveTaskButton.setImageDrawable(t.useLightOnPrimaryColor
-                        ? mLightFullscreenIcon
-                        : mDarkFullscreenIcon);
-            } else {
-                mTaskWindowingMode = WINDOWING_MODE_FREEFORM;
-                mMoveTaskButton.setImageDrawable(t.useLightOnPrimaryColor
-                        ? mLightFreeformIcon
-                        : mDarkFreeformIcon);
-            }
-            mMoveTaskButton.setOnClickListener(this);
-            mMoveTaskButton.setClickable(false);
-            ((RippleDrawable) mMoveTaskButton.getBackground()).setForceSoftware(true);
-        }
-
-        if (Recents.getDebugFlags().isFastToggleRecentsEnabled()) {
-            if (mFocusTimerIndicator == null) {
-                mFocusTimerIndicator = (ProgressBar) Utilities.findViewStubById(this,
-                        R.id.focus_timer_indicator_stub).inflate();
-            }
-            mFocusTimerIndicator.getProgressDrawable()
-                    .setColorFilter(
-                            getSecondaryColor(t.colorPrimary, t.useLightOnPrimaryColor),
-                            PorterDuff.Mode.SRC_IN);
-        }
-
         // In accessibility, a single click on the focused app info button will show it
         if (touchExplorationEnabled) {
-            mIconView.setContentDescription(t.appInfoDescription);
+            mIconView.setContentDescription(String.format(mAppInfoDescFormat, t.titleDescription));
             mIconView.setOnClickListener(this);
             mIconView.setClickable(true);
         }
@@ -651,7 +604,7 @@
         SystemServicesProxy ssp = Recents.getSystemServices();
         ComponentName cn = mTask.key.getComponent();
         int userId = mTask.key.userId;
-        ActivityInfo activityInfo = ssp.getActivityInfo(cn, userId);
+        ActivityInfo activityInfo = PackageManagerWrapper.getInstance().getActivityInfo(cn, userId);
         if (activityInfo == null) {
             return;
         }
@@ -671,11 +624,12 @@
         }
 
         // Update the overlay contents for the current app
-        mAppTitleView.setText(ssp.getBadgedApplicationLabel(activityInfo.applicationInfo, userId));
+        mAppTitleView.setText(ActivityManagerWrapper.getInstance().getBadgedApplicationLabel(
+                activityInfo.applicationInfo, userId));
         mAppTitleView.setTextColor(mTask.useLightOnPrimaryColor ?
                 mTaskBarViewLightTextColor : mTaskBarViewDarkTextColor);
-        mAppIconView.setImageDrawable(ssp.getBadgedApplicationIcon(activityInfo.applicationInfo,
-                userId));
+        mAppIconView.setImageDrawable(ActivityManagerWrapper.getInstance().getBadgedApplicationIcon(
+                activityInfo.applicationInfo, userId));
         mAppInfoView.setImageDrawable(mTask.useLightOnPrimaryColor
                 ? mLightInfoIcon
                 : mDarkInfoIcon);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index a2190b3..4152b05 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -37,9 +37,9 @@
 import com.android.systemui.R;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.ui.TaskSnapshotChangedEvent;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.ThumbnailData;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.ThumbnailData;
 import java.io.PrintWriter;
 
 
@@ -245,10 +245,6 @@
     public void updateThumbnailMatrix() {
         mThumbnailScale = 1f;
         if (mBitmapShader != null && mThumbnailData != null) {
-            // We consider this a stack task if it is not freeform (ie. has no bounds) or has been
-            // dragged into the stack from the freeform workspace
-            boolean isStackTask = !mTask.isFreeformTask() || mTask.bounds == null;
-            int xOffset, yOffset = 0;
             if (mTaskViewRect.isEmpty()) {
                 // If we haven't measured , skip the thumbnail drawing and only draw the background
                 // color
@@ -266,7 +262,7 @@
                     mThumbnailScale = (float) (mTaskViewRect.height() - mTitleBarHeight)
                             / (float) mThumbnailRect.height();
                 }
-            } else if (isStackTask) {
+            } else {
                 float invThumbnailScale = 1f / mFullscreenThumbnailScale;
                 if (mDisplayOrientation == Configuration.ORIENTATION_PORTRAIT) {
                     if (mThumbnailData.orientation == Configuration.ORIENTATION_PORTRAIT) {
@@ -283,12 +279,6 @@
                     // Otherwise, scale the screenshot to fit 1:1 in the current orientation
                     mThumbnailScale = invThumbnailScale;
                 }
-            } else {
-                // Otherwise, if this is a freeform task with task bounds, then scale the thumbnail
-                // to fit the entire bitmap into the task bounds
-                mThumbnailScale = Math.min(
-                        (float) mTaskViewRect.width() / mThumbnailRect.width(),
-                        (float) mTaskViewRect.height() / mThumbnailRect.height());
             }
             mMatrix.setTranslate(-mThumbnailData.insets.left * mFullscreenThumbnailScale,
                     -mThumbnailData.insets.top * mFullscreenThumbnailScale);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index 397f24e..9b717e0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -21,11 +21,11 @@
 import android.animation.PropertyValuesHolder;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.util.IntProperty;
 import android.util.Property;
 import android.view.View;
 
-import com.android.systemui.recents.misc.Utilities;
+import com.android.systemui.shared.recents.utilities.AnimationProps;
+import com.android.systemui.shared.recents.utilities.Utilities;
 
 import java.util.ArrayList;
 
@@ -59,7 +59,7 @@
 
     public boolean visible = false;
 
-    // This is a window-space rect used for positioning the task in the stack and freeform workspace
+    // This is a window-space rect used for positioning the task in the stack
     public RectF rect = new RectF();
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
index c513202..ccda4b5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
@@ -25,10 +25,9 @@
 import android.view.WindowManager;
 
 import com.android.systemui.R;
-import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent.Direction;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
 import com.android.systemui.recents.views.TaskViewTransform;
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java
index 86ed583..95f1d58 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java
@@ -23,7 +23,7 @@
 
 import android.view.ViewTreeObserver.OnGlobalFocusChangeListener;
 import com.android.systemui.R;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.model.TaskStack;
 import com.android.systemui.recents.views.TaskStackView;
 
 public class TaskViewFocusFrame extends View implements OnGlobalFocusChangeListener {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/lowram/TaskStackLowRamLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/lowram/TaskStackLowRamLayoutAlgorithm.java
index 17e6b9e..49cac26 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/lowram/TaskStackLowRamLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/lowram/TaskStackLowRamLayoutAlgorithm.java
@@ -23,8 +23,8 @@
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsActivityLaunchState;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
 import com.android.systemui.recents.views.TaskViewTransform;
 
diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
index 7699bb9..195f4d3 100644
--- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
@@ -16,37 +16,28 @@
 
 package com.android.systemui.shortcut;
 
-import android.accessibilityservice.AccessibilityServiceInfo;
+import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
+import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.os.UserHandle.USER_CURRENT;
+
 import android.app.ActivityManager;
-import android.app.IActivityManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.ServiceInfo;
 import android.content.res.Configuration;
 import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.ArraySet;
-import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.IWindowManager;
 import android.view.KeyEvent;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
-import android.view.accessibility.AccessibilityManager;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
 import com.android.internal.policy.DividerSnapAlgorithm;
-import com.android.settingslib.accessibility.AccessibilityUtils;
-import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.stackdivider.DividerView;
-import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
 
 import java.util.List;
-import java.util.Set;
 
 /**
  * Dispatches shortcut to System UI components
@@ -58,7 +49,6 @@
 
     private ShortcutKeyServiceProxy mShortcutKeyServiceProxy = new ShortcutKeyServiceProxy(this);
     private IWindowManager mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
-    private IActivityManager mActivityManager = ActivityManager.getService();
 
     protected final long META_MASK = ((long) KeyEvent.META_META_ON) << Integer.SIZE;
     protected final long ALT_MASK = ((long) KeyEvent.META_ALT_ON) << Integer.SIZE;
@@ -102,11 +92,10 @@
                 // If there is no window docked, we dock the top-most window.
                 Recents recents = getComponent(Recents.class);
                 int dockMode = (shortcutCode == SC_DOCK_LEFT)
-                        ? ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
-                        : ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
+                        ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
+                        : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
                 List<ActivityManager.RecentTaskInfo> taskList =
-                        SystemServicesProxy.getInstance(mContext).getRecentTasks(1,
-                                UserHandle.USER_CURRENT, false, new ArraySet<>());
+                        ActivityManagerWrapper.getInstance().getRecentTasks(1, USER_CURRENT);
                 recents.showRecentApps(
                         false /* triggeredFromAltTab */,
                         false /* fromHome */);
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
index 578a18a..0997983 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
@@ -32,7 +32,7 @@
 import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
 import com.android.systemui.recents.events.component.ShowUserToastEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
+import com.android.systemui.recents.misc.TaskStackChangeListener;
 import com.android.systemui.stackdivider.events.StartedDragingEvent;
 import com.android.systemui.stackdivider.events.StoppedDragingEvent;
 
@@ -76,7 +76,7 @@
         mContext = context;
         EventBus.getDefault().register(this);
         SystemServicesProxy.getInstance(context).registerTaskStackListener(
-                new TaskStackListener() {
+                new TaskStackChangeListener() {
                     @Override
                     public void onActivityForcedResizable(String packageName, int taskId,
                             int reason) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 2ad881f..fed2ebe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -36,14 +36,17 @@
 import android.view.WindowManager;
 import android.widget.LinearLayout;
 
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.Dependency;
+import com.android.systemui.Prefs;
 import com.android.systemui.R;
-import com.android.systemui.SwipeHelper;
+import com.android.systemui.classifier.FalsingLog;
+import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
+import com.android.systemui.recents.misc.TaskStackChangeListener;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.StatusBarState;
@@ -52,10 +55,6 @@
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.classifier.FalsingLog;
-import com.android.systemui.classifier.FalsingManager;
-import com.android.systemui.Prefs;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -306,10 +305,10 @@
     }
 
     /**
-     * An implementation of TaskStackListener, that listens for changes in the system task
+     * An implementation of TaskStackChangeListener, that listens for changes in the system task
      * stack and notifies the navigation bar.
      */
-    private class TaskStackListenerImpl extends TaskStackListener {
+    private class TaskStackListenerImpl extends TaskStackChangeListener {
         @Override
         public void onTaskStackChanged() {
             SystemServicesProxy ssp = Recents.getSystemServices();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index 87f5ca7..40ddf5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -124,8 +124,8 @@
         } else {
             if (selectedUser != null) {
                 // Show the selected user's static wallpaper.
-                return LoaderResult.success(
-                        mWallpaperManager.getBitmapAsUser(selectedUser.getIdentifier()));
+                return LoaderResult.success(mWallpaperManager.getBitmapAsUser(
+                        selectedUser.getIdentifier(), true /* hardware */));
 
             } else {
                 // When there is no selected user, show the system wallpaper
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index f3ca66f..c950036 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -17,12 +17,19 @@
 package com.android.systemui.statusbar.phone;
 
 import android.content.Context;
+import android.os.Handler;
+import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.SparseArray;
+import android.view.Display;
+import android.view.IWallpaperVisibilityListener;
+import android.view.IWindowManager;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.WindowManagerGlobal;
 
 import com.android.internal.statusbar.IStatusBarService;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 
 public final class NavigationBarTransitions extends BarTransitions {
@@ -30,6 +37,7 @@
     private final NavigationBarView mView;
     private final IStatusBarService mBarService;
     private final LightBarTransitionsController mLightTransitionsController;
+    private boolean mWallpaperVisible;
 
     private boolean mLightsOut;
     private boolean mAutoDim;
@@ -41,6 +49,21 @@
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
         mLightTransitionsController = new LightBarTransitionsController(view.getContext(),
                 this::applyDarkIntensity);
+
+        IWindowManager windowManagerService = Dependency.get(IWindowManager.class);
+        Handler handler = Handler.getMain();
+        try {
+            mWallpaperVisible = windowManagerService.registerWallpaperVisibilityListener(
+                new IWallpaperVisibilityListener.Stub() {
+                    @Override
+                    public void onWallpaperVisibilityChanged(boolean newVisibility,
+                            int displayId) throws RemoteException {
+                        mWallpaperVisible = newVisibility;
+                        handler.post(() -> applyLightsOut(true, false));
+                    }
+                }, Display.DEFAULT_DISPLAY);
+        } catch (RemoteException e) {
+        }
     }
 
     public void init() {
@@ -57,7 +80,7 @@
 
     @Override
     protected boolean isLightsOut(int mode) {
-        return super.isLightsOut(mode) || mAutoDim;
+        return super.isLightsOut(mode) || (mAutoDim && !mWallpaperVisible);
     }
 
     public LightBarTransitionsController getLightTransitionsController() {
@@ -85,7 +108,7 @@
         // ok, everyone, stop it right there
         navButtons.animate().cancel();
 
-        final float navButtonsAlpha = lightsOut ? 0.5f : 1f;
+        final float navButtonsAlpha = lightsOut ? 0.6f : 1f;
 
         if (!animate) {
             navButtons.setAlpha(navButtonsAlpha);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 9c837ed..b876286b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -66,7 +66,7 @@
 import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.qs.tiles.RotationLockTile;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
+import com.android.systemui.recents.misc.TaskStackChangeListener;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
 import com.android.systemui.statusbar.policy.BluetoothController;
@@ -639,12 +639,17 @@
     }
 
     private Intent getTaskIntent(int taskId, int userId) {
-        List<ActivityManager.RecentTaskInfo> tasks = mContext.getSystemService(ActivityManager.class)
-                .getRecentTasksForUser(NUM_TASKS_FOR_INSTANT_APP_INFO, 0, userId);
-        for (int i = 0; i < tasks.size(); i++) {
-            if (tasks.get(i).id == taskId) {
-                return tasks.get(i).baseIntent;
+        try {
+            final List<ActivityManager.RecentTaskInfo> tasks =
+                    ActivityManager.getService().getRecentTasks(
+                            NUM_TASKS_FOR_INSTANT_APP_INFO, 0, userId).getList();
+            for (int i = 0; i < tasks.size(); i++) {
+                if (tasks.get(i).id == taskId) {
+                    return tasks.get(i).baseIntent;
+                }
             }
+        } catch (RemoteException e) {
+            // Fall through
         }
         return null;
     }
@@ -763,7 +768,7 @@
         mIconController.setIconVisibility(mSlotDataSaver, isDataSaving);
     }
 
-    private final TaskStackListener mTaskListener = new TaskStackListener() {
+    private final TaskStackChangeListener mTaskListener = new TaskStackChangeListener() {
         @Override
         public void onTaskStackChanged() {
             // Listen for changes to stacks and then check which instant apps are foreground.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 3a6819e..9f03954 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -5881,8 +5881,7 @@
                 List<ActivityManager.RecentTaskInfo> recentTask = null;
                 try {
                     recentTask = ActivityManager.getService().getRecentTasks(1,
-                            ActivityManager.RECENT_WITH_EXCLUDED
-                            | ActivityManager.RECENT_INCLUDE_PROFILES,
+                            ActivityManager.RECENT_WITH_EXCLUDED,
                             mCurrentUserId).getList();
                 } catch (RemoteException e) {
                     // Abandon hope activity manager not running.
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 27c16d5..b695919 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -38,6 +38,7 @@
 
 LOCAL_STATIC_ANDROID_LIBRARIES := \
     SystemUIPluginLib \
+    SystemUISharedLib \
     android-support-v4 \
     android-support-v7-recyclerview \
     android-support-v7-preference \
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
index 5fb0a3e..b86fc21 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
@@ -44,7 +44,7 @@
 import com.android.systemui.keyguard.WorkLockActivity;
 import com.android.systemui.keyguard.WorkLockActivityController;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
+import com.android.systemui.recents.misc.TaskStackChangeListener;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -68,7 +68,7 @@
     private @Mock IActivityManager mIActivityManager;
 
     private WorkLockActivityController mController;
-    private TaskStackListener mTaskStackListener;
+    private TaskStackChangeListener mTaskStackListener;
 
     @Before
     public void setUp() throws Exception {
@@ -78,8 +78,8 @@
         doReturn("com.example.test").when(mContext).getPackageName();
 
         // Construct controller. Save the TaskStackListener for injecting events.
-        final ArgumentCaptor<TaskStackListener> listenerCaptor =
-                ArgumentCaptor.forClass(TaskStackListener.class);
+        final ArgumentCaptor<TaskStackChangeListener> listenerCaptor =
+                ArgumentCaptor.forClass(TaskStackChangeListener.class);
         mController =
                 new WorkLockActivityController(mContext, mSystemServicesProxy, mIActivityManager);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java
deleted file mode 100644
index 767e124..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.recents.model;
-
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.os.Looper;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.Task.TaskKey;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/**
- * runtest systemui -c com.android.systemui.recents.model.HighResThumbnailLoaderTest
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class HighResThumbnailLoaderTest extends SysuiTestCase {
-
-    private HighResThumbnailLoader mLoader;
-
-    @Mock
-    private SystemServicesProxy mMockSystemServicesProxy;
-    @Mock
-    private Task mTask;
-
-    private ThumbnailData mThumbnailData = new ThumbnailData();
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        mLoader = new HighResThumbnailLoader(mMockSystemServicesProxy, Looper.getMainLooper(),
-                false);
-        mTask.key = new TaskKey(0, WINDOWING_MODE_UNDEFINED, null, 0, 0, 0);
-        when(mMockSystemServicesProxy.getTaskThumbnail(anyInt(), anyBoolean()))
-                .thenReturn(mThumbnailData);
-        mLoader.setVisible(true);
-        mLoader.setTaskLoadQueueIdle(true);
-    }
-
-    @Test
-    public void testLoading() throws Exception {
-        mLoader.setVisible(true);
-        assertTrue(mLoader.isLoading());
-        mLoader.setVisible(false);
-        assertFalse(mLoader.isLoading());
-        mLoader.setVisible(true);
-        mLoader.setFlingingFast(true);
-        assertFalse(mLoader.isLoading());
-        mLoader.setFlingingFast(false);
-        assertTrue(mLoader.isLoading());
-        mLoader.setFlingingFast(false);
-        mLoader.setTaskLoadQueueIdle(false);
-        assertFalse(mLoader.isLoading());
-        mLoader.setTaskLoadQueueIdle(true);
-        assertTrue(mLoader.isLoading());
-    }
-
-    @Test
-    public void testLoad() throws Exception {
-        mLoader.onTaskVisible(mTask);
-        mLoader.waitForLoaderIdle();
-        waitForIdleSync();
-        verify(mTask).notifyTaskDataLoaded(mThumbnailData, null);
-    }
-
-    @Test
-    public void testFlinging_notLoaded() throws Exception {
-        mLoader.setFlingingFast(true);
-        mLoader.onTaskVisible(mTask);
-        mLoader.waitForLoaderIdle();
-        waitForIdleSync();
-        verify(mTask, never()).notifyTaskDataLoaded(mThumbnailData, null);
-    }
-
-    /**
-     * Tests whether task is loaded after stopping to fling
-     */
-    @Test
-    public void testAfterFlinging() throws Exception {
-        mLoader.setFlingingFast(true);
-        mLoader.onTaskVisible(mTask);
-        mLoader.setFlingingFast(false);
-        mLoader.waitForLoaderIdle();
-        waitForIdleSync();
-        verify(mTask).notifyTaskDataLoaded(mThumbnailData, null);
-    }
-
-    @Test
-    public void testAlreadyLoaded() throws Exception {
-        mTask.thumbnail = new ThumbnailData();
-        mTask.thumbnail.reducedResolution = false;
-        mLoader.onTaskVisible(mTask);
-        mLoader.waitForLoaderIdle();
-        waitForIdleSync();
-        verify(mTask, never()).notifyTaskDataLoaded(mThumbnailData, null);
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java
index 0c1baaa..76f57f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java
@@ -24,6 +24,7 @@
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
+import android.view.IWindowManager;
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.CommandQueue;
@@ -41,6 +42,7 @@
 
     @Before
     public void setup() {
+        mDependency.injectMockDependency(IWindowManager.class);
         mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
         NavigationBarView navBar = spy(new NavigationBarView(mContext, null));
         when(navBar.getCurrentView()).thenReturn(navBar);
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 6a8a222..8e88359 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4675,6 +4675,30 @@
     // OS: P
     DIALOG_LOG_PERSIST = 1225;
 
+    // ACTION: DND Settings > Priority only allows > Alarms toggle
+    // SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ZEN_ALLOW_ALARMS = 1226;
+
+    // ACTION: DND Settings > Priority only allows > Media toggle
+    // SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ZEN_ALLOW_MEDIA = 1227;
+
+    // An autofill service explicitly defined which view should commit the autofill context
+    // Package: Package of app that is autofilled
+    // OS: P
+    // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+    AUTOFILL_EXPLICIT_SAVE_TRIGGER_DEFINITION = 1228;
+
+    // The autofill context was commited when the user clicked a view explicitly marked by the
+    // service as committing it
+    // Package: Package of app that is autofilled
+    // OS: P
+    AUTOFILL_SAVE_EXPLICITLY_TRIGGERED = 1229;
+
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
   }
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 54eba2b..ee0c043 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -336,6 +336,34 @@
 
   // Count of connection attempts that were initiated unsuccessfully
   optional int32 num_open_network_connect_message_failed_to_send = 82;
+
+  // Histogram counting instances of scans with N many HotSpot 2.0 R1 APs
+  repeated NumConnectableNetworksBucket observed_hotspot_r1_aps_in_scan_histogram = 83;
+
+  // Histogram counting instances of scans with N many HotSpot 2.0 R2 APs
+  repeated NumConnectableNetworksBucket observed_hotspot_r2_aps_in_scan_histogram = 84;
+
+  // Histogram counting instances of scans with N many unique HotSpot 2.0 R1 ESS.
+  // Where ESS is defined as the (HESSID, ANQP Domain ID), (SSID, ANQP Domain ID) or
+  // (SSID, BSSID) tuple depending on AP configuration (in the above priority
+  // order).
+  repeated NumConnectableNetworksBucket observed_hotspot_r1_ess_in_scan_histogram = 85;
+
+  // Histogram counting instances of scans with N many unique HotSpot 2.0 R2 ESS.
+  // Where ESS is defined as the (HESSID, ANQP Domain ID), (SSID, ANQP Domain ID) or
+  // (SSID, BSSID) tuple depending on AP configuration (in the above priority
+  // order).
+  repeated NumConnectableNetworksBucket observed_hotspot_r2_ess_in_scan_histogram = 86;
+
+  // Histogram counting number of HotSpot 2.0 R1 APs per observed ESS in a scan
+  // (one value added per unique ESS - potentially multiple counts per single
+  // scan!)
+  repeated NumConnectableNetworksBucket observed_hotspot_r1_aps_per_ess_in_scan_histogram = 87;
+
+  // Histogram counting number of HotSpot 2.0 R2 APs per observed ESS in a scan
+  // (one value added per unique ESS - potentially multiple counts per single
+  // scan!)
+  repeated NumConnectableNetworksBucket observed_hotspot_r2_aps_per_ess_in_scan_histogram = 88;
 }
 
 // Information that gets logged for every WiFi connection.
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index c60647f..f6fcaae 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -19,6 +19,9 @@
 import android.content.Context;
 import android.os.Handler;
 import android.os.PowerManager;
+import android.util.DebugUtils;
+import android.util.ExceptionUtils;
+import android.util.Log;
 import android.util.Pools.SimplePool;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
@@ -31,6 +34,7 @@
 import android.view.WindowManagerPolicy;
 import android.view.accessibility.AccessibilityEvent;
 
+import com.android.internal.util.BitUtils;
 import com.android.server.LocalServices;
 
 /**
@@ -188,6 +192,7 @@
         }
 
         if (mEventHandler == null) {
+            if (DEBUG) Slog.d(TAG, "mEventHandler == null for event " + event);
             super.onInputEvent(event, policyFlags);
             return;
         }
@@ -339,6 +344,8 @@
             MotionEvent transformedEvent = MotionEvent.obtain(event);
             mEventHandler.onMotionEvent(transformedEvent, event, policyFlags);
             transformedEvent.recycle();
+        } else {
+            if (DEBUG) Slog.d(TAG, "mEventHandler == null for " + event);
         }
     }
 
@@ -366,11 +373,20 @@
     }
 
     @Override
+    public EventStreamTransformation getNext() {
+        return null;
+    }
+
+    @Override
     public void clearEvents(int inputSource) {
         /* do nothing */
     }
 
     void setUserAndEnabledFeatures(int userId, int enabledFeatures) {
+        if (DEBUG) {
+            Slog.i(TAG, "setUserAndEnabledFeatures(userId = " + userId + ", enabledFeatures = 0x"
+                    + Integer.toHexString(enabledFeatures) + ")");
+        }
         if (mEnabledFeatures == enabledFeatures && mUserId == userId) {
             return;
         }
@@ -397,6 +413,8 @@
     }
 
     private void enableFeatures() {
+        if (DEBUG) Slog.i(TAG, "enableFeatures()");
+
         resetStreamState();
 
         if ((mEnabledFeatures & FLAG_FEATURE_AUTOCLICK) != 0) {
@@ -443,7 +461,7 @@
      */
     private void addFirstEventHandler(EventStreamTransformation handler) {
         if (mEventHandler != null) {
-           handler.setNext(mEventHandler);
+            handler.setNext(mEventHandler);
         } else {
             handler.setNext(this);
         }
diff --git a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
index 892e9da..f5b0eb1 100644
--- a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
+++ b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
@@ -23,15 +23,12 @@
 import android.net.Uri;
 import android.os.Handler;
 import android.os.SystemClock;
-import android.os.UserHandle;
 import android.provider.Settings;
-import android.util.Slog;
 import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.MotionEvent.PointerCoords;
 import android.view.MotionEvent.PointerProperties;
-import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 
 /**
@@ -55,11 +52,10 @@
  *
  * Each instance is associated to a single user (and it does not handle user switch itself).
  */
-public class AutoclickController implements EventStreamTransformation {
+public class AutoclickController extends BaseEventStreamTransformation {
 
     private static final String LOG_TAG = AutoclickController.class.getSimpleName();
 
-    private EventStreamTransformation mNext;
     private final Context mContext;
     private final int mUserId;
 
@@ -88,9 +84,7 @@
             mClickScheduler.cancel();
         }
 
-        if (mNext != null) {
-            mNext.onMotionEvent(event, rawEvent, policyFlags);
-        }
+        super.onMotionEvent(event, rawEvent, policyFlags);
     }
 
     @Override
@@ -103,21 +97,7 @@
             }
         }
 
-        if (mNext != null) {
-          mNext.onKeyEvent(event, policyFlags);
-        }
-    }
-
-    @Override
-    public void onAccessibilityEvent(AccessibilityEvent event) {
-        if (mNext != null) {
-            mNext.onAccessibilityEvent(event);
-        }
-    }
-
-    @Override
-    public void setNext(EventStreamTransformation next) {
-        mNext = next;
+        super.onKeyEvent(event, policyFlags);
     }
 
     @Override
@@ -126,9 +106,7 @@
             mClickScheduler.cancel();
         }
 
-        if (mNext != null) {
-            mNext.clearEvents(inputSource);
-        }
+        super.clearEvents(inputSource);
     }
 
     @Override
@@ -418,7 +396,7 @@
          * Creates and forwards click event sequence.
          */
         private void sendClick() {
-            if (mLastMotionEvent == null || mNext == null) {
+            if (mLastMotionEvent == null || getNext() == null) {
                 return;
             }
 
@@ -448,10 +426,10 @@
             MotionEvent upEvent = MotionEvent.obtain(downEvent);
             upEvent.setAction(MotionEvent.ACTION_UP);
 
-            mNext.onMotionEvent(downEvent, downEvent, mEventPolicyFlags);
+            AutoclickController.super.onMotionEvent(downEvent, downEvent, mEventPolicyFlags);
             downEvent.recycle();
 
-            mNext.onMotionEvent(upEvent, upEvent, mEventPolicyFlags);
+            AutoclickController.super.onMotionEvent(upEvent, upEvent, mEventPolicyFlags);
             upEvent.recycle();
         }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/BaseEventStreamTransformation.java b/services/accessibility/java/com/android/server/accessibility/BaseEventStreamTransformation.java
new file mode 100644
index 0000000..ce54586
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/BaseEventStreamTransformation.java
@@ -0,0 +1,31 @@
+/*
+ ** Copyright 2017, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+package com.android.server.accessibility;
+
+abstract class BaseEventStreamTransformation implements EventStreamTransformation {
+    private EventStreamTransformation mNext;
+
+    @Override
+    public void setNext(EventStreamTransformation next) {
+        mNext = next;
+    }
+
+    @Override
+    public EventStreamTransformation getNext() {
+        return mNext;
+    }
+}
\ No newline at end of file
diff --git a/services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java b/services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java
index fdc4098..7982996 100644
--- a/services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java
+++ b/services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java
@@ -65,7 +65,12 @@
      * @param rawEvent The raw motion event.
      * @param policyFlags Policy flags for the event.
      */
-    public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags);
+    default void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        EventStreamTransformation next = getNext();
+        if (next != null) {
+            next.onMotionEvent(event, rawEvent, policyFlags);
+        }
+    }
 
     /**
      * Receives a key event.
@@ -73,14 +78,24 @@
      * @param event The key event.
      * @param policyFlags Policy flags for the event.
      */
-    public void onKeyEvent(KeyEvent event, int policyFlags);
+    default void onKeyEvent(KeyEvent event, int policyFlags) {
+        EventStreamTransformation next = getNext();
+        if (next != null) {
+            next.onKeyEvent(event, policyFlags);
+        }
+    }
 
     /**
      * Receives an accessibility event.
      *
      * @param event The accessibility event.
      */
-    public void onAccessibilityEvent(AccessibilityEvent event);
+    default void onAccessibilityEvent(AccessibilityEvent event) {
+        EventStreamTransformation next = getNext();
+        if (next != null) {
+            next.onAccessibilityEvent(event);
+        }
+    };
 
     /**
      * Sets the next transformation.
@@ -90,14 +105,26 @@
     public void setNext(EventStreamTransformation next);
 
     /**
+     * Gets the next transformation.
+     *
+     * @return The next transformation.
+     */
+    public EventStreamTransformation getNext();
+
+    /**
      * Clears internal state associated with events from specific input source.
      *
      * @param inputSource The input source class for which transformation state should be cleared.
      */
-    public void clearEvents(int inputSource);
+    default void clearEvents(int inputSource) {
+        EventStreamTransformation next = getNext();
+        if (next != null) {
+            next.clearEvents(inputSource);
+        }
+    }
 
     /**
      * Destroys this transformation.
      */
-    public void onDestroy();
+    default void onDestroy() {}
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/KeyboardInterceptor.java b/services/accessibility/java/com/android/server/accessibility/KeyboardInterceptor.java
index f00a954..7724945 100644
--- a/services/accessibility/java/com/android/server/accessibility/KeyboardInterceptor.java
+++ b/services/accessibility/java/com/android/server/accessibility/KeyboardInterceptor.java
@@ -22,14 +22,12 @@
 import android.util.Pools;
 import android.util.Slog;
 import android.view.KeyEvent;
-import android.view.MotionEvent;
 import android.view.WindowManagerPolicy;
-import android.view.accessibility.AccessibilityEvent;
 
 /**
  * Intercepts key events and forwards them to accessibility manager service.
  */
-public class KeyboardInterceptor implements EventStreamTransformation, Handler.Callback {
+public class KeyboardInterceptor extends BaseEventStreamTransformation implements Handler.Callback {
     private static final int MESSAGE_PROCESS_QUEUED_EVENTS = 1;
     private static final String LOG_TAG = "KeyboardInterceptor";
 
@@ -37,7 +35,6 @@
     private final WindowManagerPolicy mPolicy;
     private final Handler mHandler;
 
-    private EventStreamTransformation mNext;
     private KeyEventHolder mEventQueueStart;
     private KeyEventHolder mEventQueueEnd;
 
@@ -65,13 +62,6 @@
     }
 
     @Override
-    public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
-        if (mNext != null) {
-            mNext.onMotionEvent(event, rawEvent, policyFlags);
-        }
-    }
-
-    @Override
     public void onKeyEvent(KeyEvent event, int policyFlags) {
         /*
          * Certain keys have system-level behavior that affects accessibility services.
@@ -90,29 +80,6 @@
     }
 
     @Override
-    public void onAccessibilityEvent(AccessibilityEvent event) {
-        if (mNext != null) {
-            mNext.onAccessibilityEvent(event);
-        }
-    }
-
-    @Override
-    public void setNext(EventStreamTransformation next) {
-        mNext = next;
-    }
-
-    @Override
-    public void clearEvents(int inputSource) {
-        if (mNext != null) {
-            mNext.clearEvents(inputSource);
-        }
-    }
-
-    @Override
-    public void onDestroy() {
-    }
-
-    @Override
     public boolean handleMessage(Message msg) {
         if (msg.what != MESSAGE_PROCESS_QUEUED_EVENTS) {
             Slog.e(LOG_TAG, "Unexpected message type");
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
index 98b8e6b..a10b7a2 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
@@ -56,6 +56,7 @@
  * constraints.
  */
 class MagnificationController implements Handler.Callback {
+    private static final boolean DEBUG = false;
     private static final String LOG_TAG = "MagnificationController";
 
     public static final float MIN_SCALE = 1.0f;
@@ -509,6 +510,12 @@
 
     private boolean setScaleAndCenterLocked(float scale, float centerX, float centerY,
             boolean animate, int id) {
+        if (DEBUG) {
+            Slog.i(LOG_TAG,
+                    "setScaleAndCenterLocked(scale = " + scale + ", centerX = " + centerX
+                            + ", centerY = " + centerY + ", animate = " + animate + ", id = " + id
+                            + ")");
+        }
         final boolean changed = updateMagnificationSpecLocked(scale, centerX, centerY);
         sendSpecToAnimation(mCurrentMagnificationSpec, animate);
         if (isMagnifying() && (id != INVALID_ID)) {
@@ -535,7 +542,9 @@
 
             final float nonNormOffsetX = mCurrentMagnificationSpec.offsetX - offsetX;
             final float nonNormOffsetY = mCurrentMagnificationSpec.offsetY - offsetY;
-            updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY);
+            if (updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY)) {
+                onMagnificationChangedLocked();
+            }
             if (id != INVALID_ID) {
                 mIdOfLastServiceToMagnify = id;
             }
@@ -633,6 +642,11 @@
     }
 
     private boolean updateCurrentSpecWithOffsetsLocked(float nonNormOffsetX, float nonNormOffsetY) {
+        if (DEBUG) {
+            Slog.i(LOG_TAG,
+                    "updateCurrentSpecWithOffsetsLocked(nonNormOffsetX = " + nonNormOffsetX
+                            + ", nonNormOffsetY = " + nonNormOffsetY + ")");
+        }
         boolean changed = false;
         final float offsetX = MathUtils.constrain(nonNormOffsetX, getMinOffsetXLocked(), 0);
         if (Float.compare(mCurrentMagnificationSpec.offsetX, offsetX) != 0) {
@@ -750,6 +764,9 @@
     }
 
     private void sendSpecToAnimation(MagnificationSpec spec, boolean animate) {
+        if (DEBUG) {
+            Slog.i(LOG_TAG, "sendSpecToAnimation(spec = " + spec + ", animate = " + animate + ")");
+        }
         if (Thread.currentThread().getId() == mMainThreadId) {
             mSpecAnimationBridge.updateSentSpecMainThread(spec, animate);
         } else {
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index d6452f8..9b2b4eb 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -42,14 +42,12 @@
 import android.util.TypedValue;
 import android.view.GestureDetector;
 import android.view.GestureDetector.SimpleOnGestureListener;
-import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.MotionEvent.PointerCoords;
 import android.view.MotionEvent.PointerProperties;
 import android.view.ScaleGestureDetector;
 import android.view.ScaleGestureDetector.OnScaleGestureListener;
 import android.view.ViewConfiguration;
-import android.view.accessibility.AccessibilityEvent;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -102,31 +100,23 @@
  * 7. The magnification scale will be persisted in settings and in the cloud.
  */
 @SuppressWarnings("WeakerAccess")
-class MagnificationGestureHandler implements EventStreamTransformation {
-    private static final String LOG_TAG = "MagnificationEventHandler";
+class MagnificationGestureHandler extends BaseEventStreamTransformation {
+    private static final String LOG_TAG = "MagnificationGestureHandler";
 
     private static final boolean DEBUG_ALL = false;
     private static final boolean DEBUG_STATE_TRANSITIONS = false || DEBUG_ALL;
     private static final boolean DEBUG_DETECTING = false || DEBUG_ALL;
-    private static final boolean DEBUG_PANNING = false || DEBUG_ALL;
-
-    /** @see #handleMotionEventStateDelegating */
-    @VisibleForTesting static final int STATE_DELEGATING = 1;
-    /** @see DetectingStateHandler */
-    @VisibleForTesting static final int STATE_DETECTING = 2;
-    /** @see ViewportDraggingStateHandler */
-    @VisibleForTesting static final int STATE_VIEWPORT_DRAGGING = 3;
-    /** @see PanningScalingStateHandler */
-    @VisibleForTesting static final int STATE_PANNING_SCALING = 4;
+    private static final boolean DEBUG_PANNING_SCALING = false || DEBUG_ALL;
 
     private static final float MIN_SCALE = 2.0f;
     private static final float MAX_SCALE = 5.0f;
 
     @VisibleForTesting final MagnificationController mMagnificationController;
 
-    @VisibleForTesting final DetectingStateHandler mDetectingStateHandler;
-    @VisibleForTesting final PanningScalingStateHandler mPanningScalingStateHandler;
-    @VisibleForTesting final ViewportDraggingStateHandler mViewportDraggingStateHandler;
+    @VisibleForTesting final DelegatingState mDelegatingState;
+    @VisibleForTesting final DetectingState mDetectingState;
+    @VisibleForTesting final PanningScalingState mPanningScalingState;
+    @VisibleForTesting final ViewportDraggingState mViewportDraggingState;
 
     private final ScreenStateReceiver mScreenStateReceiver;
 
@@ -138,21 +128,12 @@
     final boolean mDetectTripleTap;
 
     /**
-     * Whether {@link #mShortcutTriggered shortcut} is enabled
+     * Whether {@link DetectingState#mShortcutTriggered shortcut} is enabled
      */
     final boolean mDetectShortcutTrigger;
 
-    EventStreamTransformation mNext;
-
-    @VisibleForTesting int mCurrentState;
-    @VisibleForTesting int mPreviousState;
-
-    @VisibleForTesting boolean mShortcutTriggered;
-
-    /**
-     * Time of last {@link MotionEvent#ACTION_DOWN} while in {@link #STATE_DELEGATING}
-     */
-    long mDelegatingStateDownTime;
+    @VisibleForTesting State mCurrentState;
+    @VisibleForTesting State mPreviousState;
 
     private PointerCoords[] mTempPointerCoords;
     private PointerProperties[] mTempPointerProperties;
@@ -174,10 +155,10 @@
             boolean detectShortcutTrigger) {
         mMagnificationController = magnificationController;
 
-        mDetectingStateHandler = new DetectingStateHandler(context);
-        mViewportDraggingStateHandler = new ViewportDraggingStateHandler();
-        mPanningScalingStateHandler =
-                new PanningScalingStateHandler(context);
+        mDelegatingState = new DelegatingState();
+        mDetectingState = new DetectingState(context);
+        mViewportDraggingState = new ViewportDraggingState();
+        mPanningScalingState = new PanningScalingState(context);
 
         mDetectTripleTap = detectTripleTap;
         mDetectShortcutTrigger = detectShortcutTrigger;
@@ -189,62 +170,29 @@
             mScreenStateReceiver = null;
         }
 
-        transitionTo(STATE_DETECTING);
+        transitionTo(mDetectingState);
     }
 
     @Override
     public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (DEBUG_ALL) Slog.i(LOG_TAG, "onMotionEvent(" + event + ")");
+
         if ((!mDetectTripleTap && !mDetectShortcutTrigger)
                 || !event.isFromSource(SOURCE_TOUCHSCREEN)) {
             dispatchTransformedEvent(event, rawEvent, policyFlags);
             return;
         }
-        // Local copy to avoid dispatching the same event to more than one state handler
-        // in case mPanningScalingStateHandler changes mCurrentState
-        int currentState = mCurrentState;
-        mPanningScalingStateHandler.onMotionEvent(event, rawEvent, policyFlags);
-        switch (currentState) {
-            case STATE_DELEGATING: {
-                handleMotionEventStateDelegating(event, rawEvent, policyFlags);
-            }
-            break;
-            case STATE_DETECTING: {
-                mDetectingStateHandler.onMotionEvent(event, rawEvent, policyFlags);
-            }
-            break;
-            case STATE_VIEWPORT_DRAGGING: {
-                mViewportDraggingStateHandler.onMotionEvent(event, rawEvent, policyFlags);
-            }
-            break;
-            case STATE_PANNING_SCALING: {
-                // mPanningScalingStateHandler handles events only
-                // if this is the current state since it uses ScaleGestureDetector
-                // and a GestureDetector which need well formed event stream.
-            }
-            break;
-            default: {
-                throw new IllegalStateException("Unknown state: " + currentState);
-            }
-        }
+
+        handleEventWith(mCurrentState, event, rawEvent, policyFlags);
     }
 
-    @Override
-    public void onKeyEvent(KeyEvent event, int policyFlags) {
-        if (mNext != null) {
-            mNext.onKeyEvent(event, policyFlags);
-        }
-    }
+    private void handleEventWith(State stateHandler,
+            MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        // To keep InputEventConsistencyVerifiers within GestureDetectors happy
+        mPanningScalingState.mScrollGestureDetector.onTouchEvent(event);
+        mPanningScalingState.mScaleGestureDetector.onTouchEvent(event);
 
-    @Override
-    public void onAccessibilityEvent(AccessibilityEvent event) {
-        if (mNext != null) {
-            mNext.onAccessibilityEvent(event);
-        }
-    }
-
-    @Override
-    public void setNext(EventStreamTransformation next) {
-        mNext = next;
+        stateHandler.onMotionEvent(event, rawEvent, policyFlags);
     }
 
     @Override
@@ -253,13 +201,16 @@
             clearAndTransitionToStateDetecting();
         }
 
-        if (mNext != null) {
-            mNext.clearEvents(inputSource);
-        }
+        super.clearEvents(inputSource);
     }
 
     @Override
     public void onDestroy() {
+        if (DEBUG_STATE_TRANSITIONS) {
+            Slog.i(LOG_TAG, "onDestroy(); delayed = "
+                    + MotionEventInfo.toString(mDetectingState.mDelayedEventQueue));
+        }
+
         if (mScreenStateReceiver != null) {
             mScreenStateReceiver.unregister();
         }
@@ -272,59 +223,21 @@
             if (wasMagnifying) {
                 clearAndTransitionToStateDetecting();
             } else {
-                toggleShortcutTriggered();
+                mDetectingState.toggleShortcutTriggered();
             }
         }
     }
 
-    private void toggleShortcutTriggered() {
-        setShortcutTriggered(!mShortcutTriggered);
-    }
-
-    private void setShortcutTriggered(boolean state) {
-        if (mShortcutTriggered == state) {
-            return;
-        }
-
-        mShortcutTriggered = state;
-        mMagnificationController.setForceShowMagnifiableBounds(state);
-    }
-
     void clearAndTransitionToStateDetecting() {
-        setShortcutTriggered(false);
-        mCurrentState = STATE_DETECTING;
-        mDetectingStateHandler.clear();
-        mViewportDraggingStateHandler.clear();
-        mPanningScalingStateHandler.clear();
-    }
-
-    private void handleMotionEventStateDelegating(MotionEvent event,
-            MotionEvent rawEvent, int policyFlags) {
-        if (event.getActionMasked() == ACTION_UP) {
-            transitionTo(STATE_DETECTING);
-        }
-        delegateEvent(event, rawEvent, policyFlags);
-    }
-
-    void delegateEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
-        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
-            mDelegatingStateDownTime = event.getDownTime();
-        }
-        if (mNext != null) {
-            // We cache some events to see if the user wants to trigger magnification.
-            // If no magnification is triggered we inject these events with adjusted
-            // time and down time to prevent subsequent transformations being confused
-            // by stale events. After the cached events, which always have a down, are
-            // injected we need to also update the down time of all subsequent non cached
-            // events. All delegated events cached and non-cached are delivered here.
-            event.setDownTime(mDelegatingStateDownTime);
-            dispatchTransformedEvent(event, rawEvent, policyFlags);
-        }
+        mCurrentState = mDelegatingState;
+        mDetectingState.clear();
+        mViewportDraggingState.clear();
+        mPanningScalingState.clear();
     }
 
     private void dispatchTransformedEvent(MotionEvent event, MotionEvent rawEvent,
             int policyFlags) {
-        if (mNext == null) return; // Nowhere to dispatch to
+        if (DEBUG_ALL) Slog.i(LOG_TAG, "dispatchTransformedEvent(event = " + event + ")");
 
         // If the touchscreen event is within the magnified portion of the screen we have
         // to change its location to be where the user thinks he is poking the
@@ -351,7 +264,7 @@
                     coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0, event.getSource(),
                     event.getFlags());
         }
-        mNext.onMotionEvent(event, rawEvent, policyFlags);
+        super.onMotionEvent(event, rawEvent, policyFlags);
     }
 
     private PointerCoords[] getTempPointerCoordsWithMinSize(int size) {
@@ -386,9 +299,10 @@
         return mTempPointerProperties;
     }
 
-    private void transitionTo(int state) {
+    private void transitionTo(State state) {
         if (DEBUG_STATE_TRANSITIONS) {
-            Slog.i(LOG_TAG, (stateToString(mCurrentState) + " -> " + stateToString(state)
+            Slog.i(LOG_TAG,
+                    (State.nameOf(mCurrentState) + " -> " + State.nameOf(state)
                     + " at " + asList(copyOfRange(new RuntimeException().getStackTrace(), 1, 5)))
                     .replace(getClass().getName(), ""));
         }
@@ -396,40 +310,40 @@
         mCurrentState = state;
     }
 
-    private static String stateToString(int state) {
-        switch (state) {
-            case STATE_DELEGATING: return "STATE_DELEGATING";
-            case STATE_DETECTING: return "STATE_DETECTING";
-            case STATE_VIEWPORT_DRAGGING: return "STATE_VIEWPORT_DRAGGING";
-            case STATE_PANNING_SCALING: return "STATE_PANNING_SCALING";
-            case 0: return "0";
-            default: throw new IllegalArgumentException("Unknown state: " + state);
-        }
-    }
-
-    private interface MotionEventHandler {
-
+    interface State {
         void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags);
 
-        void clear();
+        default void clear() {}
+
+        default String name() {
+            return getClass().getSimpleName();
+        }
+
+        static String nameOf(@Nullable State s) {
+            return s != null ? s.name() : "null";
+        }
     }
 
     /**
      * This class determines if the user is performing a scale or pan gesture.
      *
-     * @see #STATE_PANNING_SCALING
+     * Unlike when {@link ViewportDraggingState dragging the viewport}, in panning mode the viewport
+     * moves in the same direction as the fingers, and allows to easily and precisely scale the
+     * magnification level.
+     * This makes it the preferred mode for one-off adjustments, due to its precision and ease of
+     * triggering.
      */
-    final class PanningScalingStateHandler extends SimpleOnGestureListener
-            implements OnScaleGestureListener, MotionEventHandler {
+    final class PanningScalingState extends SimpleOnGestureListener
+            implements OnScaleGestureListener, State {
 
         private final ScaleGestureDetector mScaleGestureDetector;
-        private final GestureDetector mGestureDetector;
+        private final GestureDetector mScrollGestureDetector;
         final float mScalingThreshold;
 
         float mInitialScaleFactor = -1;
         boolean mScaling;
 
-        public PanningScalingStateHandler(Context context) {
+        public PanningScalingState(Context context) {
             final TypedValue scaleValue = new TypedValue();
             context.getResources().getValue(
                     com.android.internal.R.dimen.config_screen_magnification_scaling_threshold,
@@ -437,35 +351,27 @@
             mScalingThreshold = scaleValue.getFloat();
             mScaleGestureDetector = new ScaleGestureDetector(context, this);
             mScaleGestureDetector.setQuickScaleEnabled(false);
-            mGestureDetector = new GestureDetector(context, this);
+            mScrollGestureDetector = new GestureDetector(context, this);
         }
 
         @Override
         public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
-            // Dispatches #onScaleBegin, #onScale, #onScaleEnd
-            mScaleGestureDetector.onTouchEvent(event);
-            // Dispatches #onScroll
-            mGestureDetector.onTouchEvent(event);
-
-            if (mCurrentState != STATE_PANNING_SCALING) {
-                return;
-            }
-
             int action = event.getActionMasked();
+
             if (action == ACTION_POINTER_UP
                     && event.getPointerCount() == 2 // includes the pointer currently being released
-                    && mPreviousState == STATE_VIEWPORT_DRAGGING) {
+                    && mPreviousState == mViewportDraggingState) {
 
-                persistScaleAndTransitionTo(STATE_VIEWPORT_DRAGGING);
+                persistScaleAndTransitionTo(mViewportDraggingState);
 
             } else if (action == ACTION_UP) {
 
-                persistScaleAndTransitionTo(STATE_DETECTING);
+                persistScaleAndTransitionTo(mDetectingState);
 
             }
         }
 
-        public void persistScaleAndTransitionTo(int state) {
+        public void persistScaleAndTransitionTo(State state) {
             mMagnificationController.persistScale();
             clear();
             transitionTo(state);
@@ -474,16 +380,16 @@
         @Override
         public boolean onScroll(MotionEvent first, MotionEvent second,
                 float distanceX, float distanceY) {
-            if (mCurrentState != STATE_PANNING_SCALING) {
+            if (mCurrentState != mPanningScalingState) {
                 return true;
             }
-            if (DEBUG_PANNING) {
+            if (DEBUG_PANNING_SCALING) {
                 Slog.i(LOG_TAG, "Panned content by scrollX: " + distanceX
                         + " scrollY: " + distanceY);
             }
             mMagnificationController.offsetMagnifiedRegion(distanceX, distanceY,
                     AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
-            return true;
+            return /* event consumed: */ true;
         }
 
         @Override
@@ -494,12 +400,8 @@
                     return false;
                 }
                 final float deltaScale = detector.getScaleFactor() - mInitialScaleFactor;
-                if (abs(deltaScale) > mScalingThreshold) {
-                    mScaling = true;
-                    return true;
-                } else {
-                    return false;
-                }
+                mScaling = abs(deltaScale) > mScalingThreshold;
+                return mScaling;
             }
 
             final float initialScale = mMagnificationController.getScale();
@@ -523,14 +425,15 @@
 
             final float pivotX = detector.getFocusX();
             final float pivotY = detector.getFocusY();
+            if (DEBUG_PANNING_SCALING) Slog.i(LOG_TAG, "Scaled content to: " + scale + "x");
             mMagnificationController.setScale(scale, pivotX, pivotY, false,
                     AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
-            return true;
+            return /* handled: */ true;
         }
 
         @Override
         public boolean onScaleBegin(ScaleGestureDetector detector) {
-            return (mCurrentState == STATE_PANNING_SCALING);
+            return /* continue recognizing: */ (mCurrentState == mPanningScalingState);
         }
 
         @Override
@@ -546,7 +449,7 @@
 
         @Override
         public String toString() {
-            return "MagnifiedContentInteractionStateHandler{" +
+            return "PanningScalingState{" +
                     "mInitialScaleFactor=" + mInitialScaleFactor +
                     ", mScaling=" + mScaling +
                     '}';
@@ -558,9 +461,11 @@
      * determined that the user is performing a single-finger drag of the
      * magnification viewport.
      *
-     * @see #STATE_VIEWPORT_DRAGGING
+     * Unlike when {@link PanningScalingState panning}, the viewport moves in the opposite direction
+     * of the finger, and any part of the screen is reachable without lifting the finger.
+     * This makes it the preferable mode for tasks like reading text spanning full screen width.
      */
-    final class ViewportDraggingStateHandler implements MotionEventHandler {
+    final class ViewportDraggingState implements State {
 
         /** Whether to disable zoom after dragging ends */
         boolean mZoomedInBeforeDrag;
@@ -572,7 +477,7 @@
             switch (action) {
                 case ACTION_POINTER_DOWN: {
                     clear();
-                    transitionTo(STATE_PANNING_SCALING);
+                    transitionTo(mPanningScalingState);
                 }
                 break;
                 case ACTION_MOVE: {
@@ -594,7 +499,7 @@
                 case ACTION_UP: {
                     if (!mZoomedInBeforeDrag) zoomOff();
                     clear();
-                    transitionTo(STATE_DETECTING);
+                    transitionTo(mDetectingState);
                 }
                 break;
 
@@ -613,25 +518,51 @@
 
         @Override
         public String toString() {
-            return "ViewportDraggingStateHandler{" +
+            return "ViewportDraggingState{" +
                     "mZoomedInBeforeDrag=" + mZoomedInBeforeDrag +
                     ", mLastMoveOutsideMagnifiedRegion=" + mLastMoveOutsideMagnifiedRegion +
                     '}';
         }
     }
 
+    final class DelegatingState implements State {
+        /**
+         * Time of last {@link MotionEvent#ACTION_DOWN} while in {@link DelegatingState}
+         */
+        public long mLastDelegatedDownEventTime;
+
+        @Override
+        public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+            if (event.getActionMasked() == ACTION_UP) {
+                transitionTo(mDetectingState);
+            }
+
+            if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+                mLastDelegatedDownEventTime = event.getDownTime();
+            }
+            if (getNext() != null) {
+                // We cache some events to see if the user wants to trigger magnification.
+                // If no magnification is triggered we inject these events with adjusted
+                // time and down time to prevent subsequent transformations being confused
+                // by stale events. After the cached events, which always have a down, are
+                // injected we need to also update the down time of all subsequent non cached
+                // events. All delegated events cached and non-cached are delivered here.
+                event.setDownTime(mLastDelegatedDownEventTime);
+                dispatchTransformedEvent(event, rawEvent, policyFlags);
+            }
+        }
+    }
+
     /**
      * This class handles motion events when the event dispatch has not yet
      * determined what the user is doing. It watches for various tap events.
-     *
-     * @see #STATE_DETECTING
      */
-    final class DetectingStateHandler implements MotionEventHandler, Handler.Callback {
+    final class DetectingState implements State, Handler.Callback {
 
         private static final int MESSAGE_ON_TRIPLE_TAP_AND_HOLD = 1;
         private static final int MESSAGE_TRANSITION_TO_DELEGATING_STATE = 2;
 
-        final int mLongTapMinDelay = ViewConfiguration.getJumpTapTimeout();
+        final int mLongTapMinDelay;
         final int mSwipeMinDistance;
         final int mMultiTapMaxDelay;
         final int mMultiTapMaxDistance;
@@ -642,9 +573,12 @@
         private MotionEvent mLastUp;
         private MotionEvent mPreLastUp;
 
+        @VisibleForTesting boolean mShortcutTriggered;
+
         Handler mHandler = new Handler(this);
 
-        public DetectingStateHandler(Context context) {
+        public DetectingState(Context context) {
+            mLongTapMinDelay = ViewConfiguration.getLongPressTimeout();
             mMultiTapMaxDelay = ViewConfiguration.getDoubleTapTimeout()
                     + context.getResources().getInteger(
                     com.android.internal.R.integer.config_screen_magnification_multi_tap_adjustment);
@@ -661,7 +595,7 @@
                 }
                 break;
                 case MESSAGE_TRANSITION_TO_DELEGATING_STATE: {
-                    transitionToDelegatingState(/* andClear */ true);
+                    transitionToDelegatingStateAndClear();
                 }
                 break;
                 default: {
@@ -682,12 +616,12 @@
                     if (!mMagnificationController.magnificationRegionContains(
                             event.getX(), event.getY())) {
 
-                        transitionToDelegatingState(/* andClear */ !mShortcutTriggered);
+                        transitionToDelegatingStateAndClear();
 
                     } else if (isMultiTapTriggered(2 /* taps */)) {
 
                         // 3tap and hold
-                        delayedTransitionToDraggingState(event);
+                        afterLongTapTimeoutTransitionToDraggingState(event);
 
                     } else if (mDetectTripleTap
                             // If magnified, delay an ACTION_DOWN for mMultiTapMaxDelay
@@ -695,21 +629,21 @@
                             // STATE_PANNING_SCALING(triggerable with ACTION_POINTER_DOWN)
                             || mMagnificationController.isMagnifying()) {
 
-                        delayedTransitionToDelegatingState();
+                        afterMultiTapTimeoutTransitionToDelegatingState();
 
                     } else {
 
                         // Delegate pending events without delay
-                        transitionToDelegatingState(/* andClear */ true);
+                        transitionToDelegatingStateAndClear();
                     }
                 }
                 break;
                 case ACTION_POINTER_DOWN: {
                     if (mMagnificationController.isMagnifying()) {
-                        transitionTo(STATE_PANNING_SCALING);
+                        transitionTo(mPanningScalingState);
                         clear();
                     } else {
-                        transitionToDelegatingState(/* andClear */ true);
+                        transitionToDelegatingStateAndClear();
                     }
                 }
                 break;
@@ -722,7 +656,7 @@
                             && !isMultiTapTriggered(2 /* taps */)) {
 
                         // Swipe detected - delegate skipping timeout
-                        transitionToDelegatingState(/* andClear */ true);
+                        transitionToDelegatingStateAndClear();
                     }
                 }
                 break;
@@ -733,7 +667,7 @@
                     if (!mMagnificationController.magnificationRegionContains(
                             event.getX(), event.getY())) {
 
-                        transitionToDelegatingState(/* andClear */ !mShortcutTriggered);
+                        transitionToDelegatingStateAndClear();
 
                     } else if (isMultiTapTriggered(3 /* taps */)) {
 
@@ -742,12 +676,11 @@
                     } else if (
                             // Possible to be false on: 3tap&drag -> scale -> PTR_UP -> UP
                             isFingerDown()
-                                //TODO long tap should never happen here
-                            && (timeBetween(mLastDown, /* mLastUp */ event) >= mLongTapMinDelay)
-                                    || distance(mLastDown, /* mLastUp */ event)
-                                            >= mSwipeMinDistance) {
+                            //TODO long tap should never happen here
+                            && ((timeBetween(mLastDown, mLastUp) >= mLongTapMinDelay)
+                                    || (distance(mLastDown, mLastUp) >= mSwipeMinDistance))) {
 
-                        transitionToDelegatingState(/* andClear */ true);
+                        transitionToDelegatingStateAndClear();
 
                     }
                 }
@@ -795,15 +728,15 @@
             return MotionEventInfo.countOf(mDelayedEventQueue, ACTION_UP);
         }
 
-        /** -> {@link #STATE_DELEGATING} */
-        public void delayedTransitionToDelegatingState() {
+        /** -> {@link DelegatingState} */
+        public void afterMultiTapTimeoutTransitionToDelegatingState() {
             mHandler.sendEmptyMessageDelayed(
                     MESSAGE_TRANSITION_TO_DELEGATING_STATE,
                     mMultiTapMaxDelay);
         }
 
-        /** -> {@link #STATE_VIEWPORT_DRAGGING} */
-        public void delayedTransitionToDraggingState(MotionEvent event) {
+        /** -> {@link ViewportDraggingState} */
+        public void afterLongTapTimeoutTransitionToDraggingState(MotionEvent event) {
             mHandler.sendMessageDelayed(
                     mHandler.obtainMessage(MESSAGE_ON_TRIPLE_TAP_AND_HOLD, event),
                     ViewConfiguration.getLongPressTimeout());
@@ -846,11 +779,7 @@
                 MotionEventInfo info = mDelayedEventQueue;
                 mDelayedEventQueue = info.mNext;
 
-                // Because MagnifiedInteractionStateHandler requires well-formed event stream
-                mPanningScalingStateHandler.onMotionEvent(
-                        info.event, info.rawEvent, info.policyFlags);
-
-                delegateEvent(info.event, info.rawEvent, info.policyFlags);
+                handleEventWith(mDelegatingState, info.event, info.rawEvent, info.policyFlags);
 
                 info.recycle();
             }
@@ -868,10 +797,10 @@
             mLastUp = null;
         }
 
-        void transitionToDelegatingState(boolean andClear) {
-            transitionTo(STATE_DELEGATING);
+        void transitionToDelegatingStateAndClear() {
+            transitionTo(mDelegatingState);
             sendDelayedMotionEvents();
-            if (andClear) clear();
+            clear();
         }
 
         private void onTripleTap(MotionEvent up) {
@@ -895,24 +824,40 @@
             if (DEBUG_DETECTING) Slog.i(LOG_TAG, "onTripleTapAndHold()");
             clear();
 
-            mViewportDraggingStateHandler.mZoomedInBeforeDrag =
+            mViewportDraggingState.mZoomedInBeforeDrag =
                     mMagnificationController.isMagnifying();
 
             zoomOn(down.getX(), down.getY());
 
-            transitionTo(STATE_VIEWPORT_DRAGGING);
+            transitionTo(mViewportDraggingState);
         }
 
         @Override
         public String toString() {
-            return "DetectingStateHandler{" +
+            return "DetectingState{" +
                     "tapCount()=" + tapCount() +
+                    ", mShortcutTriggered=" + mShortcutTriggered +
                     ", mDelayedEventQueue=" + MotionEventInfo.toString(mDelayedEventQueue) +
                     '}';
         }
+
+        void toggleShortcutTriggered() {
+            setShortcutTriggered(!mShortcutTriggered);
+        }
+
+        void setShortcutTriggered(boolean state) {
+            if (mShortcutTriggered == state) {
+                return;
+            }
+
+            mShortcutTriggered = state;
+            mMagnificationController.setForceShowMagnifiableBounds(state);
+        }
     }
 
     private void zoomOn(float centerX, float centerY) {
+        if (DEBUG_DETECTING) Slog.i(LOG_TAG, "zoomOn(" + centerX + ", " + centerY + ")");
+
         final float scale = MathUtils.constrain(
                 mMagnificationController.getPersistedScale(),
                 MIN_SCALE, MAX_SCALE);
@@ -923,6 +868,8 @@
     }
 
     private void zoomOff() {
+        if (DEBUG_DETECTING) Slog.i(LOG_TAG, "zoomOff()");
+
         mMagnificationController.reset(/* animate */ true);
     }
 
@@ -935,16 +882,15 @@
 
     @Override
     public String toString() {
-        return "MagnificationGestureHandler{" +
-                "mDetectingStateHandler=" + mDetectingStateHandler +
-                ", mMagnifiedInteractionStateHandler=" + mPanningScalingStateHandler +
-                ", mViewportDraggingStateHandler=" + mViewportDraggingStateHandler +
+        return "MagnificationGesture{" +
+                "mDetectingState=" + mDetectingState +
+                ", mDelegatingState=" + mDelegatingState +
+                ", mMagnifiedInteractionState=" + mPanningScalingState +
+                ", mViewportDraggingState=" + mViewportDraggingState +
                 ", mDetectTripleTap=" + mDetectTripleTap +
                 ", mDetectShortcutTrigger=" + mDetectShortcutTrigger +
-                ", mCurrentState=" + stateToString(mCurrentState) +
-                ", mPreviousState=" + stateToString(mPreviousState) +
-                ", mShortcutTriggered=" + mShortcutTriggered +
-                ", mDelegatingStateDownTime=" + mDelegatingStateDownTime +
+                ", mCurrentState=" + State.nameOf(mCurrentState) +
+                ", mPreviousState=" + State.nameOf(mPreviousState) +
                 ", mMagnificationController=" + mMagnificationController +
                 '}';
     }
@@ -1051,7 +997,7 @@
 
         @Override
         public void onReceive(Context context, Intent intent) {
-            mGestureHandler.setShortcutTriggered(false);
+            mGestureHandler.mDetectingState.setShortcutTriggered(false);
         }
     }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
index 48041ad..b6b7812 100644
--- a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
+++ b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
@@ -30,13 +30,13 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.view.InputDevice;
-import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.WindowManagerPolicy;
-import android.view.accessibility.AccessibilityEvent;
+
 import com.android.internal.os.SomeArgs;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -45,7 +45,7 @@
  * <p>
  * All methods except {@code injectEvents} must be called only from the main thread.
  */
-public class MotionEventInjector implements EventStreamTransformation, Handler.Callback {
+public class MotionEventInjector extends BaseEventStreamTransformation implements Handler.Callback {
     private static final String LOG_TAG = "MotionEventInjector";
     private static final int MESSAGE_SEND_MOTION_EVENT = 1;
     private static final int MESSAGE_INJECT_EVENTS = 2;
@@ -68,7 +68,6 @@
     private final Handler mHandler;
     private final SparseArray<Boolean> mOpenGesturesInProgress = new SparseArray<>();
 
-    private EventStreamTransformation mNext;
     private IAccessibilityServiceClient mServiceInterfaceForCurrentGesture;
     private IntArray mSequencesInProgress = new IntArray(5);
     private boolean mIsDestroyed = false;
@@ -117,25 +116,6 @@
     }
 
     @Override
-    public void onKeyEvent(KeyEvent event, int policyFlags) {
-        if (mNext != null) {
-            mNext.onKeyEvent(event, policyFlags);
-        }
-    }
-
-    @Override
-    public void onAccessibilityEvent(AccessibilityEvent event) {
-        if (mNext != null) {
-            mNext.onAccessibilityEvent(event);
-        }
-    }
-
-    @Override
-    public void setNext(EventStreamTransformation next) {
-        mNext = next;
-    }
-
-    @Override
     public void clearEvents(int inputSource) {
         /*
          * Reset state for motion events passing through so we won't send a cancel event for
@@ -187,7 +167,7 @@
             return;
         }
 
-        if (mNext == null) {
+        if (getNext() == null) {
             notifyService(serviceInterface, sequence, false);
             return;
         }
@@ -262,17 +242,24 @@
                 int continuedPointerId = mStrokeIdToPointerId
                         .get(touchPoint.mContinuedStrokeId, -1);
                 if (continuedPointerId == -1) {
+                    Slog.w(LOG_TAG, "Can't continue gesture due to unknown continued stroke id in "
+                            + touchPoint);
                     return false;
                 }
                 mStrokeIdToPointerId.put(touchPoint.mStrokeId, continuedPointerId);
                 int lastPointIndex = findPointByStrokeId(
                         mLastTouchPoints, mNumLastTouchPoints, touchPoint.mContinuedStrokeId);
                 if (lastPointIndex < 0) {
+                    Slog.w(LOG_TAG, "Can't continue gesture due continued gesture id of "
+                            + touchPoint + " not matching any previous strokes in "
+                            + Arrays.asList(mLastTouchPoints));
                     return false;
                 }
                 if (mLastTouchPoints[lastPointIndex].mIsEndOfPath
                         || (mLastTouchPoints[lastPointIndex].mX != touchPoint.mX)
                         || (mLastTouchPoints[lastPointIndex].mY != touchPoint.mY)) {
+                    Slog.w(LOG_TAG, "Can't continue gesture due to points mismatch between "
+                            + mLastTouchPoints[lastPointIndex] + " and " + touchPoint);
                     return false;
                 }
                 // Update the last touch point to match the continuation, so the gestures will
@@ -292,8 +279,8 @@
 
     private void sendMotionEventToNext(MotionEvent event, MotionEvent rawEvent,
             int policyFlags) {
-        if (mNext != null) {
-            mNext.onMotionEvent(event, rawEvent, policyFlags);
+        if (getNext() != null) {
+            super.onMotionEvent(event, rawEvent, policyFlags);
             if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
                 mOpenGesturesInProgress.put(event.getSource(), true);
             }
@@ -305,7 +292,7 @@
     }
 
     private void cancelAnyGestureInProgress(int source) {
-        if ((mNext != null) && mOpenGesturesInProgress.get(source, false)) {
+        if ((getNext() != null) && mOpenGesturesInProgress.get(source, false)) {
             long now = SystemClock.uptimeMillis();
             MotionEvent cancelEvent =
                     obtainMotionEvent(now, now, MotionEvent.ACTION_CANCEL, getLastTouchPoints(), 1);
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index e380f2c..a32686d 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -55,7 +55,8 @@
  *
  * @hide
  */
-class TouchExplorer implements EventStreamTransformation, AccessibilityGestureDetector.Listener {
+class TouchExplorer extends BaseEventStreamTransformation
+        implements AccessibilityGestureDetector.Listener {
 
     private static final boolean DEBUG = false;
 
@@ -131,9 +132,6 @@
     // the two dragging pointers as opposed to use the location of the primary one.
     private final int mScaledMinPointerDistanceToUseMiddleLocation;
 
-    // The handler to which to delegate events.
-    private EventStreamTransformation mNext;
-
     // Helper class to track received pointers.
     private final ReceivedPointerTracker mReceivedPointerTracker;
 
@@ -198,9 +196,7 @@
         if (inputSource == InputDevice.SOURCE_TOUCHSCREEN) {
             clear();
         }
-        if (mNext != null) {
-            mNext.clearEvents(inputSource);
-        }
+        super.clearEvents(inputSource);
     }
 
     @Override
@@ -258,16 +254,9 @@
     }
 
     @Override
-    public void setNext(EventStreamTransformation next) {
-        mNext = next;
-    }
-
-    @Override
     public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
         if (!event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)) {
-            if (mNext != null) {
-                mNext.onMotionEvent(event, rawEvent, policyFlags);
-            }
+            super.onMotionEvent(event, rawEvent, policyFlags);
             return;
         }
 
@@ -311,13 +300,6 @@
     }
 
     @Override
-    public void onKeyEvent(KeyEvent event, int policyFlags) {
-        if (mNext != null) {
-            mNext.onKeyEvent(event, policyFlags);
-        }
-    }
-
-    @Override
     public void onAccessibilityEvent(AccessibilityEvent event) {
         final int eventType = event.getEventType();
 
@@ -353,9 +335,7 @@
                 mLastTouchedWindowId = event.getWindowId();
             } break;
         }
-        if (mNext != null) {
-            mNext.onAccessibilityEvent(event);
-        }
+        super.onAccessibilityEvent(event);
     }
 
     @Override
@@ -969,12 +949,10 @@
 
         // Make sure that the user will see the event.
         policyFlags |= WindowManagerPolicy.FLAG_PASS_TO_USER;
-        if (mNext != null) {
-            // TODO: For now pass null for the raw event since the touch
-            //       explorer is the last event transformation and it does
-            //       not care about the raw event.
-            mNext.onMotionEvent(event, null, policyFlags);
-        }
+        // TODO: For now pass null for the raw event since the touch
+        //       explorer is the last event transformation and it does
+        //       not care about the raw event.
+        super.onMotionEvent(event, null, policyFlags);
 
         mInjectedPointerTracker.onMotionEvent(event);
 
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index a6aaaa67..51afada 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -71,7 +71,6 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.os.storage.StorageManager;
 import android.service.appwidget.AppWidgetServiceDumpProto;
 import android.service.appwidget.WidgetProto;
 import android.text.TextUtils;
@@ -159,7 +158,9 @@
     // Bump if the stored widgets need to be upgraded.
     private static final int CURRENT_VERSION = 1;
 
-    private static final AtomicLong REQUEST_COUNTER = new AtomicLong();
+    // Every widget update request is associated which an increasing sequence number. This is
+    // used to verify which request has successfully been received by the host.
+    private static final AtomicLong UPDATE_COUNTER = new AtomicLong();
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
@@ -814,9 +815,9 @@
             Host host = lookupOrAddHostLocked(id);
             host.callbacks = callbacks;
 
+            long updateSequenceNo = UPDATE_COUNTER.incrementAndGet();
             int N = appWidgetIds.length;
             ArrayList<PendingHostUpdate> outUpdates = new ArrayList<>(N);
-
             LongSparseArray<PendingHostUpdate> updatesMap = new LongSparseArray<>();
             for (int i = 0; i < N; i++) {
                 if (host.getPendingUpdatesForId(appWidgetIds[i], updatesMap)) {
@@ -828,6 +829,8 @@
                     }
                 }
             }
+            // Reset the update counter once all the updates have been calculated
+            host.lastWidgetUpdateSequenceNo = updateSequenceNo;
             return new ParceledListSlice<>(outUpdates);
         }
     }
@@ -1914,9 +1917,9 @@
             // method with a wrong id. In that case, ignore the call.
             return;
         }
-        long requestId = REQUEST_COUNTER.incrementAndGet();
+        long requestId = UPDATE_COUNTER.incrementAndGet();
         if (widget != null) {
-            widget.updateRequestIds.put(viewId, requestId);
+            widget.updateSequenceNos.put(viewId, requestId);
         }
         if (widget == null || widget.host == null || widget.host.zombie
                 || widget.host.callbacks == null || widget.provider == null
@@ -1941,7 +1944,7 @@
             int appWidgetId, int viewId, long requestId) {
         try {
             callbacks.viewDataChanged(appWidgetId, viewId);
-            host.lastWidgetUpdateRequestId = requestId;
+            host.lastWidgetUpdateSequenceNo = requestId;
         } catch (RemoteException re) {
             // It failed; remove the callback. No need to prune because
             // we know that this host is still referenced by this instance.
@@ -1988,9 +1991,9 @@
     }
 
     private void scheduleNotifyUpdateAppWidgetLocked(Widget widget, RemoteViews updateViews) {
-        long requestId = REQUEST_COUNTER.incrementAndGet();
+        long requestId = UPDATE_COUNTER.incrementAndGet();
         if (widget != null) {
-            widget.updateRequestIds.put(ID_VIEWS_UPDATE, requestId);
+            widget.updateSequenceNos.put(ID_VIEWS_UPDATE, requestId);
         }
         if (widget == null || widget.provider == null || widget.provider.zombie
                 || widget.host.callbacks == null || widget.host.zombie) {
@@ -2013,7 +2016,7 @@
             int appWidgetId, RemoteViews views, long requestId) {
         try {
             callbacks.updateAppWidget(appWidgetId, views);
-            host.lastWidgetUpdateRequestId = requestId;
+            host.lastWidgetUpdateSequenceNo = requestId;
         } catch (RemoteException re) {
             synchronized (mLock) {
                 Slog.e(TAG, "Widget host dead: " + host.id, re);
@@ -2023,11 +2026,11 @@
     }
 
     private void scheduleNotifyProviderChangedLocked(Widget widget) {
-        long requestId = REQUEST_COUNTER.incrementAndGet();
+        long requestId = UPDATE_COUNTER.incrementAndGet();
         if (widget != null) {
             // When the provider changes, reset everything else.
-            widget.updateRequestIds.clear();
-            widget.updateRequestIds.append(ID_PROVIDER_CHANGED, requestId);
+            widget.updateSequenceNos.clear();
+            widget.updateSequenceNos.append(ID_PROVIDER_CHANGED, requestId);
         }
         if (widget == null || widget.provider == null || widget.provider.zombie
                 || widget.host.callbacks == null || widget.host.zombie) {
@@ -2050,7 +2053,7 @@
             int appWidgetId, AppWidgetProviderInfo info, long requestId) {
         try {
             callbacks.providerChanged(appWidgetId, info);
-            host.lastWidgetUpdateRequestId = requestId;
+            host.lastWidgetUpdateSequenceNo = requestId;
         } catch (RemoteException re) {
             synchronized (mLock){
                 Slog.e(TAG, "Widget host dead: " + host.id, re);
@@ -3887,7 +3890,11 @@
         boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
 
         int tag = TAG_UNDEFINED; // for use while saving state (the index)
-        long lastWidgetUpdateRequestId; // request id for the last update successfully sent
+        // Sequence no for the last update successfully sent. This is updated whenever a
+        // widget update is successfully sent to the host callbacks. As all new/undelivered updates
+        // will have sequenceNo greater than this, all those updates will be sent when the host
+        // callbacks are attached again.
+        long lastWidgetUpdateSequenceNo;
 
         public int getUserId() {
             return UserHandle.getUserId(id.uid);
@@ -3914,18 +3921,18 @@
          */
         public boolean getPendingUpdatesForId(int appWidgetId,
                 LongSparseArray<PendingHostUpdate> outUpdates) {
-            long updateRequestId = lastWidgetUpdateRequestId;
+            long updateSequenceNo = lastWidgetUpdateSequenceNo;
             int N = widgets.size();
             for (int i = 0; i < N; i++) {
                 Widget widget = widgets.get(i);
                 if (widget.appWidgetId == appWidgetId) {
                     outUpdates.clear();
-                    for (int j = widget.updateRequestIds.size() - 1; j >= 0; j--) {
-                        long requestId = widget.updateRequestIds.valueAt(j);
-                        if (requestId <= updateRequestId) {
+                    for (int j = widget.updateSequenceNos.size() - 1; j >= 0; j--) {
+                        long requestId = widget.updateSequenceNos.valueAt(j);
+                        if (requestId <= updateSequenceNo) {
                             continue;
                         }
-                        int id = widget.updateRequestIds.keyAt(j);
+                        int id = widget.updateSequenceNos.keyAt(j);
                         final PendingHostUpdate update;
                         switch (id) {
                             case ID_PROVIDER_CHANGED:
@@ -4021,8 +4028,8 @@
         RemoteViews maskedViews;
         Bundle options;
         Host host;
-        // Request ids for various operations
-        SparseLongArray updateRequestIds = new SparseLongArray(2);
+        // Map of request type to updateSequenceNo.
+        SparseLongArray updateSequenceNos = new SparseLongArray(2);
 
         @Override
         public String toString() {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 880f236..075c741 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -52,6 +52,7 @@
 import android.service.autofill.FillResponse;
 import android.service.autofill.IAutoFillService;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.DebugUtils;
 import android.util.LocalLog;
@@ -338,6 +339,8 @@
             return;
         }
 
+        session.logContextCommittedLocked();
+
         final boolean finished = session.showSaveLocked();
         if (sVerbose) Slog.v(TAG, "finishSessionLocked(): session finished on save? " + finished);
 
@@ -563,8 +566,9 @@
     void setAuthenticationSelected(int sessionId, @Nullable Bundle clientState) {
         synchronized (mLock) {
             if (isValidEventLocked("setAuthenticationSelected()", sessionId)) {
-                mEventHistory
-                        .addEvent(new Event(Event.TYPE_AUTHENTICATION_SELECTED, null, clientState));
+                mEventHistory.addEvent(
+                        new Event(Event.TYPE_AUTHENTICATION_SELECTED, null, clientState, null, null,
+                                null, null, null, null));
             }
         }
     }
@@ -578,7 +582,7 @@
             if (isValidEventLocked("logDatasetAuthenticationSelected()", sessionId)) {
                 mEventHistory.addEvent(
                         new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset,
-                                clientState));
+                                clientState, null, null, null, null, null, null));
             }
         }
     }
@@ -589,7 +593,8 @@
     void logSaveShown(int sessionId, @Nullable Bundle clientState) {
         synchronized (mLock) {
             if (isValidEventLocked("logSaveShown()", sessionId)) {
-                mEventHistory.addEvent(new Event(Event.TYPE_SAVE_SHOWN, null, clientState));
+                mEventHistory.addEvent(new Event(Event.TYPE_SAVE_SHOWN, null, clientState, null,
+                        null, null, null, null, null));
             }
         }
     }
@@ -602,7 +607,28 @@
         synchronized (mLock) {
             if (isValidEventLocked("logDatasetSelected()", sessionId)) {
                 mEventHistory.addEvent(
-                        new Event(Event.TYPE_DATASET_SELECTED, selectedDataset, clientState));
+                        new Event(Event.TYPE_DATASET_SELECTED, selectedDataset, clientState, null,
+                                null, null, null, null, null));
+            }
+        }
+    }
+
+    /**
+     * Updates the last fill response when an autofill context is committed.
+     */
+    void logContextCommitted(int sessionId, @Nullable Bundle clientState,
+            @Nullable ArrayList<String> selectedDatasets,
+            @Nullable ArraySet<String> ignoredDatasets,
+            @Nullable ArrayList<AutofillId> changedFieldIds,
+            @Nullable ArrayList<String> changedDatasetIds,
+            @Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
+            @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds) {
+        synchronized (mLock) {
+            if (isValidEventLocked("logDatasetNotSelected()", sessionId)) {
+                mEventHistory.addEvent(new Event(Event.TYPE_CONTEXT_COMMITTED, null,
+                        clientState, selectedDatasets, ignoredDatasets,
+                        changedFieldIds, changedDatasetIds,
+                        manuallyFilledFieldIds, manuallyFilledDatasetIds));
             }
         }
     }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index ed00ffe..59fc34d 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -54,6 +54,7 @@
 import android.service.autofill.AutofillService;
 import android.service.autofill.Dataset;
 import android.service.autofill.FillContext;
+import android.service.autofill.FillEventHistory;
 import android.service.autofill.FillRequest;
 import android.service.autofill.FillResponse;
 import android.service.autofill.InternalSanitizer;
@@ -90,6 +91,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -495,7 +497,7 @@
             notifyUnavailableToClient(false);
         }
         synchronized (mLock) {
-            processResponseLocked(response, requestFlags);
+            processResponseLocked(response, null, requestFlags);
         }
 
         final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_REQUEST, servicePackageName)
@@ -762,13 +764,21 @@
         }
 
         final Parcelable result = data.getParcelable(AutofillManager.EXTRA_AUTHENTICATION_RESULT);
-        if (sDebug) Slog.d(TAG, "setAuthenticationResultLocked(): result=" + result);
+        final Bundle newClientState = data.getBundle(AutofillManager.EXTRA_CLIENT_STATE);
+        if (sDebug) {
+            Slog.d(TAG, "setAuthenticationResultLocked(): result=" + result
+                    + ", clientState=" + newClientState);
+        }
         if (result instanceof FillResponse) {
             writeLog(MetricsEvent.AUTOFILL_AUTHENTICATED);
-            replaceResponseLocked(authenticatedResponse, (FillResponse) result);
+            replaceResponseLocked(authenticatedResponse, (FillResponse) result, newClientState);
         } else if (result instanceof Dataset) {
             if (datasetIdx != AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED) {
                 writeLog(MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED);
+                if (newClientState != null) {
+                    if (sDebug) Slog.d(TAG,  "Updating client state from auth dataset");
+                    mClientState = newClientState;
+                }
                 final Dataset dataset = (Dataset) result;
                 authenticatedResponse.getDatasets().set(datasetIdx, dataset);
                 autoFill(requestId, datasetIdx, dataset, false);
@@ -832,6 +842,194 @@
     }
 
     /**
+     * Generates a {@link android.service.autofill.FillEventHistory.Event#TYPE_CONTEXT_COMMITTED}
+     * when necessary.
+     */
+    public void logContextCommittedLocked() {
+        if (mResponses == null) {
+            if (sVerbose) Slog.v(TAG, "logContextCommittedLocked(): skipped (no responses)");
+            return;
+        }
+
+        final FillResponse lastResponse = mResponses.valueAt(mResponses.size() -1);
+        final int flags = lastResponse.getFlags();
+        if ((flags & FillResponse.FLAG_TRACK_CONTEXT_COMMITED) == 0) {
+            if (sDebug) Slog.d(TAG, "logContextCommittedLocked(): ignored by flags " + flags);
+            return;
+        }
+
+        ArraySet<String> ignoredDatasets = null;
+        ArrayList<AutofillId> changedFieldIds = null;
+        ArrayList<String> changedDatasetIds = null;
+        ArrayMap<AutofillId, ArraySet<String>> manuallyFilledIds = null;
+
+        boolean hasAtLeastOneDataset = false;
+        final int responseCount = mResponses.size();
+        for (int i = 0; i < responseCount; i++) {
+            final FillResponse response = mResponses.valueAt(i);
+            final List<Dataset> datasets = response.getDatasets();
+            if (datasets == null || datasets.isEmpty()) {
+                if (sVerbose) Slog.v(TAG,  "logContextCommitted() no datasets at " + i);
+            } else {
+                for (int j = 0; j < datasets.size(); j++) {
+                    final Dataset dataset = datasets.get(j);
+                    final String datasetId = dataset.getId();
+                    if (datasetId == null) {
+                        if (sVerbose) {
+                            Slog.v(TAG, "logContextCommitted() skipping idless dataset " + dataset);
+                        }
+                    } else {
+                        hasAtLeastOneDataset = true;
+                        if (mSelectedDatasetIds == null
+                                || !mSelectedDatasetIds.contains(datasetId)) {
+                            if (sVerbose) Slog.v(TAG, "adding ignored dataset " + datasetId);
+                            if (ignoredDatasets == null) {
+                                ignoredDatasets = new ArraySet<>();
+                            }
+                            ignoredDatasets.add(datasetId);
+                        }
+                    }
+                }
+            }
+        }
+        if (!hasAtLeastOneDataset) {
+            if (sVerbose) Slog.v(TAG, "logContextCommittedLocked(): skipped (no datasets)");
+            return;
+        }
+
+        for (int i = 0; i < mViewStates.size(); i++) {
+            final ViewState viewState = mViewStates.valueAt(i);
+            final int state = viewState.getState();
+
+            // When value changed, we need to log if it was:
+            // - autofilled -> changedDatasetIds
+            // - not autofilled but matches a dataset value -> manuallyFilledIds
+            if ((state & ViewState.STATE_CHANGED) != 0) {
+
+                // Check if autofilled value was changed
+                if ((state & ViewState.STATE_AUTOFILLED) != 0) {
+                    final String datasetId = viewState.getDatasetId();
+                    if (datasetId == null) {
+                        // Sanity check - should never happen.
+                        Slog.w(TAG, "logContextCommitted(): no dataset id on " + viewState);
+                        continue;
+                    }
+
+                    // Must first check if final changed value is not the same as value sent by
+                    // service.
+                    final AutofillValue autofilledValue = viewState.getAutofilledValue();
+                    final AutofillValue currentValue = viewState.getCurrentValue();
+                    if (autofilledValue != null && autofilledValue.equals(currentValue)) {
+                        if (sDebug) {
+                            Slog.d(TAG, "logContextCommitted(): ignoring changed " + viewState
+                                    + " because it has same value that was autofilled");
+                        }
+                        continue;
+                    }
+
+                    if (sDebug) {
+                        Slog.d(TAG, "logContextCommitted() found changed state: " + viewState);
+                    }
+                    if (changedFieldIds == null) {
+                        changedFieldIds = new ArrayList<>();
+                        changedDatasetIds = new ArrayList<>();
+                    }
+                    changedFieldIds.add(viewState.id);
+                    changedDatasetIds.add(datasetId);
+                } else {
+                    // Check if value match a dataset.
+                    final AutofillValue currentValue = viewState.getCurrentValue();
+                    if (currentValue == null) {
+                        if (sDebug) {
+                            Slog.d(TAG, "logContextCommitted(): skipping view witout current value "
+                                    + "( " + viewState + ")");
+                        }
+                        continue;
+                    }
+                    for (int j = 0; j < responseCount; j++) {
+                        final FillResponse response = mResponses.valueAt(j);
+                        final List<Dataset> datasets = response.getDatasets();
+                        if (datasets == null || datasets.isEmpty()) {
+                            if (sVerbose) Slog.v(TAG,  "logContextCommitted() no datasets at " + j);
+                        } else {
+                            for (int k = 0; k < datasets.size(); k++) {
+                                final Dataset dataset = datasets.get(k);
+                                final String datasetId = dataset.getId();
+                                if (datasetId == null) {
+                                    if (sVerbose) {
+                                        Slog.v(TAG, "logContextCommitted() skipping idless dataset "
+                                                + dataset);
+                                    }
+                                } else {
+                                    final ArrayList<AutofillValue> values = dataset.getFieldValues();
+                                    for (int l = 0; l < values.size(); l++) {
+                                        final AutofillValue candidate = values.get(l);
+                                        if (currentValue.equals(candidate)) {
+                                            if (sDebug) {
+                                                Slog.d(TAG, "field " + viewState.id
+                                                        + " was manually filled with value set by "
+                                                        + "dataset " + datasetId);
+                                            }
+                                            if (manuallyFilledIds == null) {
+                                                manuallyFilledIds = new ArrayMap<>();
+                                            }
+                                            ArraySet<String> datasetIds =
+                                                    manuallyFilledIds.get(viewState.id);
+                                            if (datasetIds == null) {
+                                                datasetIds = new ArraySet<>(1);
+                                                manuallyFilledIds.put(viewState.id, datasetIds);
+                                            }
+                                            datasetIds.add(datasetId);
+                                        }
+                                    }
+                                    if (mSelectedDatasetIds == null
+                                            || !mSelectedDatasetIds.contains(datasetId)) {
+                                        if (sVerbose) {
+                                            Slog.v(TAG, "adding ignored dataset " + datasetId);
+                                        }
+                                        if (ignoredDatasets == null) {
+                                            ignoredDatasets = new ArraySet<>();
+                                        }
+                                        ignoredDatasets.add(datasetId);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        if (sVerbose) {
+            Slog.v(TAG, "logContextCommitted(): id=" + id
+                    + ", selectedDatasetids=" + mSelectedDatasetIds
+                    + ", ignoredDatasetIds=" + ignoredDatasets
+                    + ", changedAutofillIds=" + changedFieldIds
+                    + ", changedDatasetIds=" + changedDatasetIds
+                    + ", manuallyFilledIds=" + manuallyFilledIds);
+        }
+
+        ArrayList<AutofillId> manuallyFilledFieldIds = null;
+        ArrayList<ArrayList<String>> manuallyFilledDatasetIds = null;
+
+        // Must "flatten" the map to the parcellable collection primitives
+        if (manuallyFilledIds != null) {
+            final int size = manuallyFilledIds.size();
+            manuallyFilledFieldIds = new ArrayList<>(size);
+            manuallyFilledDatasetIds = new ArrayList<>(size);
+            for (int i = 0; i < size; i++) {
+                final AutofillId fieldId = manuallyFilledIds.keyAt(i);
+                final ArraySet<String> datasetIds = manuallyFilledIds.valueAt(i);
+                manuallyFilledFieldIds.add(fieldId);
+                manuallyFilledDatasetIds.add(new ArrayList<>(datasetIds));
+            }
+        }
+        mService.logContextCommitted(id, mClientState, mSelectedDatasetIds, ignoredDatasets,
+                changedFieldIds, changedDatasetIds,
+                manuallyFilledFieldIds, manuallyFilledDatasetIds);
+    }
+
+    /**
      * Shows the save UI, when session can be saved.
      *
      * @return {@code true} if session is done, or {@code false} if it's pending user action.
@@ -962,6 +1160,7 @@
                     boolean isValid;
                     try {
                         isValid = validator.isValid(valueFinder);
+                        if (sDebug) Slog.d(TAG, validator + " returned " + isValid);
                         log.setType(isValid
                                 ? MetricsEvent.TYPE_SUCCESS
                                 : MetricsEvent.TYPE_DISMISS);
@@ -1491,8 +1690,14 @@
 
         ArraySet<AutofillId> trackedViews = null;
         boolean saveOnAllViewsInvisible = false;
+        boolean saveOnFinish = true;
         final SaveInfo saveInfo = response.getSaveInfo();
+        final AutofillId saveTriggerId;
         if (saveInfo != null) {
+            saveTriggerId = saveInfo.getTriggerId();
+            if (saveTriggerId != null) {
+                writeLog(MetricsEvent.AUTOFILL_EXPLICIT_SAVE_TRIGGER_DEFINITION);
+            }
             saveOnAllViewsInvisible =
                     (saveInfo.getFlags() & SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE) != 0;
 
@@ -1509,6 +1714,12 @@
                     Collections.addAll(trackedViews, saveInfo.getOptionalIds());
                 }
             }
+            if ((saveInfo.getFlags() & SaveInfo.FLAG_DONT_SAVE_ON_FINISH) != 0) {
+                saveOnFinish = false;
+            }
+
+        } else {
+            saveTriggerId = null;
         }
 
         // Must also track that are part of datasets, otherwise the FillUI won't be hidden when
@@ -1533,17 +1744,18 @@
 
         try {
             if (sVerbose) {
-                Slog.v(TAG, "updateTrackedIdsLocked(): " + trackedViews + " => " + fillableIds);
+                Slog.v(TAG, "updateTrackedIdsLocked(): " + trackedViews + " => " + fillableIds
+                        + " (triggering on " + saveTriggerId + ")");
             }
             mClient.setTrackedViews(id, toArray(trackedViews), saveOnAllViewsInvisible,
-                    toArray(fillableIds));
+                    saveOnFinish, toArray(fillableIds), saveTriggerId);
         } catch (RemoteException e) {
             Slog.w(TAG, "Cannot set tracked ids", e);
         }
     }
 
     private void replaceResponseLocked(@NonNull FillResponse oldResponse,
-            @NonNull FillResponse newResponse) {
+            @NonNull FillResponse newResponse, @Nullable Bundle newClientState) {
         // Disassociate view states with the old response
         setViewStatesLocked(oldResponse, ViewState.STATE_INITIAL, true);
         // Move over the id
@@ -1551,7 +1763,7 @@
         // Replace the old response
         mResponses.put(newResponse.getRequestId(), newResponse);
         // Now process the new response
-        processResponseLocked(newResponse, 0);
+        processResponseLocked(newResponse, newClientState, 0);
     }
 
     private void processNullResponseLocked(int flags) {
@@ -1565,7 +1777,8 @@
         removeSelf();
     }
 
-    private void processResponseLocked(@NonNull FillResponse newResponse, int flags) {
+    private void processResponseLocked(@NonNull FillResponse newResponse,
+            @Nullable Bundle newClientState, int flags) {
         // Make sure we are hiding the UI which will be shown
         // only if handling the current response requires it.
         mUi.hideAll(this);
@@ -1573,14 +1786,18 @@
         final int requestId = newResponse.getRequestId();
         if (sVerbose) {
             Slog.v(TAG, "processResponseLocked(): mCurrentViewId=" + mCurrentViewId
-                    + ",flags=" + flags + ", reqId=" + requestId + ", resp=" + newResponse);
+                    + ",flags=" + flags + ", reqId=" + requestId + ", resp=" + newResponse
+                    + ",newClientState=" + newClientState);
         }
 
         if (mResponses == null) {
-            mResponses = new SparseArray<>(4);
+            // Set initial capacity as 2 to handle cases where service always requires auth.
+            // TODO: add a metric for number of responses set by server, so we can use its average
+            // as the initial array capacitiy.
+            mResponses = new SparseArray<>(2);
         }
         mResponses.put(requestId, newResponse);
-        mClientState = newResponse.getClientState();
+        mClientState = newClientState != null ? newClientState : newResponse.getClientState();
 
         setViewStatesLocked(newResponse, ViewState.STATE_FILLABLE, false);
         updateTrackedIdsLocked();
@@ -1653,6 +1870,10 @@
             final AutofillId id = ids.get(j);
             final AutofillValue value = values.get(j);
             final ViewState viewState = createOrUpdateViewStateLocked(id, state, value);
+            final String datasetId = dataset.getId();
+            if (datasetId != null) {
+                viewState.setDatasetId(datasetId);
+            }
             if (response != null) {
                 viewState.setResponse(response);
             } else if (clearResponse) {
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 51659bb..1d8110f 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -78,6 +78,7 @@
     private AutofillValue mAutofilledValue;
     private Rect mVirtualBounds;
     private int mState;
+    private String mDatasetId;
 
     ViewState(Session session, AutofillId id, Listener listener, int state) {
         mSession = session;
@@ -148,6 +149,15 @@
         mState &= ~state;
     }
 
+    @Nullable
+    String getDatasetId() {
+        return mDatasetId;
+    }
+
+    void setDatasetId(String datasetId) {
+        mDatasetId = datasetId;
+    }
+
     // TODO: refactor / rename / document this method (and maybeCallOnFillReady) to make it clear
     // that it can change the value and update the UI; similarly, should replace code that
     // directly sets mAutofillValue to use encapsulation.
@@ -182,13 +192,15 @@
 
     @Override
     public String toString() {
-        return "ViewState: [id=" + id + ", currentValue=" + mCurrentValue
+        return "ViewState: [id=" + id + ", datasetId=" + mDatasetId
+                + ", currentValue=" + mCurrentValue
                 + ", autofilledValue=" + mAutofilledValue
                 + ", bounds=" + mVirtualBounds + ", state=" + getStateAsString() + "]";
     }
 
     void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("id:" ); pw.println(this.id);
+        pw.print(prefix); pw.print("datasetId:" ); pw.println(this.mDatasetId);
         pw.print(prefix); pw.print("state:" ); pw.println(getStateAsString());
         pw.print(prefix); pw.print("response:");
         if (mResponse == null) {
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index bf442dc..6d3d792 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -157,6 +157,11 @@
                 final int index = dataset.getFieldIds().indexOf(focusedViewId);
                 if (index >= 0) {
                     final RemoteViews presentation = dataset.getFieldPresentation(index);
+                    if (presentation == null) {
+                        Slog.w(TAG, "not displaying UI on field " + focusedViewId + " because "
+                                + "service didn't provide a presentation for it on " + dataset);
+                        continue;
+                    }
                     final View view;
                     try {
                         if (sVerbose) Slog.v(TAG, "setting remote view for " + focusedViewId);
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index d48f23c..307f74d 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -32,11 +32,15 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.service.autofill.BatchUpdates;
 import android.service.autofill.CustomDescription;
+import android.service.autofill.InternalTransformation;
+import android.service.autofill.InternalValidator;
 import android.service.autofill.SaveInfo;
 import android.service.autofill.ValueFinder;
 import android.text.Html;
 import android.util.ArraySet;
+import android.util.Pair;
 import android.util.Slog;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -57,6 +61,7 @@
 import com.android.server.UiThread;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
 
 /**
  * Autofill Save Prompt
@@ -185,68 +190,17 @@
 
         setServiceIcon(context, view, serviceIcon);
 
-        ScrollView subtitleContainer = null;
-        final CustomDescription customDescription = info.getCustomDescription();
-        if (customDescription != null) {
-            writeLog(MetricsEvent.AUTOFILL_SAVE_CUSTOM_DESCRIPTION, type);
-
+        final boolean hasCustomDescription =
+                applyCustomDescription(context, view, valueFinder, info);
+        if (hasCustomDescription) {
             mSubTitle = null;
-            if (sDebug) Slog.d(TAG, "Using custom description");
-
-            final RemoteViews presentation = customDescription.getPresentation(valueFinder);
-            if (presentation != null) {
-                final RemoteViews.OnClickHandler handler = new RemoteViews.OnClickHandler() {
-                    @Override
-                    public boolean onClickHandler(View view, PendingIntent pendingIntent,
-                            Intent intent) {
-                        final LogMaker log =
-                                newLogMaker(MetricsEvent.AUTOFILL_SAVE_LINK_TAPPED, type);
-                        // We need to hide the Save UI before launching the pending intent, and
-                        // restore back it once the activity is finished, and that's achieved by
-                        // adding a custom extra in the activity intent.
-                        final boolean isValid = isValidLink(pendingIntent, intent);
-                        if (!isValid) {
-                            log.setType(MetricsEvent.TYPE_UNKNOWN);
-                            mMetricsLogger.write(log);
-                            return false;
-                        }
-                        if (sVerbose) Slog.v(TAG, "Intercepting custom description intent");
-                        final IBinder token = mPendingUi.getToken();
-                        intent.putExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN, token);
-                        try {
-                            pendingUi.client.startIntentSender(pendingIntent.getIntentSender(),
-                                    intent);
-                            mPendingUi.setState(PendingUi.STATE_PENDING);
-                            if (sDebug) Slog.d(TAG, "hiding UI until restored with token " + token);
-                            hide();
-                            log.setType(MetricsEvent.TYPE_OPEN);
-                            mMetricsLogger.write(log);
-                            return true;
-                        } catch (RemoteException e) {
-                            Slog.w(TAG, "error triggering pending intent: " + intent);
-                            log.setType(MetricsEvent.TYPE_FAILURE);
-                            mMetricsLogger.write(log);
-                            return false;
-                        }
-                    }
-                };
-
-                try {
-                    final View customSubtitleView = presentation.apply(context, null, handler);
-                    subtitleContainer = view.findViewById(R.id.autofill_save_custom_subtitle);
-                    subtitleContainer.addView(customSubtitleView);
-                    subtitleContainer.setVisibility(View.VISIBLE);
-                } catch (Exception e) {
-                    Slog.e(TAG, "Could not inflate custom description. ", e);
-                }
-            } else {
-                Slog.w(TAG, "could not create remote presentation for custom title");
-            }
+            if (sDebug) Slog.d(TAG, "on constructor: applied custom description");
         } else {
             mSubTitle = info.getDescription();
             if (mSubTitle != null) {
                 writeLog(MetricsEvent.AUTOFILL_SAVE_CUSTOM_SUBTITLE, type);
-                subtitleContainer = view.findViewById(R.id.autofill_save_custom_subtitle);
+                final ScrollView subtitleContainer =
+                        view.findViewById(R.id.autofill_save_custom_subtitle);
                 final TextView subtitleView = new TextView(context);
                 subtitleView.setText(mSubTitle);
                 subtitleContainer.addView(subtitleView,
@@ -293,6 +247,122 @@
         show();
     }
 
+    private boolean applyCustomDescription(@NonNull Context context, @NonNull View saveUiView,
+            @NonNull ValueFinder valueFinder, @NonNull SaveInfo info) {
+        final CustomDescription customDescription = info.getCustomDescription();
+        if (customDescription == null) {
+            return false;
+        }
+        final int type = info.getType();
+        writeLog(MetricsEvent.AUTOFILL_SAVE_CUSTOM_DESCRIPTION, type);
+
+        final RemoteViews template = customDescription.getPresentation();
+        if (template == null) {
+            Slog.w(TAG, "No remote view on custom description");
+            return false;
+        }
+
+        // First apply the unconditional transformations (if any) to the templates.
+        final ArrayList<Pair<Integer, InternalTransformation>> transformations =
+                customDescription.getTransformations();
+        if (transformations != null) {
+            if (!InternalTransformation.batchApply(valueFinder, template, transformations)) {
+                Slog.w(TAG, "could not apply main transformations on custom description");
+                return false;
+            }
+        }
+
+        final RemoteViews.OnClickHandler handler = new RemoteViews.OnClickHandler() {
+            @Override
+            public boolean onClickHandler(View view, PendingIntent pendingIntent,
+                    Intent intent) {
+                final LogMaker log =
+                        newLogMaker(MetricsEvent.AUTOFILL_SAVE_LINK_TAPPED, type);
+                // We need to hide the Save UI before launching the pending intent, and
+                // restore back it once the activity is finished, and that's achieved by
+                // adding a custom extra in the activity intent.
+                final boolean isValid = isValidLink(pendingIntent, intent);
+                if (!isValid) {
+                    log.setType(MetricsEvent.TYPE_UNKNOWN);
+                    mMetricsLogger.write(log);
+                    return false;
+                }
+                if (sVerbose) Slog.v(TAG, "Intercepting custom description intent");
+                final IBinder token = mPendingUi.getToken();
+                intent.putExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN, token);
+                try {
+                    mPendingUi.client.startIntentSender(pendingIntent.getIntentSender(),
+                            intent);
+                    mPendingUi.setState(PendingUi.STATE_PENDING);
+                    if (sDebug) Slog.d(TAG, "hiding UI until restored with token " + token);
+                    hide();
+                    log.setType(MetricsEvent.TYPE_OPEN);
+                    mMetricsLogger.write(log);
+                    return true;
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "error triggering pending intent: " + intent);
+                    log.setType(MetricsEvent.TYPE_FAILURE);
+                    mMetricsLogger.write(log);
+                    return false;
+                }
+            }
+        };
+
+        try {
+            // Create the remote view peer.
+            final View customSubtitleView = template.apply(context, null, handler);
+
+            // And apply batch updates (if any).
+            final ArrayList<Pair<InternalValidator, BatchUpdates>> updates =
+                    customDescription.getUpdates();
+            if (updates != null) {
+                final int size = updates.size();
+                if (sDebug) Slog.d(TAG, "custom description has " + size + " batch updates");
+                for (int i = 0; i < size; i++) {
+                    final Pair<InternalValidator, BatchUpdates> pair = updates.get(i);
+                    final InternalValidator condition = pair.first;
+                    if (condition == null || !condition.isValid(valueFinder)) {
+                        if (sDebug) Slog.d(TAG, "Skipping batch update #" + i );
+                        continue;
+                    }
+                    final BatchUpdates batchUpdates = pair.second;
+                    // First apply the updates...
+                    final RemoteViews templateUpdates = batchUpdates.getUpdates();
+                    if (templateUpdates != null) {
+                        if (sDebug) Slog.d(TAG, "Applying template updates for batch update #" + i);
+                        templateUpdates.reapply(context, customSubtitleView);
+                    }
+                    // Then the transformations...
+                    final ArrayList<Pair<Integer, InternalTransformation>> batchTransformations =
+                            batchUpdates.getTransformations();
+                    if (batchTransformations != null) {
+                        if (sDebug) {
+                            Slog.d(TAG, "Applying child transformation for batch update #" + i
+                                    + ": " + batchTransformations);
+                        }
+                        if (!InternalTransformation.batchApply(valueFinder, template,
+                                batchTransformations)) {
+                            Slog.w(TAG, "Could not apply child transformation for batch update "
+                                    + "#" + i + ": " + batchTransformations);
+                            return false;
+                        }
+                        template.reapply(context, customSubtitleView);
+                    }
+                }
+            }
+
+            // Finally, add the custom description to the save UI.
+            final ScrollView subtitleContainer =
+                    saveUiView.findViewById(R.id.autofill_save_custom_subtitle);
+            subtitleContainer.addView(customSubtitleView);
+            subtitleContainer.setVisibility(View.VISIBLE);
+            return true;
+        } catch (Exception e) {
+            Slog.e(TAG, "Error applying custom description. ", e);
+        }
+        return false;
+    }
+
     private void setServiceIcon(Context context, View view, Drawable serviceIcon) {
         final ImageView iconView = view.findViewById(R.id.autofill_save_icon);
         final Resources res = context.getResources();
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index eabe21f..f9213aa 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -319,7 +319,6 @@
     boolean mProvisioned;
     boolean mAutoRestore;
     PowerManager.WakeLock mWakelock;
-    HandlerThread mHandlerThread;
     BackupHandler mBackupHandler;
     PendingIntent mRunBackupIntent, mRunInitIntent;
     BroadcastReceiver mRunBackupReceiver, mRunInitReceiver;
@@ -409,43 +408,37 @@
     // Called through the trampoline from onUnlockUser(), then we buck the work
     // off to the background thread to keep the unlock time down.
     public void unlockSystemUser() {
-        mBackupHandler.post(() -> {
-            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup init");
-            sInstance.initialize(UserHandle.USER_SYSTEM);
-            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-
-            // Migrate legacy setting
-            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup migrate");
-            if (!backupSettingMigrated(UserHandle.USER_SYSTEM)) {
+        // Migrate legacy setting
+        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup migrate");
+        if (!backupSettingMigrated(UserHandle.USER_SYSTEM)) {
+            if (DEBUG) {
+                Slog.i(TAG, "Backup enable apparently not migrated");
+            }
+            final ContentResolver r = sInstance.mContext.getContentResolver();
+            final int enableState = Settings.Secure.getIntForUser(r,
+                    Settings.Secure.BACKUP_ENABLED, -1, UserHandle.USER_SYSTEM);
+            if (enableState >= 0) {
                 if (DEBUG) {
-                    Slog.i(TAG, "Backup enable apparently not migrated");
+                    Slog.i(TAG, "Migrating enable state " + (enableState != 0));
                 }
-                final ContentResolver r = sInstance.mContext.getContentResolver();
-                final int enableState = Settings.Secure.getIntForUser(r,
-                        Settings.Secure.BACKUP_ENABLED, -1, UserHandle.USER_SYSTEM);
-                if (enableState >= 0) {
-                    if (DEBUG) {
-                        Slog.i(TAG, "Migrating enable state " + (enableState != 0));
-                    }
-                    writeBackupEnableState(enableState != 0, UserHandle.USER_SYSTEM);
-                    Settings.Secure.putStringForUser(r,
-                            Settings.Secure.BACKUP_ENABLED, null, UserHandle.USER_SYSTEM);
-                } else {
-                    if (DEBUG) {
-                        Slog.i(TAG, "Backup not yet configured; retaining null enable state");
-                    }
+                writeBackupEnableState(enableState != 0, UserHandle.USER_SYSTEM);
+                Settings.Secure.putStringForUser(r,
+                        Settings.Secure.BACKUP_ENABLED, null, UserHandle.USER_SYSTEM);
+            } else {
+                if (DEBUG) {
+                    Slog.i(TAG, "Backup not yet configured; retaining null enable state");
                 }
             }
-            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+        }
+        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
 
-            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable");
-            try {
-                sInstance.setBackupEnabled(readBackupEnableState(UserHandle.USER_SYSTEM));
-            } catch (RemoteException e) {
-                // can't happen; it's a local object
-            }
-            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-        });
+        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable");
+        try {
+            sInstance.setBackupEnabled(readBackupEnableState(UserHandle.USER_SYSTEM));
+        } catch (RemoteException e) {
+            // can't happen; it's a local object
+        }
+        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
     }
 
     class ProvisionedObserver extends ContentObserver {
@@ -1220,7 +1213,7 @@
 
     // ----- Main service implementation -----
 
-    public BackupManagerService(Context context, Trampoline parent) {
+    public BackupManagerService(Context context, Trampoline parent, HandlerThread backupThread) {
         mContext = context;
         mPackageManager = context.getPackageManager();
         mPackageManagerBinder = AppGlobals.getPackageManager();
@@ -1233,9 +1226,7 @@
         mBackupManagerBinder = Trampoline.asInterface(parent.asBinder());
 
         // spin up the backup/restore handler thread
-        mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND);
-        mHandlerThread.start();
-        mBackupHandler = new BackupHandler(mHandlerThread.getLooper());
+        mBackupHandler = new BackupHandler(backupThread.getLooper());
 
         // Set up our bookkeeping
         final ContentResolver resolver = context.getContentResolver();
@@ -1360,7 +1351,7 @@
         if (DEBUG) Slog.v(TAG, "Starting with transport " + currentTransport);
 
         mTransportManager = new TransportManager(context, transportWhitelist, currentTransport,
-                mTransportBoundListener, mHandlerThread.getLooper());
+                mTransportBoundListener, backupThread.getLooper());
         mTransportManager.registerAllTransports();
 
         // Now that we know about valid backup participants, parse any
diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
index f298065..20f2369 100644
--- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
@@ -237,7 +237,6 @@
     private boolean mProvisioned;
     private boolean mAutoRestore;
     private PowerManager.WakeLock mWakelock;
-    private HandlerThread mHandlerThread;
     private BackupHandler mBackupHandler;
     private PendingIntent mRunBackupIntent;
     private PendingIntent mRunInitIntent;
@@ -556,43 +555,37 @@
     // Called through the trampoline from onUnlockUser(), then we buck the work
     // off to the background thread to keep the unlock time down.
     public void unlockSystemUser() {
-        mBackupHandler.post(() -> {
-            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup init");
-            sInstance.initialize(UserHandle.USER_SYSTEM);
-            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-
-            // Migrate legacy setting
-            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup migrate");
-            if (!backupSettingMigrated(UserHandle.USER_SYSTEM)) {
+        // Migrate legacy setting
+        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup migrate");
+        if (!backupSettingMigrated(UserHandle.USER_SYSTEM)) {
+            if (DEBUG) {
+                Slog.i(TAG, "Backup enable apparently not migrated");
+            }
+            final ContentResolver r = sInstance.mContext.getContentResolver();
+            final int enableState = Settings.Secure.getIntForUser(r,
+                    Settings.Secure.BACKUP_ENABLED, -1, UserHandle.USER_SYSTEM);
+            if (enableState >= 0) {
                 if (DEBUG) {
-                    Slog.i(TAG, "Backup enable apparently not migrated");
+                    Slog.i(TAG, "Migrating enable state " + (enableState != 0));
                 }
-                final ContentResolver r = sInstance.mContext.getContentResolver();
-                final int enableState = Settings.Secure.getIntForUser(r,
-                        Settings.Secure.BACKUP_ENABLED, -1, UserHandle.USER_SYSTEM);
-                if (enableState >= 0) {
-                    if (DEBUG) {
-                        Slog.i(TAG, "Migrating enable state " + (enableState != 0));
-                    }
-                    writeBackupEnableState(enableState != 0, UserHandle.USER_SYSTEM);
-                    Settings.Secure.putStringForUser(r,
-                            Settings.Secure.BACKUP_ENABLED, null, UserHandle.USER_SYSTEM);
-                } else {
-                    if (DEBUG) {
-                        Slog.i(TAG, "Backup not yet configured; retaining null enable state");
-                    }
+                writeBackupEnableState(enableState != 0, UserHandle.USER_SYSTEM);
+                Settings.Secure.putStringForUser(r,
+                        Settings.Secure.BACKUP_ENABLED, null, UserHandle.USER_SYSTEM);
+            } else {
+                if (DEBUG) {
+                    Slog.i(TAG, "Backup not yet configured; retaining null enable state");
                 }
             }
-            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+        }
+        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
 
-            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable");
-            try {
-                sInstance.setBackupEnabled(readBackupEnableState(UserHandle.USER_SYSTEM));
-            } catch (RemoteException e) {
-                // can't happen; it's a local object
-            }
-            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-        });
+        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable");
+        try {
+            sInstance.setBackupEnabled(readBackupEnableState(UserHandle.USER_SYSTEM));
+        } catch (RemoteException e) {
+            // can't happen; it's a local object
+        }
+        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
     }
 
     // Bookkeeping of in-flight operations for timeout etc. purposes.  The operation
@@ -729,7 +722,8 @@
 
     // ----- Main service implementation -----
 
-    public RefactoredBackupManagerService(Context context, Trampoline parent) {
+    public RefactoredBackupManagerService(Context context, Trampoline parent,
+            HandlerThread backupThread) {
         mContext = context;
         mPackageManager = context.getPackageManager();
         mPackageManagerBinder = AppGlobals.getPackageManager();
@@ -742,9 +736,7 @@
         mBackupManagerBinder = Trampoline.asInterface(parent.asBinder());
 
         // spin up the backup/restore handler thread
-        mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND);
-        mHandlerThread.start();
-        mBackupHandler = new BackupHandler(this, mHandlerThread.getLooper());
+        mBackupHandler = new BackupHandler(this, backupThread.getLooper());
 
         // Set up our bookkeeping
         final ContentResolver resolver = context.getContentResolver();
@@ -824,7 +816,7 @@
         if (DEBUG) Slog.v(TAG, "Starting with transport " + currentTransport);
 
         mTransportManager = new TransportManager(context, transportWhitelist, currentTransport,
-                mTransportBoundListener, mHandlerThread.getLooper());
+                mTransportBoundListener, backupThread.getLooper());
         mTransportManager.registerAllTransports();
 
         // Now that we know about valid backup participants, parse any
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 9739e38..9847edf 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -28,11 +28,15 @@
 import android.content.Intent;
 import android.os.Binder;
 import android.os.Environment;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemProperties;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Slog;
@@ -75,6 +79,8 @@
     final boolean mGlobalDisable;
     volatile BackupManagerServiceInterface mService;
 
+    private HandlerThread mHandlerThread;
+
     public Trampoline(Context context) {
         mContext = context;
         mGlobalDisable = isBackupDisabled();
@@ -111,11 +117,11 @@
     }
 
     protected BackupManagerServiceInterface createRefactoredBackupManagerService() {
-        return new RefactoredBackupManagerService(mContext, this);
+        return new RefactoredBackupManagerService(mContext, this, mHandlerThread);
     }
 
     protected BackupManagerServiceInterface createBackupManagerService() {
-        return new BackupManagerService(mContext, this);
+        return new BackupManagerService(mContext, this, mHandlerThread);
     }
 
     // internal control API
@@ -140,10 +146,21 @@
     }
 
     void unlockSystemUser() {
-        BackupManagerServiceInterface svc = mService;
-        if (svc != null) {
-            svc.unlockSystemUser();
-        }
+        mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND);
+        mHandlerThread.start();
+
+        Handler h = new Handler(mHandlerThread.getLooper());
+        h.post(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup init");
+            initialize(UserHandle.USER_SYSTEM);
+            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+
+            BackupManagerServiceInterface svc = mService;
+            Slog.i(TAG, "Unlocking system user; mService=" + mService);
+            if (svc != null) {
+                svc.unlockSystemUser();
+            }
+        });
     }
 
     public void setBackupServiceActive(final int userHandle, boolean makeActive) {
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 599485f..633bb3e 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -6,6 +6,7 @@
 
 LOCAL_AIDL_INCLUDES := \
     frameworks/native/aidl/binder \
+    system/core/storaged/binder \
     system/netd/server/binder \
     system/vold/binder
 
@@ -13,6 +14,7 @@
     $(call all-java-files-under,java) \
     java/com/android/server/EventLogTags.logtags \
     java/com/android/server/am/EventLogTags.logtags \
+    ../../../../system/core/storaged/binder/android/os/IStoraged.aidl \
     ../../../../system/netd/server/binder/android/net/INetd.aidl \
     ../../../../system/netd/server/binder/android/net/metrics/INetdEventListener.aidl \
     ../../../../system/vold/binder/android/os/IVold.aidl \
@@ -34,6 +36,8 @@
     time_zone_distro \
     time_zone_distro_installer \
     android.hidl.base-V1.0-java \
+    android.hardware.health-V1.0-java \
+    android.hardware.health-V2.0-java \
     android.hardware.weaver-V1.0-java \
     android.hardware.biometrics.fingerprint-V2.1-java \
     android.hardware.oemlock-V1.0-java \
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 50b8df2..4ffa5f1 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -491,7 +491,8 @@
             return Collections.emptyList();
         }
         synchronized (this) {
-            Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false);
+            Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
+                    false /* uidMismatchExpected */);
             if (pkgOps == null) {
                 return null;
             }
@@ -530,7 +531,8 @@
 
     private void pruneOp(Op op, int uid, String packageName) {
         if (op.time == 0 && op.rejectTime == 0) {
-            Ops ops = getOpsRawLocked(uid, packageName, false);
+            Ops ops = getOpsRawLocked(uid, packageName, false /* edit */,
+                    false /* uidMismatchExpected */);
             if (ops != null) {
                 ops.remove(op.op);
                 if (ops.size() <= 0) {
@@ -1046,7 +1048,9 @@
     public int checkPackage(int uid, String packageName) {
         Preconditions.checkNotNull(packageName);
         synchronized (this) {
-            if (getOpsRawLocked(uid, packageName, true) != null) {
+            Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
+                    true /* uidMismatchExpected */);
+            if (ops != null) {
                 return AppOpsManager.MODE_ALLOWED;
             } else {
                 return AppOpsManager.MODE_ERRORED;
@@ -1090,7 +1094,8 @@
     private int noteOperationUnchecked(int code, int uid, String packageName,
             int proxyUid, String proxyPackageName) {
         synchronized (this) {
-            Ops ops = getOpsRawLocked(uid, packageName, true);
+            Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
+                    false /* uidMismatchExpected */);
             if (ops == null) {
                 if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
                         + " package " + packageName);
@@ -1148,7 +1153,8 @@
         }
         ClientState client = (ClientState)token;
         synchronized (this) {
-            Ops ops = getOpsRawLocked(uid, resolvedPackageName, true);
+            Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */,
+                    false /* uidMismatchExpected */);
             if (ops == null) {
                 if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid
                         + " package " + resolvedPackageName);
@@ -1274,7 +1280,8 @@
         return uidState;
     }
 
-    private Ops getOpsRawLocked(int uid, String packageName, boolean edit) {
+    private Ops getOpsRawLocked(int uid, String packageName, boolean edit,
+            boolean uidMismatchExpected) {
         UidState uidState = getUidStateLocked(uid, edit);
         if (uidState == null) {
             return null;
@@ -1326,10 +1333,12 @@
                     if (pkgUid != uid) {
                         // Oops!  The package name is not valid for the uid they are calling
                         // under.  Abort.
-                        RuntimeException ex = new RuntimeException("here");
-                        ex.fillInStackTrace();
-                        Slog.w(TAG, "Bad call: specified package " + packageName
-                                + " under uid " + uid + " but it is really " + pkgUid, ex);
+                        if (!uidMismatchExpected) {
+                            RuntimeException ex = new RuntimeException("here");
+                            ex.fillInStackTrace();
+                            Slog.w(TAG, "Bad call: specified package " + packageName
+                                    + " under uid " + uid + " but it is really " + pkgUid, ex);
+                        }
                         return null;
                     }
                 } finally {
@@ -1359,7 +1368,8 @@
     }
 
     private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
-        Ops ops = getOpsRawLocked(uid, packageName, edit);
+        Ops ops = getOpsRawLocked(uid, packageName, edit,
+                false /* uidMismatchExpected */);
         if (ops == null) {
             return null;
         }
@@ -1393,7 +1403,8 @@
                 if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
                     // If we are the system, bypass user restrictions for certain codes
                     synchronized (this) {
-                        Ops ops = getOpsRawLocked(uid, packageName, true);
+                        Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
+                                false /* uidMismatchExpected */);
                         if ((ops != null) && ops.isPrivileged) {
                             return false;
                         }
@@ -1713,7 +1724,8 @@
                         out.startTag(null, "uid");
                         out.attribute(null, "n", Integer.toString(pkg.getUid()));
                         synchronized (this) {
-                            Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), false);
+                            Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(),
+                                    false /* edit */, false /* uidMismatchExpected */);
                             // Should always be present as the list of PackageOps is generated
                             // from Ops.
                             if (ops != null) {
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 5106c8d..46b671b 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -24,6 +24,7 @@
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
 import android.os.ShellCommand;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.util.DumpUtils;
 import com.android.server.am.BatteryStatsService;
@@ -35,9 +36,15 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.hidl.manager.V1_0.IServiceManager;
+import android.hidl.manager.V1_0.IServiceNotification;
+import android.hardware.health.V2_0.HealthInfo;
+import android.hardware.health.V2_0.IHealthInfoCallback;
+import android.hardware.health.V2_0.IHealth;
+import android.hardware.health.V2_0.Result;
 import android.os.BatteryManager;
 import android.os.BatteryManagerInternal;
-import android.os.BatteryProperties;
+import android.os.BatteryProperty;
 import android.os.Binder;
 import android.os.FileUtils;
 import android.os.Handler;
@@ -53,6 +60,7 @@
 import android.provider.Settings;
 import android.service.battery.BatteryServiceDumpProto;
 import android.util.EventLog;
+import android.util.MutableInt;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
@@ -62,6 +70,10 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 
+import java.util.Arrays;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * <p>BatteryService monitors the charging status, and charge level of the device
@@ -100,6 +112,8 @@
 
     private static final int BATTERY_SCALE = 100;    // battery capacity is a percentage
 
+    private static final long HEALTH_HAL_WAIT_MS = 1000;
+
     // Used locally for determining when to make a last ditch effort to log
     // discharge stats before the device dies.
     private int mCriticalBatteryLevel;
@@ -118,8 +132,8 @@
 
     private final Object mLock = new Object();
 
-    private BatteryProperties mBatteryProps;
-    private final BatteryProperties mLastBatteryProps = new BatteryProperties();
+    private HealthInfo mHealthInfo;
+    private final HealthInfo mLastHealthInfo = new HealthInfo();
     private boolean mBatteryLevelCritical;
     private int mLastBatteryStatus;
     private int mLastBatteryHealth;
@@ -157,6 +171,10 @@
 
     private ActivityManagerInternal mActivityManagerInternal;
 
+    private HealthServiceWrapper mHealthServiceWrapper;
+    private HealthHalCallback mHealthHalCallback;
+    private BatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
+
     public BatteryService(Context context) {
         super(context);
 
@@ -195,17 +213,12 @@
 
     @Override
     public void onStart() {
-        IBinder b = ServiceManager.getService("batteryproperties");
-        final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =
-                IBatteryPropertiesRegistrar.Stub.asInterface(b);
-        try {
-            batteryPropertiesRegistrar.registerListener(new BatteryListener());
-        } catch (RemoteException e) {
-            // Should never happen.
-        }
+        registerHealthCallback();
 
         mBinderService = new BinderService();
         publishBinderService("battery", mBinderService);
+        mBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar();
+        publishBinderService("batteryproperties", mBatteryPropertiesRegistrar);
         publishLocalService(BatteryManagerInternal.class, new LocalService());
     }
 
@@ -231,6 +244,49 @@
         }
     }
 
+    private void registerHealthCallback() {
+        mHealthServiceWrapper = new HealthServiceWrapper();
+        mHealthHalCallback = new HealthHalCallback();
+        // IHealth is lazily retrieved.
+        try {
+            mHealthServiceWrapper.init(mHealthHalCallback,
+                    new HealthServiceWrapper.IServiceManagerSupplier() {},
+                    new HealthServiceWrapper.IHealthSupplier() {});
+        } catch (RemoteException | NoSuchElementException ex) {
+            Slog.w(TAG, "health: cannot register callback. "
+                        + "BatteryService will be started with dummy values. Reason: "
+                        + ex.getClass().getSimpleName() + ": " + ex.getMessage());
+            update(new HealthInfo());
+            return;
+        }
+
+        // init register for new service notifications, and IServiceManager should return the
+        // existing service in a near future. Wait for this.update() to instantiate
+        // the initial mHealthInfo.
+        long timeWaited = 0;
+        synchronized (mLock) {
+            long beforeWait = SystemClock.uptimeMillis();
+            while (mHealthInfo == null &&
+                    (timeWaited = SystemClock.uptimeMillis() - beforeWait) < HEALTH_HAL_WAIT_MS) {
+                try {
+                    mLock.wait(HEALTH_HAL_WAIT_MS - timeWaited);
+                } catch (InterruptedException ex) {
+                    break;
+                }
+            }
+            if (mHealthInfo == null) {
+                Slog.w(TAG, "health: Waited " + timeWaited + "ms for callbacks but received "
+                        + "nothing. BatteryService will be started with dummy values.");
+                update(new HealthInfo());
+                return;
+            }
+        }
+
+        if (DEBUG) {
+            Slog.d(TAG, "health: Waited " + timeWaited + "ms and received the update.");
+        }
+    }
+
     private void updateBatteryWarningLevelLocked() {
         final ContentResolver resolver = mContext.getContentResolver();
         int defWarnLevel = mContext.getResources().getInteger(
@@ -251,16 +307,16 @@
     private boolean isPoweredLocked(int plugTypeSet) {
         // assume we are powered if battery state is unknown so
         // the "stay on while plugged in" option will work.
-        if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
+        if (mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
             return true;
         }
-        if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mBatteryProps.chargerAcOnline) {
+        if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mHealthInfo.legacy.chargerAcOnline) {
             return true;
         }
-        if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mBatteryProps.chargerUsbOnline) {
+        if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mHealthInfo.legacy.chargerUsbOnline) {
             return true;
         }
-        if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mBatteryProps.chargerWirelessOnline) {
+        if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mHealthInfo.legacy.chargerWirelessOnline) {
             return true;
         }
         return false;
@@ -277,15 +333,15 @@
          *   (becomes <= mLowBatteryWarningLevel).
          */
         return !plugged
-                && mBatteryProps.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
-                && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel
+                && mHealthInfo.legacy.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
+                && mHealthInfo.legacy.batteryLevel <= mLowBatteryWarningLevel
                 && (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
     }
 
     private void shutdownIfNoPowerLocked() {
         // shut down gracefully if our battery is critically low and we are not powered.
         // wait until the system has booted before attempting to display the shutdown dialog.
-        if (mBatteryProps.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
+        if (mHealthInfo.legacy.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
@@ -306,7 +362,7 @@
         // shut down gracefully if temperature is too high (> 68.0C by default)
         // wait until the system has booted before attempting to display the
         // shutdown dialog.
-        if (mBatteryProps.batteryTemperature > mShutdownBatteryTemperature) {
+        if (mHealthInfo.legacy.batteryTemperature > mShutdownBatteryTemperature) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
@@ -323,28 +379,51 @@
         }
     }
 
-    private void update(BatteryProperties props) {
+    private void update(HealthInfo info) {
         synchronized (mLock) {
             if (!mUpdatesStopped) {
-                mBatteryProps = props;
+                mHealthInfo = info;
                 // Process the new values.
                 processValuesLocked(false);
+                mLock.notifyAll(); // for any waiters on new info
             } else {
-                mLastBatteryProps.set(props);
+                copy(mLastHealthInfo, info);
             }
         }
     }
 
+    private static void copy(HealthInfo dst, HealthInfo src) {
+        dst.legacy.chargerAcOnline = src.legacy.chargerAcOnline;
+        dst.legacy.chargerUsbOnline = src.legacy.chargerUsbOnline;
+        dst.legacy.chargerWirelessOnline = src.legacy.chargerWirelessOnline;
+        dst.legacy.maxChargingCurrent = src.legacy.maxChargingCurrent;
+        dst.legacy.maxChargingVoltage = src.legacy.maxChargingVoltage;
+        dst.legacy.batteryStatus = src.legacy.batteryStatus;
+        dst.legacy.batteryHealth = src.legacy.batteryHealth;
+        dst.legacy.batteryPresent = src.legacy.batteryPresent;
+        dst.legacy.batteryLevel = src.legacy.batteryLevel;
+        dst.legacy.batteryVoltage = src.legacy.batteryVoltage;
+        dst.legacy.batteryTemperature = src.legacy.batteryTemperature;
+        dst.legacy.batteryCurrent = src.legacy.batteryCurrent;
+        dst.legacy.batteryCycleCount = src.legacy.batteryCycleCount;
+        dst.legacy.batteryFullCharge = src.legacy.batteryFullCharge;
+        dst.legacy.batteryChargeCounter = src.legacy.batteryChargeCounter;
+        dst.legacy.batteryTechnology = src.legacy.batteryTechnology;
+        dst.batteryCurrentAverage = src.batteryCurrentAverage;
+        dst.batteryCapacity = src.batteryCapacity;
+        dst.energyCounter = src.energyCounter;
+    }
+
     private void processValuesLocked(boolean force) {
         boolean logOutlier = false;
         long dischargeDuration = 0;
 
-        mBatteryLevelCritical = (mBatteryProps.batteryLevel <= mCriticalBatteryLevel);
-        if (mBatteryProps.chargerAcOnline) {
+        mBatteryLevelCritical = (mHealthInfo.legacy.batteryLevel <= mCriticalBatteryLevel);
+        if (mHealthInfo.legacy.chargerAcOnline) {
             mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
-        } else if (mBatteryProps.chargerUsbOnline) {
+        } else if (mHealthInfo.legacy.chargerUsbOnline) {
             mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
-        } else if (mBatteryProps.chargerWirelessOnline) {
+        } else if (mHealthInfo.legacy.chargerWirelessOnline) {
             mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
         } else {
             mPlugType = BATTERY_PLUGGED_NONE;
@@ -352,30 +431,17 @@
 
         if (DEBUG) {
             Slog.d(TAG, "Processing new values: "
-                    + "chargerAcOnline=" + mBatteryProps.chargerAcOnline
-                    + ", chargerUsbOnline=" + mBatteryProps.chargerUsbOnline
-                    + ", chargerWirelessOnline=" + mBatteryProps.chargerWirelessOnline
-                    + ", maxChargingCurrent" + mBatteryProps.maxChargingCurrent
-                    + ", maxChargingVoltage" + mBatteryProps.maxChargingVoltage
-                    + ", batteryStatus=" + mBatteryProps.batteryStatus
-                    + ", batteryHealth=" + mBatteryProps.batteryHealth
-                    + ", batteryPresent=" + mBatteryProps.batteryPresent
-                    + ", batteryLevel=" + mBatteryProps.batteryLevel
-                    + ", batteryTechnology=" + mBatteryProps.batteryTechnology
-                    + ", batteryVoltage=" + mBatteryProps.batteryVoltage
-                    + ", batteryChargeCounter=" + mBatteryProps.batteryChargeCounter
-                    + ", batteryFullCharge=" + mBatteryProps.batteryFullCharge
-                    + ", batteryTemperature=" + mBatteryProps.batteryTemperature
+                    + "info=" + mHealthInfo
                     + ", mBatteryLevelCritical=" + mBatteryLevelCritical
                     + ", mPlugType=" + mPlugType);
         }
 
         // Let the battery stats keep track of the current level.
         try {
-            mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth,
-                    mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature,
-                    mBatteryProps.batteryVoltage, mBatteryProps.batteryChargeCounter,
-                    mBatteryProps.batteryFullCharge);
+            mBatteryStats.setBatteryState(mHealthInfo.legacy.batteryStatus, mHealthInfo.legacy.batteryHealth,
+                    mPlugType, mHealthInfo.legacy.batteryLevel, mHealthInfo.legacy.batteryTemperature,
+                    mHealthInfo.legacy.batteryVoltage, mHealthInfo.legacy.batteryChargeCounter,
+                    mHealthInfo.legacy.batteryFullCharge);
         } catch (RemoteException e) {
             // Should never happen.
         }
@@ -383,16 +449,16 @@
         shutdownIfNoPowerLocked();
         shutdownIfOverTempLocked();
 
-        if (force || (mBatteryProps.batteryStatus != mLastBatteryStatus ||
-                mBatteryProps.batteryHealth != mLastBatteryHealth ||
-                mBatteryProps.batteryPresent != mLastBatteryPresent ||
-                mBatteryProps.batteryLevel != mLastBatteryLevel ||
+        if (force || (mHealthInfo.legacy.batteryStatus != mLastBatteryStatus ||
+                mHealthInfo.legacy.batteryHealth != mLastBatteryHealth ||
+                mHealthInfo.legacy.batteryPresent != mLastBatteryPresent ||
+                mHealthInfo.legacy.batteryLevel != mLastBatteryLevel ||
                 mPlugType != mLastPlugType ||
-                mBatteryProps.batteryVoltage != mLastBatteryVoltage ||
-                mBatteryProps.batteryTemperature != mLastBatteryTemperature ||
-                mBatteryProps.maxChargingCurrent != mLastMaxChargingCurrent ||
-                mBatteryProps.maxChargingVoltage != mLastMaxChargingVoltage ||
-                mBatteryProps.batteryChargeCounter != mLastChargeCounter ||
+                mHealthInfo.legacy.batteryVoltage != mLastBatteryVoltage ||
+                mHealthInfo.legacy.batteryTemperature != mLastBatteryTemperature ||
+                mHealthInfo.legacy.maxChargingCurrent != mLastMaxChargingCurrent ||
+                mHealthInfo.legacy.maxChargingVoltage != mLastMaxChargingVoltage ||
+                mHealthInfo.legacy.batteryChargeCounter != mLastChargeCounter ||
                 mInvalidCharger != mLastInvalidCharger)) {
 
             if (mPlugType != mLastPlugType) {
@@ -401,33 +467,33 @@
 
                     // There's no value in this data unless we've discharged at least once and the
                     // battery level has changed; so don't log until it does.
-                    if (mDischargeStartTime != 0 && mDischargeStartLevel != mBatteryProps.batteryLevel) {
+                    if (mDischargeStartTime != 0 && mDischargeStartLevel != mHealthInfo.legacy.batteryLevel) {
                         dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
                         logOutlier = true;
                         EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration,
-                                mDischargeStartLevel, mBatteryProps.batteryLevel);
+                                mDischargeStartLevel, mHealthInfo.legacy.batteryLevel);
                         // make sure we see a discharge event before logging again
                         mDischargeStartTime = 0;
                     }
                 } else if (mPlugType == BATTERY_PLUGGED_NONE) {
                     // charging -> discharging or we just powered up
                     mDischargeStartTime = SystemClock.elapsedRealtime();
-                    mDischargeStartLevel = mBatteryProps.batteryLevel;
+                    mDischargeStartLevel = mHealthInfo.legacy.batteryLevel;
                 }
             }
-            if (mBatteryProps.batteryStatus != mLastBatteryStatus ||
-                    mBatteryProps.batteryHealth != mLastBatteryHealth ||
-                    mBatteryProps.batteryPresent != mLastBatteryPresent ||
+            if (mHealthInfo.legacy.batteryStatus != mLastBatteryStatus ||
+                    mHealthInfo.legacy.batteryHealth != mLastBatteryHealth ||
+                    mHealthInfo.legacy.batteryPresent != mLastBatteryPresent ||
                     mPlugType != mLastPlugType) {
                 EventLog.writeEvent(EventLogTags.BATTERY_STATUS,
-                        mBatteryProps.batteryStatus, mBatteryProps.batteryHealth, mBatteryProps.batteryPresent ? 1 : 0,
-                        mPlugType, mBatteryProps.batteryTechnology);
+                        mHealthInfo.legacy.batteryStatus, mHealthInfo.legacy.batteryHealth, mHealthInfo.legacy.batteryPresent ? 1 : 0,
+                        mPlugType, mHealthInfo.legacy.batteryTechnology);
             }
-            if (mBatteryProps.batteryLevel != mLastBatteryLevel) {
+            if (mHealthInfo.legacy.batteryLevel != mLastBatteryLevel) {
                 // Don't do this just from voltage or temperature changes, that is
                 // too noisy.
                 EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,
-                        mBatteryProps.batteryLevel, mBatteryProps.batteryVoltage, mBatteryProps.batteryTemperature);
+                        mHealthInfo.legacy.batteryLevel, mHealthInfo.legacy.batteryVoltage, mHealthInfo.legacy.batteryTemperature);
             }
             if (mBatteryLevelCritical && !mLastBatteryLevelCritical &&
                     mPlugType == BATTERY_PLUGGED_NONE) {
@@ -440,16 +506,16 @@
             if (!mBatteryLevelLow) {
                 // Should we now switch in to low battery mode?
                 if (mPlugType == BATTERY_PLUGGED_NONE
-                        && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel) {
+                        && mHealthInfo.legacy.batteryLevel <= mLowBatteryWarningLevel) {
                     mBatteryLevelLow = true;
                 }
             } else {
                 // Should we now switch out of low battery mode?
                 if (mPlugType != BATTERY_PLUGGED_NONE) {
                     mBatteryLevelLow = false;
-                } else if (mBatteryProps.batteryLevel >= mLowBatteryCloseWarningLevel)  {
+                } else if (mHealthInfo.legacy.batteryLevel >= mLowBatteryCloseWarningLevel)  {
                     mBatteryLevelLow = false;
-                } else if (force && mBatteryProps.batteryLevel >= mLowBatteryWarningLevel) {
+                } else if (force && mHealthInfo.legacy.batteryLevel >= mLowBatteryWarningLevel) {
                     // If being forced, the previous state doesn't matter, we will just
                     // absolutely check to see if we are now above the warning level.
                     mBatteryLevelLow = false;
@@ -496,7 +562,7 @@
                     }
                 });
             } else if (mSentLowBatteryBroadcast &&
-                    mBatteryProps.batteryLevel >= mLowBatteryCloseWarningLevel) {
+                    mHealthInfo.legacy.batteryLevel >= mLowBatteryCloseWarningLevel) {
                 mSentLowBatteryBroadcast = false;
                 final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
                 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -522,16 +588,16 @@
                 logOutlierLocked(dischargeDuration);
             }
 
-            mLastBatteryStatus = mBatteryProps.batteryStatus;
-            mLastBatteryHealth = mBatteryProps.batteryHealth;
-            mLastBatteryPresent = mBatteryProps.batteryPresent;
-            mLastBatteryLevel = mBatteryProps.batteryLevel;
+            mLastBatteryStatus = mHealthInfo.legacy.batteryStatus;
+            mLastBatteryHealth = mHealthInfo.legacy.batteryHealth;
+            mLastBatteryPresent = mHealthInfo.legacy.batteryPresent;
+            mLastBatteryLevel = mHealthInfo.legacy.batteryLevel;
             mLastPlugType = mPlugType;
-            mLastBatteryVoltage = mBatteryProps.batteryVoltage;
-            mLastBatteryTemperature = mBatteryProps.batteryTemperature;
-            mLastMaxChargingCurrent = mBatteryProps.maxChargingCurrent;
-            mLastMaxChargingVoltage = mBatteryProps.maxChargingVoltage;
-            mLastChargeCounter = mBatteryProps.batteryChargeCounter;
+            mLastBatteryVoltage = mHealthInfo.legacy.batteryVoltage;
+            mLastBatteryTemperature = mHealthInfo.legacy.batteryTemperature;
+            mLastMaxChargingCurrent = mHealthInfo.legacy.maxChargingCurrent;
+            mLastMaxChargingVoltage = mHealthInfo.legacy.maxChargingVoltage;
+            mLastChargeCounter = mHealthInfo.legacy.batteryChargeCounter;
             mLastBatteryLevelCritical = mBatteryLevelCritical;
             mLastInvalidCharger = mInvalidCharger;
         }
@@ -543,38 +609,26 @@
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
 
-        int icon = getIconLocked(mBatteryProps.batteryLevel);
+        int icon = getIconLocked(mHealthInfo.legacy.batteryLevel);
 
         intent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
-        intent.putExtra(BatteryManager.EXTRA_STATUS, mBatteryProps.batteryStatus);
-        intent.putExtra(BatteryManager.EXTRA_HEALTH, mBatteryProps.batteryHealth);
-        intent.putExtra(BatteryManager.EXTRA_PRESENT, mBatteryProps.batteryPresent);
-        intent.putExtra(BatteryManager.EXTRA_LEVEL, mBatteryProps.batteryLevel);
+        intent.putExtra(BatteryManager.EXTRA_STATUS, mHealthInfo.legacy.batteryStatus);
+        intent.putExtra(BatteryManager.EXTRA_HEALTH, mHealthInfo.legacy.batteryHealth);
+        intent.putExtra(BatteryManager.EXTRA_PRESENT, mHealthInfo.legacy.batteryPresent);
+        intent.putExtra(BatteryManager.EXTRA_LEVEL, mHealthInfo.legacy.batteryLevel);
         intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
         intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon);
         intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType);
-        intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mBatteryProps.batteryVoltage);
-        intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mBatteryProps.batteryTemperature);
-        intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mBatteryProps.batteryTechnology);
+        intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.legacy.batteryVoltage);
+        intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.legacy.batteryTemperature);
+        intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mHealthInfo.legacy.batteryTechnology);
         intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger);
-        intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mBatteryProps.maxChargingCurrent);
-        intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, mBatteryProps.maxChargingVoltage);
-        intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mBatteryProps.batteryChargeCounter);
+        intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mHealthInfo.legacy.maxChargingCurrent);
+        intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, mHealthInfo.legacy.maxChargingVoltage);
+        intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.legacy.batteryChargeCounter);
         if (DEBUG) {
-            Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED.  level:" + mBatteryProps.batteryLevel +
-                    ", scale:" + BATTERY_SCALE + ", status:" + mBatteryProps.batteryStatus +
-                    ", health:" + mBatteryProps.batteryHealth +
-                    ", present:" + mBatteryProps.batteryPresent +
-                    ", voltage: " + mBatteryProps.batteryVoltage +
-                    ", temperature: " + mBatteryProps.batteryTemperature +
-                    ", technology: " + mBatteryProps.batteryTechnology +
-                    ", AC powered:" + mBatteryProps.chargerAcOnline +
-                    ", USB powered:" + mBatteryProps.chargerUsbOnline +
-                    ", Wireless powered:" + mBatteryProps.chargerWirelessOnline +
-                    ", icon:" + icon  + ", invalid charger:" + mInvalidCharger +
-                    ", maxChargingCurrent:" + mBatteryProps.maxChargingCurrent +
-                    ", maxChargingVoltage:" + mBatteryProps.maxChargingVoltage +
-                    ", chargeCounter:" + mBatteryProps.batteryChargeCounter);
+            Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. scale:" + BATTERY_SCALE
+                    + ", info:" + mHealthInfo.toString());
         }
 
         mHandler.post(new Runnable() {
@@ -635,14 +689,14 @@
                 long durationThreshold = Long.parseLong(durationThresholdString);
                 int dischargeThreshold = Integer.parseInt(dischargeThresholdString);
                 if (duration <= durationThreshold &&
-                        mDischargeStartLevel - mBatteryProps.batteryLevel >= dischargeThreshold) {
+                        mDischargeStartLevel - mHealthInfo.legacy.batteryLevel >= dischargeThreshold) {
                     // If the discharge cycle is bad enough we want to know about it.
                     logBatteryStatsLocked();
                 }
                 if (DEBUG) Slog.v(TAG, "duration threshold: " + durationThreshold +
                         " discharge threshold: " + dischargeThreshold);
                 if (DEBUG) Slog.v(TAG, "duration: " + duration + " discharge: " +
-                        (mDischargeStartLevel - mBatteryProps.batteryLevel));
+                        (mDischargeStartLevel - mHealthInfo.legacy.batteryLevel));
             } catch (NumberFormatException e) {
                 Slog.e(TAG, "Invalid DischargeThresholds GService string: " +
                         durationThresholdString + " or " + dischargeThresholdString);
@@ -651,14 +705,14 @@
     }
 
     private int getIconLocked(int level) {
-        if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) {
+        if (mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) {
             return com.android.internal.R.drawable.stat_sys_battery_charge;
-        } else if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) {
+        } else if (mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) {
             return com.android.internal.R.drawable.stat_sys_battery;
-        } else if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING
-                || mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_FULL) {
+        } else if (mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING
+                || mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_FULL) {
             if (isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)
-                    && mBatteryProps.batteryLevel >= 100) {
+                    && mHealthInfo.legacy.batteryLevel >= 100) {
                 return com.android.internal.R.drawable.stat_sys_battery_charge;
             } else {
                 return com.android.internal.R.drawable.stat_sys_battery;
@@ -720,11 +774,11 @@
                 getContext().enforceCallingOrSelfPermission(
                         android.Manifest.permission.DEVICE_POWER, null);
                 if (!mUpdatesStopped) {
-                    mLastBatteryProps.set(mBatteryProps);
+                    copy(mLastHealthInfo, mHealthInfo);
                 }
-                mBatteryProps.chargerAcOnline = false;
-                mBatteryProps.chargerUsbOnline = false;
-                mBatteryProps.chargerWirelessOnline = false;
+                mHealthInfo.legacy.chargerAcOnline = false;
+                mHealthInfo.legacy.chargerUsbOnline = false;
+                mHealthInfo.legacy.chargerWirelessOnline = false;
                 long ident = Binder.clearCallingIdentity();
                 try {
                     mUpdatesStopped = true;
@@ -751,30 +805,30 @@
                 }
                 try {
                     if (!mUpdatesStopped) {
-                        mLastBatteryProps.set(mBatteryProps);
+                        copy(mLastHealthInfo, mHealthInfo);
                     }
                     boolean update = true;
                     switch (key) {
                         case "present":
-                            mBatteryProps.batteryPresent = Integer.parseInt(value) != 0;
+                            mHealthInfo.legacy.batteryPresent = Integer.parseInt(value) != 0;
                             break;
                         case "ac":
-                            mBatteryProps.chargerAcOnline = Integer.parseInt(value) != 0;
+                            mHealthInfo.legacy.chargerAcOnline = Integer.parseInt(value) != 0;
                             break;
                         case "usb":
-                            mBatteryProps.chargerUsbOnline = Integer.parseInt(value) != 0;
+                            mHealthInfo.legacy.chargerUsbOnline = Integer.parseInt(value) != 0;
                             break;
                         case "wireless":
-                            mBatteryProps.chargerWirelessOnline = Integer.parseInt(value) != 0;
+                            mHealthInfo.legacy.chargerWirelessOnline = Integer.parseInt(value) != 0;
                             break;
                         case "status":
-                            mBatteryProps.batteryStatus = Integer.parseInt(value);
+                            mHealthInfo.legacy.batteryStatus = Integer.parseInt(value);
                             break;
                         case "level":
-                            mBatteryProps.batteryLevel = Integer.parseInt(value);
+                            mHealthInfo.legacy.batteryLevel = Integer.parseInt(value);
                             break;
                         case "temp":
-                            mBatteryProps.batteryTemperature = Integer.parseInt(value);
+                            mHealthInfo.legacy.batteryTemperature = Integer.parseInt(value);
                             break;
                         case "invalid":
                             mInvalidCharger = Integer.parseInt(value);
@@ -806,7 +860,7 @@
                 try {
                     if (mUpdatesStopped) {
                         mUpdatesStopped = false;
-                        mBatteryProps.set(mLastBatteryProps);
+                        copy(mHealthInfo, mLastHealthInfo);
                         processValuesFromShellLocked(pw, opts);
                     }
                 } finally {
@@ -833,20 +887,20 @@
                 if (mUpdatesStopped) {
                     pw.println("  (UPDATES STOPPED -- use 'reset' to restart)");
                 }
-                pw.println("  AC powered: " + mBatteryProps.chargerAcOnline);
-                pw.println("  USB powered: " + mBatteryProps.chargerUsbOnline);
-                pw.println("  Wireless powered: " + mBatteryProps.chargerWirelessOnline);
-                pw.println("  Max charging current: " + mBatteryProps.maxChargingCurrent);
-                pw.println("  Max charging voltage: " + mBatteryProps.maxChargingVoltage);
-                pw.println("  Charge counter: " + mBatteryProps.batteryChargeCounter);
-                pw.println("  status: " + mBatteryProps.batteryStatus);
-                pw.println("  health: " + mBatteryProps.batteryHealth);
-                pw.println("  present: " + mBatteryProps.batteryPresent);
-                pw.println("  level: " + mBatteryProps.batteryLevel);
+                pw.println("  AC powered: " + mHealthInfo.legacy.chargerAcOnline);
+                pw.println("  USB powered: " + mHealthInfo.legacy.chargerUsbOnline);
+                pw.println("  Wireless powered: " + mHealthInfo.legacy.chargerWirelessOnline);
+                pw.println("  Max charging current: " + mHealthInfo.legacy.maxChargingCurrent);
+                pw.println("  Max charging voltage: " + mHealthInfo.legacy.maxChargingVoltage);
+                pw.println("  Charge counter: " + mHealthInfo.legacy.batteryChargeCounter);
+                pw.println("  status: " + mHealthInfo.legacy.batteryStatus);
+                pw.println("  health: " + mHealthInfo.legacy.batteryHealth);
+                pw.println("  present: " + mHealthInfo.legacy.batteryPresent);
+                pw.println("  level: " + mHealthInfo.legacy.batteryLevel);
                 pw.println("  scale: " + BATTERY_SCALE);
-                pw.println("  voltage: " + mBatteryProps.batteryVoltage);
-                pw.println("  temperature: " + mBatteryProps.batteryTemperature);
-                pw.println("  technology: " + mBatteryProps.batteryTechnology);
+                pw.println("  voltage: " + mHealthInfo.legacy.batteryVoltage);
+                pw.println("  temperature: " + mHealthInfo.legacy.batteryTemperature);
+                pw.println("  technology: " + mHealthInfo.legacy.batteryTechnology);
             } else {
                 Shell shell = new Shell();
                 shell.exec(mBinderService, null, fd, null, args, null, new ResultReceiver(null));
@@ -860,25 +914,25 @@
         synchronized (mLock) {
             proto.write(BatteryServiceDumpProto.ARE_UPDATES_STOPPED, mUpdatesStopped);
             int batteryPluggedValue = BatteryServiceDumpProto.BATTERY_PLUGGED_NONE;
-            if (mBatteryProps.chargerAcOnline) {
+            if (mHealthInfo.legacy.chargerAcOnline) {
                 batteryPluggedValue = BatteryServiceDumpProto.BATTERY_PLUGGED_AC;
-            } else if (mBatteryProps.chargerUsbOnline) {
+            } else if (mHealthInfo.legacy.chargerUsbOnline) {
                 batteryPluggedValue = BatteryServiceDumpProto.BATTERY_PLUGGED_USB;
-            } else if (mBatteryProps.chargerWirelessOnline) {
+            } else if (mHealthInfo.legacy.chargerWirelessOnline) {
                 batteryPluggedValue = BatteryServiceDumpProto.BATTERY_PLUGGED_WIRELESS;
             }
             proto.write(BatteryServiceDumpProto.PLUGGED, batteryPluggedValue);
-            proto.write(BatteryServiceDumpProto.MAX_CHARGING_CURRENT, mBatteryProps.maxChargingCurrent);
-            proto.write(BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE, mBatteryProps.maxChargingVoltage);
-            proto.write(BatteryServiceDumpProto.CHARGE_COUNTER, mBatteryProps.batteryChargeCounter);
-            proto.write(BatteryServiceDumpProto.STATUS, mBatteryProps.batteryStatus);
-            proto.write(BatteryServiceDumpProto.HEALTH, mBatteryProps.batteryHealth);
-            proto.write(BatteryServiceDumpProto.IS_PRESENT, mBatteryProps.batteryPresent);
-            proto.write(BatteryServiceDumpProto.LEVEL, mBatteryProps.batteryLevel);
+            proto.write(BatteryServiceDumpProto.MAX_CHARGING_CURRENT, mHealthInfo.legacy.maxChargingCurrent);
+            proto.write(BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE, mHealthInfo.legacy.maxChargingVoltage);
+            proto.write(BatteryServiceDumpProto.CHARGE_COUNTER, mHealthInfo.legacy.batteryChargeCounter);
+            proto.write(BatteryServiceDumpProto.STATUS, mHealthInfo.legacy.batteryStatus);
+            proto.write(BatteryServiceDumpProto.HEALTH, mHealthInfo.legacy.batteryHealth);
+            proto.write(BatteryServiceDumpProto.IS_PRESENT, mHealthInfo.legacy.batteryPresent);
+            proto.write(BatteryServiceDumpProto.LEVEL, mHealthInfo.legacy.batteryLevel);
             proto.write(BatteryServiceDumpProto.SCALE, BATTERY_SCALE);
-            proto.write(BatteryServiceDumpProto.VOLTAGE, mBatteryProps.batteryVoltage);
-            proto.write(BatteryServiceDumpProto.TEMPERATURE, mBatteryProps.batteryTemperature);
-            proto.write(BatteryServiceDumpProto.TECHNOLOGY, mBatteryProps.batteryTechnology);
+            proto.write(BatteryServiceDumpProto.VOLTAGE, mHealthInfo.legacy.batteryVoltage);
+            proto.write(BatteryServiceDumpProto.TEMPERATURE, mHealthInfo.legacy.batteryTemperature);
+            proto.write(BatteryServiceDumpProto.TECHNOLOGY, mHealthInfo.legacy.batteryTechnology);
         }
         proto.flush();
     }
@@ -911,8 +965,8 @@
          * Synchronize on BatteryService.
          */
         public void updateLightsLocked() {
-            final int level = mBatteryProps.batteryLevel;
-            final int status = mBatteryProps.batteryStatus;
+            final int level = mHealthInfo.legacy.batteryLevel;
+            final int status = mHealthInfo.legacy.batteryStatus;
             if (level < mLowBatteryWarningLevel) {
                 if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
                     // Solid red when battery is charging
@@ -938,15 +992,43 @@
         }
     }
 
-    private final class BatteryListener extends IBatteryPropertiesListener.Stub {
-        @Override public void batteryPropertiesChanged(BatteryProperties props) {
-            final long identity = Binder.clearCallingIdentity();
+    private final class HealthHalCallback extends IHealthInfoCallback.Stub
+            implements HealthServiceWrapper.Callback {
+        @Override public void healthInfoChanged(HealthInfo props) {
+            BatteryService.this.update(props);
+        }
+        // on new service registered
+        @Override public void onRegistration(IHealth oldService, IHealth newService,
+                String instance) {
+            if (newService == null) return;
+
             try {
-                BatteryService.this.update(props);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
+                if (oldService != null) {
+                    int r = oldService.unregisterCallback(this);
+                    if (r != Result.SUCCESS) {
+                        Slog.w(TAG, "health: cannot unregister previous callback: " +
+                                Result.toString(r));
+                    }
+                }
+            } catch (RemoteException ex) {
+                Slog.w(TAG, "health: cannot unregister previous callback (transaction error): "
+                            + ex.getMessage());
             }
-       }
+
+            try {
+                int r = newService.registerCallback(this);
+                if (r != Result.SUCCESS) {
+                    Slog.w(TAG, "health: cannot register callback: " + Result.toString(r));
+                    return;
+                }
+                // registerCallback does NOT guarantee that update is called
+                // immediately, so request a manual update here.
+                newService.update();
+            } catch (RemoteException ex) {
+                Slog.e(TAG, "health: cannot register callback (transaction error): "
+                        + ex.getMessage());
+            }
+        }
     }
 
     private final class BinderService extends Binder {
@@ -967,6 +1049,63 @@
         }
     }
 
+    // Reduced IBatteryPropertiesRegistrar that only implements getProperty for usage
+    // in BatteryManager.
+    private final class BatteryPropertiesRegistrar extends IBatteryPropertiesRegistrar.Stub {
+        public void registerListener(IBatteryPropertiesListener listener) {
+            Slog.e(TAG, "health: must not call registerListener on battery properties");
+        }
+        public void unregisterListener(IBatteryPropertiesListener listener) {
+            Slog.e(TAG, "health: must not call unregisterListener on battery properties");
+        }
+        public int getProperty(int id, final BatteryProperty prop) throws RemoteException {
+            IHealth service = mHealthServiceWrapper.getLastService();
+            final MutableInt outResult = new MutableInt(Result.NOT_SUPPORTED);
+            switch(id) {
+                case BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER:
+                    service.getChargeCounter((int result, int value) -> {
+                        outResult.value = result;
+                        if (result == Result.SUCCESS) prop.setLong(value);
+                    });
+                    break;
+                case BatteryManager.BATTERY_PROPERTY_CURRENT_NOW:
+                    service.getCurrentNow((int result, int value) -> {
+                        outResult.value = result;
+                        if (result == Result.SUCCESS) prop.setLong(value);
+                    });
+                    break;
+                case BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE:
+                    service.getCurrentAverage((int result, int value) -> {
+                        outResult.value = result;
+                        if (result == Result.SUCCESS) prop.setLong(value);
+                    });
+                    break;
+                case BatteryManager.BATTERY_PROPERTY_CAPACITY:
+                    service.getCapacity((int result, int value) -> {
+                        outResult.value = result;
+                        if (result == Result.SUCCESS) prop.setLong(value);
+                    });
+                    break;
+                case BatteryManager.BATTERY_PROPERTY_STATUS:
+                    service.getChargeStatus((int result, int value) -> {
+                        outResult.value = result;
+                        if (result == Result.SUCCESS) prop.setLong(value);
+                    });
+                    break;
+                case BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER:
+                    service.getEnergyCounter((int result, long value) -> {
+                        outResult.value = result;
+                        if (result == Result.SUCCESS) prop.setLong(value);
+                    });
+                    break;
+            }
+            return outResult.value;
+        }
+        public void scheduleUpdate() {
+            Slog.e(TAG, "health: must not call scheduleUpdate on battery properties");
+        }
+    }
+
     private final class LocalService extends BatteryManagerInternal {
         @Override
         public boolean isPowered(int plugTypeSet) {
@@ -985,7 +1124,7 @@
         @Override
         public int getBatteryLevel() {
             synchronized (mLock) {
-                return mBatteryProps.batteryLevel;
+                return mHealthInfo.legacy.batteryLevel;
             }
         }
 
@@ -1003,4 +1142,138 @@
             }
         }
     }
+
+    /**
+     * HealthServiceWrapper wraps the internal IHealth service and refreshes the service when
+     * necessary.
+     *
+     * On new registration of IHealth service, {@link #onRegistration onRegistration} is called and
+     * the internal service is refreshed.
+     * On death of an existing IHealth service, the internal service is NOT cleared to avoid
+     * race condition between death notification and new service notification. Hence,
+     * a caller must check for transaction errors when calling into the service.
+     *
+     * @hide Should only be used internally.
+     */
+    @VisibleForTesting
+    static final class HealthServiceWrapper {
+        private static final String TAG = "HealthServiceWrapper";
+        public static final String INSTANCE_HEALTHD = "backup";
+        public static final String INSTANCE_VENDOR = "default";
+        // All interesting instances, sorted by priority high -> low.
+        private static final List<String> sAllInstances =
+                Arrays.asList(INSTANCE_VENDOR, INSTANCE_HEALTHD);
+
+        private final IServiceNotification mNotification = new Notification();
+        private Callback mCallback;
+        private IHealthSupplier mHealthSupplier;
+
+        private final Object mLastServiceSetLock = new Object();
+        // Last IHealth service received.
+        // set must be also be guarded with mLastServiceSetLock to ensure ordering.
+        private final AtomicReference<IHealth> mLastService = new AtomicReference<>();
+
+        /**
+         * init should be called after constructor. For testing purposes, init is not called by
+         * constructor.
+         */
+        HealthServiceWrapper() {
+        }
+
+        IHealth getLastService() {
+            return mLastService.get();
+        }
+
+        /**
+         * Start monitoring registration of new IHealth services. Only instances that are in
+         * {@code sAllInstances} and in device / framework manifest are used. This function should
+         * only be called once.
+         * @throws RemoteException transaction error when talking to IServiceManager
+         * @throws NoSuchElementException if one of the following cases:
+         *         - No service manager;
+         *         - none of {@code sAllInstances} are in manifests (i.e. not
+         *           available on this device), or none of these instances are available to current
+         *           process.
+         * @throws NullPointerException when callback is null or supplier is null
+         */
+        void init(Callback callback,
+                  IServiceManagerSupplier managerSupplier,
+                  IHealthSupplier healthSupplier)
+                throws RemoteException, NoSuchElementException, NullPointerException {
+            if (callback == null || managerSupplier == null || healthSupplier == null)
+                throw new NullPointerException();
+
+            mCallback = callback;
+            mHealthSupplier = healthSupplier;
+
+            IServiceManager manager = managerSupplier.get();
+            for (String name : sAllInstances) {
+                if (manager.getTransport(IHealth.kInterfaceName, name) ==
+                        IServiceManager.Transport.EMPTY) {
+                    continue;
+                }
+
+                manager.registerForNotifications(IHealth.kInterfaceName, name, mNotification);
+                Slog.i(TAG, "health: HealthServiceWrapper listening to instance " + name);
+                return;
+            }
+
+            throw new NoSuchElementException(String.format(
+                    "No IHealth service instance among %s is available. Perhaps no permission?",
+                    sAllInstances.toString()));
+        }
+
+        interface Callback {
+            /**
+             * This function is invoked asynchronously when a new and related IServiceNotification
+             * is received.
+             * @param service the recently retrieved service from IServiceManager.
+             * Can be a dead service before service notification of a new service is delivered.
+             * Implementation must handle cases for {@link RemoteException}s when calling
+             * into service.
+             * @param instance instance name.
+             */
+            void onRegistration(IHealth oldService, IHealth newService, String instance);
+        }
+
+        /**
+         * Supplier of services.
+         * Must not return null; throw {@link NoSuchElementException} if a service is not available.
+         */
+        interface IServiceManagerSupplier {
+            default IServiceManager get() throws NoSuchElementException, RemoteException {
+                return IServiceManager.getService();
+            }
+        }
+        /**
+         * Supplier of services.
+         * Must not return null; throw {@link NoSuchElementException} if a service is not available.
+         */
+        interface IHealthSupplier {
+            default IHealth get(String name) throws NoSuchElementException, RemoteException {
+                return IHealth.getService(name);
+            }
+        }
+
+        private class Notification extends IServiceNotification.Stub {
+            @Override
+            public final void onRegistration(String interfaceName, String instanceName,
+                    boolean preexisting) {
+                if (!IHealth.kInterfaceName.equals(interfaceName)) return;
+                if (!sAllInstances.contains(instanceName)) return;
+                try {
+                    // ensures the order of multiple onRegistration on different threads.
+                    synchronized (mLastServiceSetLock) {
+                        IHealth newService = mHealthSupplier.get(instanceName);
+                        IHealth oldService = mLastService.getAndSet(newService);
+                        Slog.i(TAG, "health: new instance registered " + instanceName);
+                        mCallback.onRegistration(oldService, newService, instanceName);
+                    }
+                } catch (NoSuchElementException | RemoteException ex) {
+                    Slog.e(TAG, "health: Cannot get instance '" + instanceName + "': " +
+                           ex.getMessage() + ". Perhaps no permission?");
+                }
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 2d9baf6..0921a00 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -1333,6 +1333,10 @@
         public int[] getPowerSaveWhitelistUserAppIds() {
             return DeviceIdleController.this.getPowerSaveWhitelistUserAppIds();
         }
+
+        public int[] getPowerSaveTempWhitelistAppIds() {
+            return DeviceIdleController.this.getAppIdTempWhitelistInternal();
+        }
     }
 
     public DeviceIdleController(Context context) {
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index c23757f..9da3757 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -52,6 +52,7 @@
 import android.annotation.BinderThread;
 import android.annotation.ColorInt;
 import android.annotation.IntDef;
+import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -3190,6 +3191,7 @@
         }
     }
 
+    @MainThread
     @Override
     public boolean handleMessage(Message msg) {
         SomeArgs args;
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index 40499c9..119c9df6 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -38,6 +38,8 @@
 
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.util.proto.ProtoOutputStream;
+
 import com.android.internal.util.FastPrintWriter;
 
 /**
@@ -279,6 +281,31 @@
         return printedSomething;
     }
 
+    void writeProtoMap(ProtoOutputStream proto, long fieldId, ArrayMap<String, F[]> map) {
+        int N = map.size();
+        for (int mapi = 0; mapi < N; mapi++) {
+            long token = proto.start(fieldId);
+            proto.write(IntentResolverProto.ArrayMapEntry.KEY, map.keyAt(mapi));
+            for (F f : map.valueAt(mapi)) {
+                if (f != null) {
+                    proto.write(IntentResolverProto.ArrayMapEntry.VALUES, f.toString());
+                }
+            }
+            proto.end(token);
+        }
+    }
+
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        long token = proto.start(fieldId);
+        writeProtoMap(proto, IntentResolverProto.FULL_MIME_TYPES, mTypeToFilter);
+        writeProtoMap(proto, IntentResolverProto.BASE_MIME_TYPES, mBaseTypeToFilter);
+        writeProtoMap(proto, IntentResolverProto.WILD_MIME_TYPES, mWildTypeToFilter);
+        writeProtoMap(proto, IntentResolverProto.SCHEMES, mSchemeToFilter);
+        writeProtoMap(proto, IntentResolverProto.NON_DATA_ACTIONS, mActionToFilter);
+        writeProtoMap(proto, IntentResolverProto.MIME_TYPED_ACTIONS, mTypedActionToFilter);
+        proto.end(token);
+    }
+
     public boolean dump(PrintWriter out, String title, String prefix, String packageName,
             boolean printFilter, boolean collapseDuplicates) {
         String innerPrefix = prefix + "  ";
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 2e1f142..cf1d33c 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -882,8 +882,14 @@
         for (int direction : DIRECTIONS) {
             IpSecAlgorithm crypt = config.getEncryption(direction);
             IpSecAlgorithm auth = config.getAuthentication(direction);
-            if (crypt == null && auth == null) {
-                throw new IllegalArgumentException("Encryption and Authentication are both null");
+            IpSecAlgorithm authenticatedEncryption = config.getAuthenticatedEncryption(direction);
+            if (authenticatedEncryption == null && crypt == null && auth == null) {
+                throw new IllegalArgumentException(
+                        "No Encryption or Authentication algorithms specified");
+            } else if (authenticatedEncryption != null && (auth != null || crypt != null)) {
+                throw new IllegalArgumentException(
+                        "Authenticated Encryption is mutually"
+                                + " exclusive with other Authentication or Encryption algorithms");
             }
 
             if (mSpiRecords.getAndCheckOwner(config.getSpiResourceId(direction)) == null) {
@@ -922,6 +928,7 @@
         for (int direction : DIRECTIONS) {
             IpSecAlgorithm auth = c.getAuthentication(direction);
             IpSecAlgorithm crypt = c.getEncryption(direction);
+            IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption(direction);
 
             spis[direction] = mSpiRecords.getAndCheckOwner(c.getSpiResourceId(direction));
             int spi = spis[direction].getSpi();
@@ -942,6 +949,9 @@
                                 (crypt != null) ? crypt.getName() : "",
                                 (crypt != null) ? crypt.getKey() : null,
                                 (crypt != null) ? crypt.getTruncationLengthBits() : 0,
+                                (authCrypt != null) ? authCrypt.getName() : "",
+                                (authCrypt != null) ? authCrypt.getKey() : null,
+                                (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0,
                                 encapType,
                                 encapLocalPort,
                                 encapRemotePort);
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index ba3afc3..c60d7b0 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1980,7 +1980,8 @@
 
         final String[] domainStrs = domains == null ? new String[0] : domains.split(" ");
         final int[] params = { sampleValidity, successThreshold, minSamples, maxSamples };
-        final boolean useTls = false;
+        final boolean useTls = Settings.Global.getInt(resolver,
+                Settings.Global.DNS_TLS_DISABLED, 0) == 0;
         final String tlsHostname = "";
         final String[] tlsFingerprints = new String[0];
         try {
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 55391b3..cd25610 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -56,6 +56,7 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
+import android.os.IStoraged;
 import android.os.IVold;
 import android.os.IVoldListener;
 import android.os.IVoldTaskListener;
@@ -395,6 +396,7 @@
     private final Context mContext;
 
     private volatile IVold mVold;
+    private volatile IStoraged mStoraged;
 
     private volatile boolean mSystemReady = false;
     private volatile boolean mBootCompleted = false;
@@ -809,6 +811,7 @@
                 }
                 for (int userId : systemUnlockedUsers) {
                     mVold.onUserStarted(userId);
+                    mStoraged.onUserStarted(userId);
                 }
             } catch (Exception e) {
                 Slog.wtf(TAG, e);
@@ -824,6 +827,7 @@
         // bind mount against.
         try {
             mVold.onUserStarted(userId);
+            mStoraged.onUserStarted(userId);
         } catch (Exception e) {
             Slog.wtf(TAG, e);
         }
@@ -850,6 +854,7 @@
 
         try {
             mVold.onUserStopped(userId);
+            mStoraged.onUserStopped(userId);
         } catch (Exception e) {
             Slog.wtf(TAG, e);
         }
@@ -1335,13 +1340,36 @@
     }
 
     private void connect() {
-        IBinder binder = ServiceManager.getService("vold");
+        IBinder binder = ServiceManager.getService("storaged");
+        if (binder != null) {
+            try {
+                binder.linkToDeath(new DeathRecipient() {
+                    @Override
+                    public void binderDied() {
+                        Slog.w(TAG, "storaged died; reconnecting");
+                        mStoraged = null;
+                        connect();
+                    }
+                }, 0);
+            } catch (RemoteException e) {
+                binder = null;
+            }
+        }
+
+        if (binder != null) {
+            mStoraged = IStoraged.Stub.asInterface(binder);
+        } else {
+            Slog.w(TAG, "storaged not found; trying again");
+        }
+
+        binder = ServiceManager.getService("vold");
         if (binder != null) {
             try {
                 binder.linkToDeath(new DeathRecipient() {
                     @Override
                     public void binderDied() {
                         Slog.w(TAG, "vold died; reconnecting");
+                        mVold = null;
                         connect();
                     }
                 }, 0);
@@ -1354,18 +1382,21 @@
             mVold = IVold.Stub.asInterface(binder);
             try {
                 mVold.setListener(mListener);
-                onDaemonConnected();
-                return;
             } catch (RemoteException e) {
+                mVold = null;
                 Slog.w(TAG, "vold listener rejected; trying again", e);
             }
         } else {
             Slog.w(TAG, "vold not found; trying again");
         }
 
-        BackgroundThread.getHandler().postDelayed(() -> {
-            connect();
-        }, DateUtils.SECOND_IN_MILLIS);
+        if (mStoraged == null || mVold == null) {
+            BackgroundThread.getHandler().postDelayed(() -> {
+                connect();
+            }, DateUtils.SECOND_IN_MILLIS);
+        } else {
+            onDaemonConnected();
+        }
     }
 
     private void systemReady() {
diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
index 94397d0..58731d2 100644
--- a/services/core/java/com/android/server/SystemService.java
+++ b/services/core/java/com/android/server/SystemService.java
@@ -64,6 +64,11 @@
     public static final int PHASE_SYSTEM_SERVICES_READY = 500;
 
     /**
+     * After receiving this boot phase, services can safely call into device specific services.
+     */
+    public static final int PHASE_DEVICE_SPECIFIC_SERVICES_READY = 520;
+
+    /**
      * After receiving this boot phase, services can broadcast Intents.
      */
     public static final int PHASE_ACTIVITY_MANAGER_READY = 550;
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 4e15e5d..c684032 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -2248,12 +2248,10 @@
                         Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
                                 + response);
                     }
-                    Bundle result2 = new Bundle();
-                    result2.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, removalAllowed);
                     try {
-                        response.onResult(result2);
+                        response.onResult(result);
                     } catch (RemoteException e) {
-                        // ignore
+                        Slog.e(TAG, "Error calling onResult()", e);
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index 8839cfc..089db87 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -16,9 +16,11 @@
 
 package com.android.server.am;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
@@ -45,13 +47,14 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.wm.ConfigurationContainer;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 
 /**
  * Exactly one of these classes per Display in the system. Capable of holding zero or more
  * attached {@link ActivityStack}s.
  */
-class ActivityDisplay extends ConfigurationContainer {
+class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityDisplay" : TAG_AM;
     private static final String TAG_STACK = TAG + POSTFIX_STACK;
 
@@ -65,7 +68,7 @@
 
     /** All of the stacks on this display. Order matters, topmost stack is in front of all other
      * stacks, bottommost behind. Accessed directly by ActivityManager package classes */
-    final ArrayList<ActivityStack> mStacks = new ArrayList<>();
+    private final ArrayList<ActivityStack> mStacks = new ArrayList<>();
 
     /** Array of all UIDs that are present on the display. */
     private IntArray mDisplayAccessUIDs = new IntArray();
@@ -77,6 +80,13 @@
 
     private boolean mSleeping;
 
+    // Cached reference to some special stacks we tend to get a lot so we don't need to loop
+    // through the list to find them.
+    private ActivityStack mHomeStack = null;
+    private ActivityStack mRecentsStack = null;
+    private ActivityStack mPinnedStack = null;
+    private ActivityStack mSplitScreenPrimaryStack = null;
+
     ActivityDisplay(ActivityStackSupervisor supervisor, int displayId) {
         mSupervisor = supervisor;
         mDisplayId = displayId;
@@ -95,6 +105,7 @@
         }
         if (DEBUG_STACK) Slog.v(TAG_STACK, "addChild: attaching " + stack
                 + " to displayId=" + mDisplayId + " position=" + position);
+        addStackReferenceIfNeeded(stack);
         positionChildAt(stack, position);
         mSupervisor.mService.updateSleepIfNeededLocked();
     }
@@ -103,6 +114,7 @@
         if (DEBUG_STACK) Slog.v(TAG_STACK, "removeChild: detaching " + stack
                 + " from displayId=" + mDisplayId);
         mStacks.remove(stack);
+        removeStackReferenceIfNeeded(stack);
         mSupervisor.mService.updateSleepIfNeededLocked();
     }
 
@@ -147,9 +159,19 @@
      * @see ConfigurationContainer#isCompatible(int, int)
      */
     <T extends ActivityStack> T getStack(int windowingMode, int activityType) {
+        if (activityType == ACTIVITY_TYPE_HOME) {
+            return (T) mHomeStack;
+        } else if (activityType == ACTIVITY_TYPE_RECENTS) {
+            return (T) mRecentsStack;
+        }
+        if (windowingMode == WINDOWING_MODE_PINNED) {
+            return (T) mPinnedStack;
+        } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+            return (T) mSplitScreenPrimaryStack;
+        }
+
         for (int i = mStacks.size() - 1; i >= 0; --i) {
             final ActivityStack stack = mStacks.get(i);
-            // TODO: Should undefined windowing and activity type be compatible with standard type?
             if (stack.isCompatible(windowingMode, activityType)) {
                 return (T) stack;
             }
@@ -157,15 +179,28 @@
         return null;
     }
 
+    private boolean alwaysCreateStack(int windowingMode, int activityType) {
+        // Always create a stack for fullscreen, freeform, and split-screen-secondary windowing
+        // modes so that we can manage visual ordering and return types correctly.
+        return activityType == ACTIVITY_TYPE_STANDARD
+                && (windowingMode == WINDOWING_MODE_FULLSCREEN
+                || windowingMode == WINDOWING_MODE_FREEFORM
+                || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+    }
+
     /**
+     * Returns an existing stack compatible with the windowing mode and activity type or creates one
+     * if a compatible stack doesn't exist.
      * @see #getStack(int, int)
      * @see #createStack(int, int, boolean)
      */
     <T extends ActivityStack> T getOrCreateStack(int windowingMode, int activityType,
             boolean onTop) {
-        T stack = getStack(windowingMode, activityType);
-        if (stack != null) {
-            return stack;
+        if (!alwaysCreateStack(windowingMode, activityType)) {
+            T stack = getStack(windowingMode, activityType);
+            if (stack != null) {
+                return stack;
+            }
         }
         return createStack(windowingMode, activityType, onTop);
     }
@@ -217,17 +252,7 @@
             }
         }
 
-        final boolean inSplitScreenMode = hasSplitScreenStack();
-        if (!inSplitScreenMode
-                && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
-            // Switch to fullscreen windowing mode if we are not in split-screen mode and we are
-            // trying to launch in split-screen secondary.
-            windowingMode = WINDOWING_MODE_FULLSCREEN;
-        } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN
-                && WindowConfiguration.supportSplitScreenWindowingMode(
-                        windowingMode, activityType)) {
-            windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-        }
+        windowingMode = updateWindowingModeForSplitScreenIfNeeded(windowingMode, activityType);
 
         final int stackId = mSupervisor.getNextStackId();
 
@@ -275,7 +300,7 @@
                 if (stack.getWindowingMode() != windowingMode) {
                     continue;
                 }
-                mSupervisor.removeStackLocked(stack.mStackId);
+                mSupervisor.removeStack(stack);
             }
         }
     }
@@ -290,12 +315,63 @@
             for (int i = mStacks.size() - 1; i >= 0; --i) {
                 final ActivityStack stack = mStacks.get(i);
                 if (stack.getActivityType() == activityType) {
-                    mSupervisor.removeStackLocked(stack.mStackId);
+                    mSupervisor.removeStack(stack);
                 }
             }
         }
     }
 
+    void onStackWindowingModeChanged(ActivityStack stack) {
+        removeStackReferenceIfNeeded(stack);
+        addStackReferenceIfNeeded(stack);
+    }
+
+    private void addStackReferenceIfNeeded(ActivityStack stack) {
+        final int activityType = stack.getActivityType();
+        final int windowingMode = stack.getWindowingMode();
+
+        if (activityType == ACTIVITY_TYPE_HOME) {
+            if (mHomeStack != null && mHomeStack != stack) {
+                throw new IllegalArgumentException("addStackReferenceIfNeeded: home stack="
+                        + mHomeStack + " already exist on display=" + this + " stack=" + stack);
+            }
+            mHomeStack = stack;
+        } else if (activityType == ACTIVITY_TYPE_RECENTS) {
+            if (mRecentsStack != null && mRecentsStack != stack) {
+                throw new IllegalArgumentException("addStackReferenceIfNeeded: recents stack="
+                        + mRecentsStack + " already exist on display=" + this + " stack=" + stack);
+            }
+            mRecentsStack = stack;
+        }
+        if (windowingMode == WINDOWING_MODE_PINNED) {
+            if (mPinnedStack != null && mPinnedStack != stack) {
+                throw new IllegalArgumentException("addStackReferenceIfNeeded: pinned stack="
+                        + mPinnedStack + " already exist on display=" + this
+                        + " stack=" + stack);
+            }
+            mPinnedStack = stack;
+        } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+            if (mSplitScreenPrimaryStack != null && mSplitScreenPrimaryStack != stack) {
+                throw new IllegalArgumentException("addStackReferenceIfNeeded:"
+                        + " split-screen-primary" + " stack=" + mSplitScreenPrimaryStack
+                        + " already exist on display=" + this + " stack=" + stack);
+            }
+            mSplitScreenPrimaryStack = stack;
+        }
+    }
+
+    private void removeStackReferenceIfNeeded(ActivityStack stack) {
+        if (stack == mHomeStack) {
+            mHomeStack = null;
+        } else if (stack == mRecentsStack) {
+            mRecentsStack = null;
+        } else if (stack == mPinnedStack) {
+            mPinnedStack = null;
+        } else if (stack == mSplitScreenPrimaryStack) {
+            mSplitScreenPrimaryStack = null;
+        }
+    }
+
     /** Returns the top visible stack activity type that isn't in the exclude windowing mode. */
     int getTopVisibleStackActivityType(int excludeWindowingMode) {
         for (int i = mStacks.size() - 1; i >= 0; --i) {
@@ -310,20 +386,57 @@
         return ACTIVITY_TYPE_UNDEFINED;
     }
 
-    ActivityStack getSplitScreenStack() {
-        return getStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
+    /**
+     * Get the topmost stack on the display. It may be different from focused stack, because
+     * focus may be on another display.
+     */
+    ActivityStack getTopStack() {
+        return mStacks.isEmpty() ? null : mStacks.get(mStacks.size() - 1);
     }
 
-    boolean hasSplitScreenStack() {
-        return getSplitScreenStack() != null;
+    boolean isTopStack(ActivityStack stack) {
+        return stack == getTopStack();
+    }
+
+    int getIndexOf(ActivityStack stack) {
+        return mStacks.indexOf(stack);
+    }
+
+    void onLockTaskPackagesUpdated() {
+        for (int i = mStacks.size() - 1; i >= 0; --i) {
+            mStacks.get(i).onLockTaskPackagesUpdated();
+        }
+    }
+
+    ActivityStack getSplitScreenPrimaryStack() {
+        return mSplitScreenPrimaryStack;
+    }
+
+    boolean hasSplitScreenPrimaryStack() {
+        return mSplitScreenPrimaryStack != null;
     }
 
     PinnedActivityStack getPinnedStack() {
-        return getStack(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
+        return (PinnedActivityStack) mPinnedStack;
     }
 
     boolean hasPinnedStack() {
-        return getPinnedStack() != null;
+        return mPinnedStack != null;
+    }
+
+    int updateWindowingModeForSplitScreenIfNeeded(int windowingMode, int activityType) {
+        final boolean inSplitScreenMode = hasSplitScreenPrimaryStack();
+        if (!inSplitScreenMode
+                && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
+            // Switch to fullscreen windowing mode if we are not in split-screen mode and we are
+            // trying to launch in split-screen secondary.
+            return WINDOWING_MODE_FULLSCREEN;
+        } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN
+                && WindowConfiguration.supportSplitScreenWindowingMode(
+                windowingMode, activityType)) {
+            return WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+        }
+        return windowingMode;
     }
 
     @Override
@@ -337,7 +450,7 @@
     }
 
     @Override
-    protected ConfigurationContainer getChildAt(int index) {
+    protected ActivityStack getChildAt(int index) {
         return mStacks.get(index);
     }
 
@@ -385,6 +498,10 @@
         mSleeping = asleep;
     }
 
+    public void dump(PrintWriter pw, String prefix) {
+        pw.println(prefix + "displayId=" + mDisplayId + " mStacks=" + mStacks);
+    }
+
     public void writeToProto(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         super.writeToProto(proto, CONFIGURATION_CONTAINER);
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index 3a9bf12..ceb2ad6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -59,7 +59,6 @@
     static final boolean DEBUG_FOCUS = false;
     static final boolean DEBUG_IDLE = DEBUG_ALL_ACTIVITIES || false;
     static final boolean DEBUG_IMMERSIVE = DEBUG_ALL || false;
-    static final boolean DEBUG_LOCKSCREEN = DEBUG_ALL || false;
     static final boolean DEBUG_LOCKTASK = DEBUG_ALL || false;
     static final boolean DEBUG_LRU = DEBUG_ALL || false;
     static final boolean DEBUG_MU = DEBUG_ALL || false;
@@ -74,10 +73,10 @@
     static final boolean DEBUG_PROVIDER = DEBUG_ALL || false;
     static final boolean DEBUG_PSS = DEBUG_ALL || false;
     static final boolean DEBUG_RECENTS = DEBUG_ALL || false;
+    static final boolean DEBUG_RECENTS_TRIM_TASKS = DEBUG_RECENTS || false;
     static final boolean DEBUG_RELEASE = DEBUG_ALL_ACTIVITIES || false;
     static final boolean DEBUG_RESULTS = DEBUG_ALL || false;
     static final boolean DEBUG_SAVED_STATE = DEBUG_ALL_ACTIVITIES || false;
-    static final boolean DEBUG_SCREENSHOTS = DEBUG_ALL_ACTIVITIES || false;
     static final boolean DEBUG_SERVICE = DEBUG_ALL || false;
     static final boolean DEBUG_FOREGROUND_SERVICE = DEBUG_ALL || false;
     static final boolean DEBUG_SERVICE_EXECUTING = DEBUG_ALL || false;
@@ -85,7 +84,6 @@
     static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || false;
     static final boolean DEBUG_SWITCH = DEBUG_ALL || false;
     static final boolean DEBUG_TASKS = DEBUG_ALL || false;
-    static final boolean DEBUG_THUMBNAILS = DEBUG_ALL || false;
     static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
     static final boolean DEBUG_UID_OBSERVERS = DEBUG_ALL || false;
     static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false;
@@ -105,7 +103,6 @@
     static final String POSTFIX_FOCUS = (APPEND_CATEGORY_NAME) ? "_Focus" : "";
     static final String POSTFIX_IDLE = (APPEND_CATEGORY_NAME) ? "_Idle" : "";
     static final String POSTFIX_IMMERSIVE = (APPEND_CATEGORY_NAME) ? "_Immersive" : "";
-    static final String POSTFIX_LOCKSCREEN = (APPEND_CATEGORY_NAME) ? "_LockScreen" : "";
     static final String POSTFIX_LOCKTASK = (APPEND_CATEGORY_NAME) ? "_LockTask" : "";
     static final String POSTFIX_LRU = (APPEND_CATEGORY_NAME) ? "_LRU" : "";
     static final String POSTFIX_MU = "_MU";
@@ -122,7 +119,6 @@
     static final String POSTFIX_RELEASE = (APPEND_CATEGORY_NAME) ? "_Release" : "";
     static final String POSTFIX_RESULTS = (APPEND_CATEGORY_NAME) ? "_Results" : "";
     static final String POSTFIX_SAVED_STATE = (APPEND_CATEGORY_NAME) ? "_SavedState" : "";
-    static final String POSTFIX_SCREENSHOTS = (APPEND_CATEGORY_NAME) ? "_Screenshots" : "";
     static final String POSTFIX_SERVICE = (APPEND_CATEGORY_NAME) ? "_Service" : "";
     static final String POSTFIX_SERVICE_EXECUTING =
             (APPEND_CATEGORY_NAME) ? "_ServiceExecuting" : "";
@@ -130,13 +126,11 @@
     static final String POSTFIX_STATES = (APPEND_CATEGORY_NAME) ? "_States" : "";
     static final String POSTFIX_SWITCH = (APPEND_CATEGORY_NAME) ? "_Switch" : "";
     static final String POSTFIX_TASKS = (APPEND_CATEGORY_NAME) ? "_Tasks" : "";
-    static final String POSTFIX_THUMBNAILS = (APPEND_CATEGORY_NAME) ? "_Thumbnails" : "";
     static final String POSTFIX_TRANSITION = (APPEND_CATEGORY_NAME) ? "_Transition" : "";
     static final String POSTFIX_UID_OBSERVERS = (APPEND_CATEGORY_NAME)
             ? "_UidObservers" : "";
     static final String POSTFIX_URI_PERMISSION = (APPEND_CATEGORY_NAME) ? "_UriPermission" : "";
     static final String POSTFIX_USER_LEAVING = (APPEND_CATEGORY_NAME) ? "_UserLeaving" : "";
     static final String POSTFIX_VISIBILITY = (APPEND_CATEGORY_NAME) ? "_Visibility" : "";
-    static final String POSTFIX_VISIBLE_BEHIND = (APPEND_CATEGORY_NAME) ? "_VisibleBehind" : "";
 
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a1a7a32..e1e53b3 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -31,7 +31,6 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS;
@@ -50,6 +49,9 @@
 import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode;
 import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground;
 import static android.os.Build.VERSION_CODES.N;
+import static android.os.IServiceManager.DUMP_PRIORITY_CRITICAL;
+import static android.os.IServiceManager.DUMP_PRIORITY_HIGH;
+import static android.os.IServiceManager.DUMP_PRIORITY_NORMAL;
 import static android.os.Process.BLUETOOTH_UID;
 import static android.os.Process.FIRST_APPLICATION_UID;
 import static android.os.Process.FIRST_ISOLATED_UID;
@@ -130,7 +132,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROVIDER;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
@@ -175,7 +176,6 @@
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
 import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
 import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
-import static com.android.server.am.proto.ActivityManagerServiceProto.ACTIVITIES;
 import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN;
 import static com.android.server.wm.AppTransition.TRANSIT_NONE;
 import static com.android.server.wm.AppTransition.TRANSIT_TASK_IN_PLACE;
@@ -208,7 +208,6 @@
 import android.app.Dialog;
 import android.app.IActivityController;
 import android.app.IActivityManager;
-import android.app.IAppTask;
 import android.app.IApplicationThread;
 import android.app.IInstrumentationWatcher;
 import android.app.INotificationManager;
@@ -396,6 +395,9 @@
 import com.android.server.ThreadPriorityBooster;
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityStack.ActivityState;
+import com.android.server.am.proto.ActivityManagerServiceProto;
+import com.android.server.am.proto.BroadcastProto;
+import com.android.server.am.proto.StickyBroadcastProto;
 import com.android.server.firewall.IntentFirewall;
 import com.android.server.job.JobSchedulerInternal;
 import com.android.server.pm.Installer;
@@ -731,9 +733,6 @@
                 doDump(fd, pw, new String[] {"associations"});
             }
             doDump(fd, pw, new String[] {"processes"});
-            doDump(fd, pw, new String[] {"-v", "all"});
-            doDump(fd, pw, new String[] {"service", "all"});
-            doDump(fd, pw, new String[] {"provider", "all"});
         }
 
         @Override
@@ -1711,7 +1710,6 @@
     static final int PUSH_TEMP_WHITELIST_UI_MSG = 68;
     static final int SERVICE_FOREGROUND_CRASH_MSG = 69;
     static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70;
-    static final int TOP_APP_KILLED_BY_LMK_MSG = 73;
     static final int NOTIFY_VR_KEYGUARD_MSG = 74;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
@@ -1732,9 +1730,6 @@
      */
     private boolean mUserIsMonkey;
 
-    /** Flag whether the device has a Recents UI */
-    boolean mHasRecents;
-
     /** The dimensions of the thumbnails in the Recents UI. */
     int mThumbnailWidth;
     int mThumbnailHeight;
@@ -1940,17 +1935,6 @@
                 dispatchProcessDied(pid, uid);
                 break;
             }
-            case TOP_APP_KILLED_BY_LMK_MSG: {
-                final String appName = (String) msg.obj;
-                final AlertDialog d = new BaseErrorDialog(mUiContext);
-                d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
-                d.setTitle(mUiContext.getText(R.string.top_app_killed_title));
-                d.setMessage(mUiContext.getString(R.string.top_app_killed_message, appName));
-                d.setButton(DialogInterface.BUTTON_POSITIVE, mUiContext.getText(R.string.close),
-                        obtainMessage(DISMISS_DIALOG_UI_MSG, d));
-                d.show();
-                break;
-            }
             case DISPATCH_UIDS_CHANGED_UI_MSG: {
                 dispatchUidsChanged();
             } break;
@@ -2498,13 +2482,16 @@
 
     public void setSystemProcess() {
         try {
-            ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
+            ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true,
+                    DUMP_PRIORITY_CRITICAL | DUMP_PRIORITY_NORMAL);
             ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
-            ServiceManager.addService("meminfo", new MemBinder(this));
+            ServiceManager.addService("meminfo", new MemBinder(this), /* allowIsolated= */ false,
+                    DUMP_PRIORITY_HIGH | DUMP_PRIORITY_NORMAL);
             ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
             ServiceManager.addService("dbinfo", new DbBinder(this));
             if (MONITOR_CPU_USAGE) {
-                ServiceManager.addService("cpuinfo", new CpuBinder(this));
+                ServiceManager.addService("cpuinfo", new CpuBinder(this),
+                        /* allowIsolated= */ false, DUMP_PRIORITY_CRITICAL);
             }
             ServiceManager.addService("permission", new PermissionController(this));
             ServiceManager.addService("processinfo", new ProcessInfoService(this));
@@ -2535,7 +2522,6 @@
         synchronized (this) {
             mWindowManager = wm;
             mStackSupervisor.setWindowManager(wm);
-            mActivityStarter.setWindowManager(wm);
             mLockTaskController.setWindowManager(wm);
         }
     }
@@ -2777,8 +2763,9 @@
         mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
         mTaskChangeNotificationController =
                 new TaskChangeNotificationController(this, mStackSupervisor, mHandler);
-        mActivityStarter = new ActivityStarter(this, mStackSupervisor);
+        mActivityStarter = new ActivityStarter(this);
         mRecentTasks = new RecentTasks(this, mStackSupervisor);
+        mStackSupervisor.setRecentTasks(mRecentTasks);
         mLockTaskController = new LockTaskController(mContext, mStackSupervisor, mHandler);
 
         mProcessCpuThread = new Thread("CpuTracker") {
@@ -4890,7 +4877,7 @@
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
-                return mStackSupervisor.startActivityFromRecentsInner(taskId, bOptions);
+                return mStackSupervisor.startActivityFromRecents(taskId, bOptions);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -5425,7 +5412,6 @@
             boolean doLowMem = app.instr == null;
             boolean doOomAdj = doLowMem;
             if (!app.killedByAm) {
-                maybeNotifyTopAppKilled(app);
                 Slog.i(TAG, "Process " + app.processName + " (pid " + pid + ") has died: "
                         + ProcessList.makeOomAdjString(app.setAdj)
                         + ProcessList.makeProcStateString(app.setProcState));
@@ -5459,23 +5445,6 @@
         }
     }
 
-    /** Show system error dialog when a top app is killed by LMK */
-    void maybeNotifyTopAppKilled(ProcessRecord app) {
-        if (!shouldNotifyTopAppKilled(app)) {
-            return;
-        }
-
-        Message msg = mHandler.obtainMessage(TOP_APP_KILLED_BY_LMK_MSG);
-        msg.obj = mContext.getPackageManager().getApplicationLabel(app.info);
-        mUiHandler.sendMessage(msg);
-    }
-
-    /** Only show notification when the top app is killed on low ram devices */
-    private boolean shouldNotifyTopAppKilled(ProcessRecord app) {
-        return app.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP &&
-            ActivityManager.isLowRamDeviceStatic();
-    }
-
     /**
      * If a stack trace dump file is configured, dump process stack traces.
      * @param clearTraces causes the dump file to be erased prior to the new
@@ -5960,16 +5929,7 @@
 
                 if (appInfo != null) {
                     forceStopPackageLocked(packageName, appInfo.uid, "clear data");
-                    // Remove all tasks match the cleared application package and user
-                    for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
-                        final TaskRecord tr = mRecentTasks.get(i);
-                        final String taskPackageName =
-                                tr.getBaseIntent().getComponent().getPackageName();
-                        if (tr.userId != resolvedUserId) continue;
-                        if (!taskPackageName.equals(packageName)) continue;
-                        mStackSupervisor.removeTaskByIdLocked(tr.taskId, false,
-                                REMOVE_FROM_RECENTS);
-                    }
+                    mRecentTasks.removeTasksByPackageName(packageName, resolvedUserId);
                 }
             }
 
@@ -6550,7 +6510,7 @@
         }
 
         // Clean-up disabled tasks
-        cleanupDisabledPackageTasksLocked(packageName, disabledClasses, userId);
+        mRecentTasks.cleanupDisabledPackageTasksLocked(packageName, disabledClasses, userId);
 
         // Clean-up disabled services.
         mServices.bringDownDisabledPackageServicesLocked(
@@ -9797,35 +9757,12 @@
     public List<IBinder> getAppTasks(String callingPackage) {
         int callingUid = Binder.getCallingUid();
         long ident = Binder.clearCallingIdentity();
-
-        synchronized(this) {
-            ArrayList<IBinder> list = new ArrayList<IBinder>();
-            try {
-                if (DEBUG_ALL) Slog.v(TAG, "getAppTasks");
-
-                final int N = mRecentTasks.size();
-                for (int i = 0; i < N; i++) {
-                    TaskRecord tr = mRecentTasks.get(i);
-                    // Skip tasks that do not match the caller.  We don't need to verify
-                    // callingPackage, because we are also limiting to callingUid and know
-                    // that will limit to the correct security sandbox.
-                    if (tr.effectiveUid != callingUid) {
-                        continue;
-                    }
-                    Intent intent = tr.getBaseIntent();
-                    if (intent == null ||
-                            !callingPackage.equals(intent.getComponent().getPackageName())) {
-                        continue;
-                    }
-                    ActivityManager.RecentTaskInfo taskInfo =
-                            createRecentTaskInfoFromTaskRecord(tr);
-                    AppTaskImpl taskImpl = new AppTaskImpl(taskInfo.persistentId, callingUid);
-                    list.add(taskImpl.asBinder());
-                }
-            } finally {
-                Binder.restoreCallingIdentity(ident);
+        try {
+            synchronized(this) {
+                return mRecentTasks.getAppTasksList(callingUid, callingPackage);
             }
-            return list;
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
@@ -9848,58 +9785,6 @@
         return list;
     }
 
-    /**
-     * Creates a new RecentTaskInfo from a TaskRecord.
-     */
-    private ActivityManager.RecentTaskInfo createRecentTaskInfoFromTaskRecord(TaskRecord tr) {
-        // Update the task description to reflect any changes in the task stack
-        tr.updateTaskDescription();
-
-        // Compose the recent task info
-        ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
-        rti.id = tr.getTopActivity() == null ? INVALID_TASK_ID : tr.taskId;
-        rti.persistentId = tr.taskId;
-        rti.baseIntent = new Intent(tr.getBaseIntent());
-        rti.origActivity = tr.origActivity;
-        rti.realActivity = tr.realActivity;
-        rti.description = tr.lastDescription;
-        rti.stackId = tr.getStackId();
-        rti.userId = tr.userId;
-        rti.taskDescription = new ActivityManager.TaskDescription(tr.lastTaskDescription);
-        rti.firstActiveTime = tr.firstActiveTime;
-        rti.lastActiveTime = tr.lastActiveTime;
-        rti.affiliatedTaskId = tr.mAffiliatedTaskId;
-        rti.affiliatedTaskColor = tr.mAffiliatedTaskColor;
-        rti.numActivities = 0;
-        if (tr.mBounds != null) {
-            rti.bounds = new Rect(tr.mBounds);
-        }
-        rti.supportsSplitScreenMultiWindow = tr.supportsSplitScreenWindowingMode();
-        rti.resizeMode = tr.mResizeMode;
-        rti.configuration.setTo(tr.getConfiguration());
-
-        ActivityRecord base = null;
-        ActivityRecord top = null;
-        ActivityRecord tmp;
-
-        for (int i = tr.mActivities.size() - 1; i >= 0; --i) {
-            tmp = tr.mActivities.get(i);
-            if (tmp.finishing) {
-                continue;
-            }
-            base = tmp;
-            if (top == null || (top.state == ActivityState.INITIALIZING)) {
-                top = base;
-            }
-            rti.numActivities++;
-        }
-
-        rti.baseActivity = (base != null) ? base.intent.getComponent() : null;
-        rti.topActivity = (top != null) ? top.intent.getComponent() : null;
-
-        return rti;
-    }
-
     private boolean isGetTasksAllowed(String caller, int callingPid, int callingUid) {
         boolean allowed = checkPermission(android.Manifest.permission.REAL_GET_TASKS,
                 callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
@@ -9933,119 +9818,15 @@
         final int callingUid = Binder.getCallingUid();
         userId = mUserController.handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
                 false, ALLOW_FULL_ONLY, "getRecentTasks", null);
+        final boolean allowed = isGetTasksAllowed("getRecentTasks", Binder.getCallingPid(),
+                callingUid);
+        final boolean detailed = checkCallingPermission(
+                android.Manifest.permission.GET_DETAILED_TASKS)
+                        == PackageManager.PERMISSION_GRANTED;
 
-        final boolean includeProfiles = (flags & ActivityManager.RECENT_INCLUDE_PROFILES) != 0;
-        final boolean withExcluded = (flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0;
         synchronized (this) {
-            final boolean allowed = isGetTasksAllowed("getRecentTasks", Binder.getCallingPid(),
+            return mRecentTasks.getRecentTasks(maxNum, flags, allowed, detailed, userId,
                     callingUid);
-            final boolean detailed = checkCallingPermission(
-                    android.Manifest.permission.GET_DETAILED_TASKS)
-                    == PackageManager.PERMISSION_GRANTED;
-
-            if (!isUserRunning(userId, ActivityManager.FLAG_AND_UNLOCKED)) {
-                Slog.i(TAG, "user " + userId + " is still locked. Cannot load recents");
-                return ParceledListSlice.emptyList();
-            }
-            mRecentTasks.loadUserRecentsLocked(userId);
-
-            final int recentsCount = mRecentTasks.size();
-            ArrayList<ActivityManager.RecentTaskInfo> res =
-                    new ArrayList<>(maxNum < recentsCount ? maxNum : recentsCount);
-
-            final Set<Integer> includedUsers;
-            if (includeProfiles) {
-                includedUsers = mUserController.getProfileIds(userId);
-            } else {
-                includedUsers = new HashSet<>();
-            }
-            includedUsers.add(Integer.valueOf(userId));
-
-            for (int i = 0; i < recentsCount && maxNum > 0; i++) {
-                TaskRecord tr = mRecentTasks.get(i);
-                // Only add calling user or related users recent tasks
-                if (!includedUsers.contains(Integer.valueOf(tr.userId))) {
-                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + tr);
-                    continue;
-                }
-
-                if (tr.realActivitySuspended) {
-                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, activity suspended: " + tr);
-                    continue;
-                }
-
-                // Return the entry if desired by the caller.  We always return
-                // the first entry, because callers always expect this to be the
-                // foreground app.  We may filter others if the caller has
-                // not supplied RECENT_WITH_EXCLUDED and there is some reason
-                // we should exclude the entry.
-
-                if (i == 0
-                        || withExcluded
-                        || (tr.intent == null)
-                        || ((tr.intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
-                                == 0)) {
-                    if (!allowed) {
-                        // If the caller doesn't have the GET_TASKS permission, then only
-                        // allow them to see a small subset of tasks -- their own and home.
-                        if (!tr.isActivityTypeHome() && tr.effectiveUid != callingUid) {
-                            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + tr);
-                            continue;
-                        }
-                    }
-                    final ActivityStack stack = tr.getStack();
-                    if ((flags & ActivityManager.RECENT_IGNORE_HOME_AND_RECENTS_STACK_TASKS) != 0) {
-                        if (stack != null && stack.isHomeOrRecentsStack()) {
-                            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
-                                    "Skipping, home or recents stack task: " + tr);
-                            continue;
-                        }
-                    }
-                    if ((flags & ActivityManager.RECENT_INGORE_DOCKED_STACK_TOP_TASK) != 0) {
-                        if (stack != null && stack.inSplitScreenPrimaryWindowingMode()
-                                && stack.topTask() == tr) {
-                            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
-                                    "Skipping, top task in docked stack: " + tr);
-                            continue;
-                        }
-                    }
-                    if ((flags & ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS) != 0) {
-                        if (stack != null && stack.inPinnedWindowingMode()) {
-                            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
-                                    "Skipping, pinned stack task: " + tr);
-                            continue;
-                        }
-                    }
-                    if (tr.autoRemoveRecents && tr.getTopActivity() == null) {
-                        // Don't include auto remove tasks that are finished or finishing.
-                        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
-                                "Skipping, auto-remove without activity: " + tr);
-                        continue;
-                    }
-                    if ((flags&ActivityManager.RECENT_IGNORE_UNAVAILABLE) != 0
-                            && !tr.isAvailable) {
-                        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
-                                "Skipping, unavail real act: " + tr);
-                        continue;
-                    }
-
-                    if (!tr.mUserSetupComplete) {
-                        // Don't include task launched while user is not done setting-up.
-                        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
-                                "Skipping, user setup not complete: " + tr);
-                        continue;
-                    }
-
-                    ActivityManager.RecentTaskInfo rti = createRecentTaskInfoFromTaskRecord(tr);
-                    if (!detailed) {
-                        rti.baseIntent.replaceExtras((Bundle)null);
-                    }
-
-                    res.add(rti);
-                    maxNum--;
-                }
-            }
-            return new ParceledListSlice<>(res);
         }
     }
 
@@ -10117,23 +9898,10 @@
                 TaskRecord task = new TaskRecord(this,
                         mStackSupervisor.getNextTaskIdForUserLocked(r.userId),
                         ainfo, intent, description);
-
-                int trimIdx = mRecentTasks.trimForTaskLocked(task, false);
-                if (trimIdx >= 0) {
-                    // If this would have caused a trim, then we'll abort because that
-                    // means it would be added at the end of the list but then just removed.
+                if (!mRecentTasks.addToBottom(task)) {
                     return INVALID_TASK_ID;
                 }
-
-                final int N = mRecentTasks.size();
-                if (N >= (ActivityManager.getMaxRecentTasksStatic()-1)) {
-                    final TaskRecord tr = mRecentTasks.remove(N - 1);
-                    tr.removedFromRecents();
-                }
-
-                task.inRecents = true;
-                mRecentTasks.add(task);
-                r.getStack().addTask(task, false, "addAppTask");
+                r.getStack().addTask(task, !ON_TOP, "addAppTask");
 
                 // TODO: Send the thumbnail to WM to store it.
 
@@ -10349,38 +10117,6 @@
         mWindowManager.executeAppTransition();
     }
 
-    private void removeTasksByPackageNameLocked(String packageName, int userId) {
-        // Remove all tasks with activities in the specified package from the list of recent tasks
-        for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
-            TaskRecord tr = mRecentTasks.get(i);
-            if (tr.userId != userId) continue;
-
-            ComponentName cn = tr.intent.getComponent();
-            if (cn != null && cn.getPackageName().equals(packageName)) {
-                // If the package name matches, remove the task.
-                mStackSupervisor.removeTaskByIdLocked(tr.taskId, true, REMOVE_FROM_RECENTS);
-            }
-        }
-    }
-
-    private void cleanupDisabledPackageTasksLocked(String packageName, Set<String> filterByClasses,
-            int userId) {
-
-        for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
-            TaskRecord tr = mRecentTasks.get(i);
-            if (userId != UserHandle.USER_ALL && tr.userId != userId) {
-                continue;
-            }
-
-            ComponentName cn = tr.intent.getComponent();
-            final boolean sameComponent = cn != null && cn.getPackageName().equals(packageName)
-                    && (filterByClasses == null || filterByClasses.contains(cn.getClassName()));
-            if (sameComponent) {
-                mStackSupervisor.removeTaskByIdLocked(tr.taskId, false, REMOVE_FROM_RECENTS);
-            }
-        }
-    }
-
     @Override
     public void removeStack(int stackId) {
         enforceCallingPermission(Manifest.permission.MANAGE_ACTIVITY_STACKS, "removeStack()");
@@ -10388,11 +10124,14 @@
             final long ident = Binder.clearCallingIdentity();
             try {
                 final ActivityStack stack = mStackSupervisor.getStack(stackId);
-                if (stack != null && !stack.isActivityTypeStandardOrUndefined()) {
+                if (stack == null) {
+                    return;
+                }
+                if (!stack.isActivityTypeStandardOrUndefined()) {
                     throw new IllegalArgumentException(
                             "Removing non-standard stack is not allowed.");
                 }
-                mStackSupervisor.removeStackLocked(stackId);
+                mStackSupervisor.removeStack(stack);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -10758,7 +10497,7 @@
         try {
             synchronized (this) {
                 final ActivityStack stack =
-                        mStackSupervisor.getDefaultDisplay().getSplitScreenStack();
+                        mStackSupervisor.getDefaultDisplay().getSplitScreenPrimaryStack();
                 if (toTop) {
                     mStackSupervisor.resizeStackLocked(stack, null /* destBounds */,
                             null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
@@ -14145,7 +13884,6 @@
 
             // Load resources only after the current configuration has been set.
             final Resources res = mContext.getResources();
-            mHasRecents = res.getBoolean(com.android.internal.R.bool.config_hasRecents);
             mThumbnailWidth = res.getDimensionPixelSize(
                     com.android.internal.R.dimen.thumbnail_width);
             mThumbnailHeight = res.getDimensionPixelSize(
@@ -15104,10 +14842,31 @@
         long origId = Binder.clearCallingIdentity();
 
         if (useProto) {
-            //TODO: Options when dumping proto
             final ProtoOutputStream proto = new ProtoOutputStream(fd);
-            synchronized (this) {
-                writeActivitiesToProtoLocked(proto);
+            String cmd = opti < args.length ? args[opti] : "";
+            opti++;
+
+            if ("activities".equals(cmd) || "a".equals(cmd)) {
+                // output proto is ActivityStackSupervisorProto
+                synchronized (this) {
+                    writeActivitiesToProtoLocked(proto);
+                }
+            } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
+                // output proto is BroadcastProto
+                synchronized (this) {
+                    writeBroadcastsToProtoLocked(proto);
+                }
+            } else {
+                // default option, dump everything, output is ActivityManagerServiceProto
+                synchronized (this) {
+                    long activityToken = proto.start(ActivityManagerServiceProto.ACTIVITIES);
+                    writeActivitiesToProtoLocked(proto);
+                    proto.end(activityToken);
+
+                    long broadcastToken = proto.start(ActivityManagerServiceProto.BROADCASTS);
+                    writeBroadcastsToProtoLocked(proto);
+                    proto.end(broadcastToken);
+                }
             }
             proto.flush();
             Binder.restoreCallingIdentity(origId);
@@ -15131,9 +14890,15 @@
                 synchronized (this) {
                     dumpActivityStarterLocked(pw, dumpPackage);
                 }
+            } else if ("containers".equals(cmd)) {
+                synchronized (this) {
+                    dumpActivityContainersLocked(pw);
+                }
             } else if ("recents".equals(cmd) || "r".equals(cmd)) {
                 synchronized (this) {
-                    dumpRecentsLocked(fd, pw, args, opti, true, dumpPackage);
+                    if (mRecentTasks != null) {
+                        mRecentTasks.dump(pw, true /* dumpAll */, dumpPackage);
+                    }
                 }
             } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
                 String[] newArgs;
@@ -15354,7 +15119,9 @@
                 if (dumpAll) {
                     pw.println("-------------------------------------------------------------------------------");
                 }
-                dumpRecentsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
+                if (mRecentTasks != null) {
+                    mRecentTasks.dump(pw, dumpAll, dumpPackage);
+                }
                 pw.println();
                 if (dumpAll) {
                     pw.println("-------------------------------------------------------------------------------");
@@ -15369,6 +15136,11 @@
                 if (dumpAll) {
                     pw.println("-------------------------------------------------------------------------------");
                 }
+                dumpActivityContainersLocked(pw);
+                pw.println();
+                if (dumpAll) {
+                    pw.println("-------------------------------------------------------------------------------");
+                }
                 dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
                 if (mAssociations.size() > 0) {
                     pw.println();
@@ -15424,7 +15196,9 @@
                 if (dumpAll) {
                     pw.println("-------------------------------------------------------------------------------");
                 }
-                dumpRecentsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
+                if (mRecentTasks != null) {
+                    mRecentTasks.dump(pw, dumpAll, dumpPackage);
+                }
                 pw.println();
                 if (dumpAll) {
                     pw.println("-------------------------------------------------------------------------------");
@@ -15439,6 +15213,11 @@
                 if (dumpAll) {
                     pw.println("-------------------------------------------------------------------------------");
                 }
+                dumpActivityContainersLocked(pw);
+                pw.println();
+                if (dumpAll) {
+                    pw.println("-------------------------------------------------------------------------------");
+                }
                 dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
                 if (mAssociations.size() > 0) {
                     pw.println();
@@ -15458,7 +15237,8 @@
     }
 
     private void writeActivitiesToProtoLocked(ProtoOutputStream proto) {
-        mStackSupervisor.writeToProto(proto, ACTIVITIES);
+        // The output proto of "activity --proto activities" is ActivityStackSupervisorProto
+        mStackSupervisor.writeToProto(proto);
     }
 
     private void dumpLastANRLocked(PrintWriter pw) {
@@ -15470,6 +15250,12 @@
         }
     }
 
+    private void dumpActivityContainersLocked(PrintWriter pw) {
+        pw.println("ACTIVITY MANAGER STARTER (dumpsys activity containers)");
+        mStackSupervisor.dumpChildrenNames(pw, " ");
+        pw.println(" ");
+    }
+
     private void dumpActivityStarterLocked(PrintWriter pw, String dumpPackage) {
         pw.println("ACTIVITY MANAGER STARTER (dumpsys activity starter)");
         mActivityStarter.dump(pw, "", dumpPackage);
@@ -15510,42 +15296,6 @@
         }
     }
 
-    void dumpRecentsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
-            int opti, boolean dumpAll, String dumpPackage) {
-        pw.println("ACTIVITY MANAGER RECENT TASKS (dumpsys activity recents)");
-
-        boolean printedAnything = false;
-
-        if (mRecentTasks != null && mRecentTasks.size() > 0) {
-            boolean printedHeader = false;
-
-            final int N = mRecentTasks.size();
-            for (int i=0; i<N; i++) {
-                TaskRecord tr = mRecentTasks.get(i);
-                if (dumpPackage != null) {
-                    if (tr.realActivity == null ||
-                            !dumpPackage.equals(tr.realActivity.getPackageName())) {
-                        continue;
-                    }
-                }
-                if (!printedHeader) {
-                    pw.println("  Recent tasks:");
-                    printedHeader = true;
-                    printedAnything = true;
-                }
-                pw.print("  * Recent #"); pw.print(i); pw.print(": ");
-                        pw.println(tr);
-                if (dumpAll) {
-                    mRecentTasks.get(i).dump(pw, "    ");
-                }
-            }
-        }
-
-        if (!printedAnything) {
-            pw.println("  (nothing)");
-        }
-    }
-
     void dumpAssociationsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, boolean dumpClient, String dumpPackage) {
         pw.println("ACTIVITY MANAGER ASSOCIATIONS (dumpsys activity associations)");
@@ -16372,6 +16122,40 @@
         }
     }
 
+    void writeBroadcastsToProtoLocked(ProtoOutputStream proto) {
+        if (mRegisteredReceivers.size() > 0) {
+            Iterator it = mRegisteredReceivers.values().iterator();
+            while (it.hasNext()) {
+                ReceiverList r = (ReceiverList)it.next();
+                r.writeToProto(proto, BroadcastProto.RECEIVER_LIST);
+            }
+        }
+        mReceiverResolver.writeToProto(proto, BroadcastProto.RECEIVER_RESOLVER);
+        for (BroadcastQueue q : mBroadcastQueues) {
+            q.writeToProto(proto, BroadcastProto.BROADCAST_QUEUE);
+        }
+        for (int user=0; user<mStickyBroadcasts.size(); user++) {
+            long token = proto.start(BroadcastProto.STICKY_BROADCASTS);
+            proto.write(StickyBroadcastProto.USER, mStickyBroadcasts.keyAt(user));
+            for (Map.Entry<String, ArrayList<Intent>> ent
+                    : mStickyBroadcasts.valueAt(user).entrySet()) {
+                long actionToken = proto.start(StickyBroadcastProto.ACTIONS);
+                proto.write(StickyBroadcastProto.StickyAction.NAME, ent.getKey());
+                for (Intent intent : ent.getValue()) {
+                    intent.writeToProto(proto, StickyBroadcastProto.StickyAction.INTENTS,
+                            false, true, true, false);
+                }
+                proto.end(actionToken);
+            }
+            proto.end(token);
+        }
+
+        long handlerToken = proto.start(BroadcastProto.HANDLER);
+        proto.write(BroadcastProto.MainHandler.HANDLER, mHandler.toString());
+        mHandler.getLooper().writeToProto(proto, BroadcastProto.MainHandler.LOOPER);
+        proto.end(handlerToken);
+    }
+
     void dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, String dumpPackage) {
         boolean needSep = false;
@@ -19360,7 +19144,7 @@
                                         // Remove all permissions granted from/to this package
                                         removeUriPermissionsForPackageLocked(ssp, userId, true);
 
-                                        removeTasksByPackageNameLocked(ssp, userId);
+                                        mRecentTasks.removeTasksByPackageName(ssp, userId);
 
                                         mServices.forceStopPackageLocked(ssp, userId);
 
@@ -24368,125 +24152,6 @@
     }
 
     /**
-     * An implementation of IAppTask, that allows an app to manage its own tasks via
-     * {@link android.app.ActivityManager.AppTask}.  We keep track of the callingUid to ensure that
-     * only the process that calls getAppTasks() can call the AppTask methods.
-     */
-    class AppTaskImpl extends IAppTask.Stub {
-        private int mTaskId;
-        private int mCallingUid;
-
-        public AppTaskImpl(int taskId, int callingUid) {
-            mTaskId = taskId;
-            mCallingUid = callingUid;
-        }
-
-        private void checkCaller() {
-            if (mCallingUid != Binder.getCallingUid()) {
-                throw new SecurityException("Caller " + mCallingUid
-                        + " does not match caller of getAppTasks(): " + Binder.getCallingUid());
-            }
-        }
-
-        @Override
-        public void finishAndRemoveTask() {
-            checkCaller();
-
-            synchronized (ActivityManagerService.this) {
-                long origId = Binder.clearCallingIdentity();
-                try {
-                    // We remove the task from recents to preserve backwards
-                    if (!mStackSupervisor.removeTaskByIdLocked(mTaskId, false,
-                            REMOVE_FROM_RECENTS)) {
-                        throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
-                    }
-                } finally {
-                    Binder.restoreCallingIdentity(origId);
-                }
-            }
-        }
-
-        @Override
-        public ActivityManager.RecentTaskInfo getTaskInfo() {
-            checkCaller();
-
-            synchronized (ActivityManagerService.this) {
-                long origId = Binder.clearCallingIdentity();
-                try {
-                    TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(mTaskId);
-                    if (tr == null) {
-                        throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
-                    }
-                    return createRecentTaskInfoFromTaskRecord(tr);
-                } finally {
-                    Binder.restoreCallingIdentity(origId);
-                }
-            }
-        }
-
-        @Override
-        public void moveToFront() {
-            checkCaller();
-            // Will bring task to front if it already has a root activity.
-            final long origId = Binder.clearCallingIdentity();
-            try {
-                synchronized (this) {
-                    mStackSupervisor.startActivityFromRecentsInner(mTaskId, null);
-                }
-            } finally {
-                Binder.restoreCallingIdentity(origId);
-            }
-        }
-
-        @Override
-        public int startActivity(IBinder whoThread, String callingPackage,
-                Intent intent, String resolvedType, Bundle bOptions) {
-            checkCaller();
-
-            int callingUser = UserHandle.getCallingUserId();
-            TaskRecord tr;
-            IApplicationThread appThread;
-            synchronized (ActivityManagerService.this) {
-                tr = mStackSupervisor.anyTaskForIdLocked(mTaskId);
-                if (tr == null) {
-                    throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
-                }
-                appThread = IApplicationThread.Stub.asInterface(whoThread);
-                if (appThread == null) {
-                    throw new IllegalArgumentException("Bad app thread " + appThread);
-                }
-            }
-            return mActivityStarter.startActivityMayWait(appThread, -1, callingPackage, intent,
-                    resolvedType, null, null, null, null, 0, 0, null, null,
-                    null, bOptions, false, callingUser, tr, "AppTaskImpl");
-        }
-
-        @Override
-        public void setExcludeFromRecents(boolean exclude) {
-            checkCaller();
-
-            synchronized (ActivityManagerService.this) {
-                long origId = Binder.clearCallingIdentity();
-                try {
-                    TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(mTaskId);
-                    if (tr == null) {
-                        throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
-                    }
-                    Intent intent = tr.getBaseIntent();
-                    if (exclude) {
-                        intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-                    } else {
-                        intent.setFlags(intent.getFlags()
-                                & ~Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-                    }
-                } finally {
-                    Binder.restoreCallingIdentity(origId);
-                }
-            }
-        }
-    }
-
-    /**
      * Kill processes for the user with id userId and that depend on the package named packageName
      */
     @Override
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index fdcb8c6..93c0f77 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -5,6 +5,7 @@
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.ActivityManagerInternal.APP_TRANSITION_TIMEOUT;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
@@ -127,7 +128,7 @@
             case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY:
                 mWindowState = WINDOW_STATE_SIDE_BY_SIDE;
                 break;
-            case WINDOW_STATE_FREEFORM:
+            case WINDOWING_MODE_FREEFORM:
                 mWindowState = WINDOW_STATE_FREEFORM;
                 break;
             default:
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index f544d37..2c72a4d 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -58,6 +58,10 @@
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
 import static android.content.pm.ActivityInfo.PERSIST_ACROSS_REBOOTS;
 import static android.content.pm.ActivityInfo.PERSIST_ROOT_ONLY;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
@@ -282,6 +286,7 @@
     int configChangeFlags;  // which config values have changed
     private boolean keysPaused;     // has key dispatching been paused for it?
     int launchMode;         // the launch mode activity attribute.
+    int lockTaskLaunchMode; // the lockTaskMode manifest attribute, subject to override
     boolean visible;        // does this activity's window need to be shown?
     boolean visibleIgnoringKeyguard; // is this activity visible, ignoring the fact that Keyguard
                                      // might hide this activity?
@@ -418,9 +423,13 @@
             if (iconFilename != null || taskDescription.getLabel() != null ||
                     taskDescription.getPrimaryColor() != 0) {
                 pw.print(prefix); pw.print("taskDescription:");
-                        pw.print(" iconFilename="); pw.print(taskDescription.getIconFilename());
                         pw.print(" label=\""); pw.print(taskDescription.getLabel());
                                 pw.print("\"");
+                        pw.print(" icon="); pw.print(taskDescription.getInMemoryIcon() != null
+                                ? taskDescription.getInMemoryIcon().getByteCount() + " bytes"
+                                : "null");
+                        pw.print(" iconResource="); pw.print(taskDescription.getIconResource());
+                        pw.print(" iconFilename="); pw.print(taskDescription.getIconFilename());
                         pw.print(" primaryColor=");
                         pw.println(Integer.toHexString(taskDescription.getPrimaryColor()));
                         pw.print(prefix + " backgroundColor=");
@@ -430,9 +439,6 @@
                         pw.print(prefix + " navigationBarColor=");
                         pw.println(Integer.toHexString(taskDescription.getNavigationBarColor()));
             }
-            if (iconFilename == null && taskDescription.getIcon() != null) {
-                pw.print(prefix); pw.println("taskDescription contains Bitmap");
-            }
         }
         if (results != null) {
             pw.print(prefix); pw.print("results="); pw.println(results);
@@ -824,23 +830,6 @@
         hasBeenLaunched = false;
         mStackSupervisor = supervisor;
 
-        mRotationAnimationHint = aInfo.rotationAnimation;
-
-        if (options != null) {
-            pendingOptions = options;
-            mLaunchTaskBehind = pendingOptions.getLaunchTaskBehind();
-
-            final int rotationAnimation = pendingOptions.getRotationAnimationHint();
-            // Only override manifest supplied option if set.
-            if (rotationAnimation >= 0) {
-                mRotationAnimationHint = rotationAnimation;
-            }
-            PendingIntent usageReport = pendingOptions.getUsageTimeReport();
-            if (usageReport != null) {
-                appTimeTracker = new AppTimeTracker(usageReport);
-            }
-        }
-
         // This starts out true, since the initial state of an activity is that we have everything,
         // and we shouldn't never consider it lacking in state to be removed if it dies.
         haveState = true;
@@ -907,6 +896,32 @@
 
         mShowWhenLocked = (aInfo.flags & FLAG_SHOW_WHEN_LOCKED) != 0;
         mTurnScreenOn = (aInfo.flags & FLAG_TURN_SCREEN_ON) != 0;
+
+        mRotationAnimationHint = aInfo.rotationAnimation;
+        lockTaskLaunchMode = aInfo.lockTaskLaunchMode;
+        if (appInfo.isPrivilegedApp() && (lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_ALWAYS
+                || lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_NEVER)) {
+            lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_DEFAULT;
+        }
+
+        if (options != null) {
+            pendingOptions = options;
+            mLaunchTaskBehind = options.getLaunchTaskBehind();
+
+            final int rotationAnimation = pendingOptions.getRotationAnimationHint();
+            // Only override manifest supplied option if set.
+            if (rotationAnimation >= 0) {
+                mRotationAnimationHint = rotationAnimation;
+            }
+            final PendingIntent usageReport = pendingOptions.getUsageTimeReport();
+            if (usageReport != null) {
+                appTimeTracker = new AppTimeTracker(usageReport);
+            }
+            final boolean useLockTask = pendingOptions.getLockTaskMode();
+            if (useLockTask && lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_DEFAULT) {
+                lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
+            }
+        }
     }
 
     AppWindowContainerController getWindowContainerController() {
@@ -1544,7 +1559,7 @@
             // On devices that support leanback only (Android TV), Recents activity can only be
             // visible if the home stack is the focused stack or we are in split-screen mode.
             final ActivityDisplay display = getDisplay();
-            boolean hasSplitScreenStack = display != null && display.hasSplitScreenStack();
+            boolean hasSplitScreenStack = display != null && display.hasSplitScreenPrimaryStack();
             isVisible = hasSplitScreenStack || mStackSupervisor.isFocusedStack(getStack());
         }
 
@@ -2732,6 +2747,8 @@
 
     void setShowWhenLocked(boolean showWhenLocked) {
         mShowWhenLocked = showWhenLocked;
+        mStackSupervisor.ensureActivitiesVisibleLocked(null, 0 /* configChanges */,
+                false /* preserveWindows */);
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 05db922..941c371 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -16,7 +16,6 @@
 
 package com.android.server.am;
 
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
@@ -34,8 +33,8 @@
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
-
 import static android.view.Display.INVALID_DISPLAY;
+
 import static com.android.server.am.ActivityDisplay.POSITION_BOTTOM;
 import static com.android.server.am.ActivityDisplay.POSITION_TOP;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
@@ -99,12 +98,10 @@
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
-import android.app.ActivityManager.StackId;
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
 import android.app.IActivityController;
 import android.app.ResultInfo;
-import android.app.WindowConfiguration;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -193,10 +190,6 @@
     // finished destroying itself.
     private static final int DESTROY_TIMEOUT = 10 * 1000;
 
-    // How long until we reset a task when the user returns to it.  Currently
-    // disabled.
-    private static final long ACTIVITY_INACTIVE_RESET_TIME = 0;
-
     // Set to false to disable the preview that is shown while a new activity
     // is being started.
     private static final boolean SHOW_APP_STARTING_PREVIEW = true;
@@ -358,8 +351,6 @@
     /** Run all ActivityStacks through this */
     protected final ActivityStackSupervisor mStackSupervisor;
 
-    private final LaunchingTaskPositioner mTaskPositioner;
-
     private boolean mTopActivityOccludesKeyguard;
     private ActivityRecord mTopDismissingKeyguardActivity;
 
@@ -462,8 +453,6 @@
         mWindowManager = mService.mWindowManager;
         mStackId = stackId;
         mCurrentUser = mService.mUserController.getCurrentUserId();
-        mTaskPositioner = windowingMode == WINDOWING_MODE_FREEFORM
-                ? new LaunchingTaskPositioner() : null;
         mTmpRect2.setEmpty();
         setWindowingMode(windowingMode);
         setActivityType(activityType);
@@ -481,6 +470,39 @@
         return mWindowContainerController;
     }
 
+    @Override
+    public void onConfigurationChanged(Configuration newParentConfig) {
+        final int prevWindowingMode = getWindowingMode();
+        super.onConfigurationChanged(newParentConfig);
+        final ActivityDisplay display = getDisplay();
+        if (display != null && prevWindowingMode != getWindowingMode()) {
+            display.onStackWindowingModeChanged(this);
+        }
+    }
+
+    @Override
+    public boolean isCompatible(int windowingMode, int activityType) {
+        // TODO: Should we just move this to ConfigurationContainer?
+        if (activityType == ACTIVITY_TYPE_UNDEFINED) {
+            // Undefined activity types end up in a standard stack once the stack is created on a
+            // display, so they should be considered compatible.
+            activityType = ACTIVITY_TYPE_STANDARD;
+        }
+        final ActivityDisplay display = getDisplay();
+        if (display != null) {
+            if (activityType == ACTIVITY_TYPE_STANDARD
+                    && windowingMode == WINDOWING_MODE_UNDEFINED) {
+                // Standard activity types will mostly take on the windowing mode of the display if
+                // one isn't specified, so look-up a compatible stack based on the display's
+                // windowing mode.
+                windowingMode = display.getWindowingMode();
+            }
+            windowingMode =
+                    display.updateWindowingModeForSplitScreenIfNeeded(windowingMode, activityType);
+        }
+        return super.isCompatible(windowingMode, activityType);
+    }
+
     /** Adds the stack to specified display and calls WindowManager to do the same. */
     void reparent(ActivityDisplay activityDisplay, boolean onTop) {
         removeFromDisplay();
@@ -504,11 +526,7 @@
         mDisplayId = activityDisplay.mDisplayId;
         mBounds = bounds != null ? new Rect(bounds) : null;
         mFullscreen = mBounds == null;
-        if (mTaskPositioner != null) {
-            activityDisplay.mDisplay.getSize(mTmpSize);
-            mTaskPositioner.setDisplaySize(mTmpSize);
-            mTaskPositioner.configure(mBounds);
-        }
+
         onParentChanged();
 
         activityDisplay.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM);
@@ -536,9 +554,6 @@
             display.removeChild(this);
         }
         mDisplayId = INVALID_DISPLAY;
-        if (mTaskPositioner != null) {
-            mTaskPositioner.reset();
-        }
     }
 
     /** Removes the stack completely. Also calls WindowManager to do the same on its side. */
@@ -642,9 +657,6 @@
 
     void setBounds(Rect bounds) {
         mBounds = mFullscreen ? null : new Rect(bounds);
-        if (mTaskPositioner != null) {
-            mTaskPositioner.configure(bounds);
-        }
     }
 
     ActivityRecord topRunningActivityLocked() {
@@ -1547,6 +1559,10 @@
                 && !mForceHidden;
     }
 
+    boolean isTopStackOnDisplay() {
+        return getDisplay().isTopStack(this);
+    }
+
     /**
      * Returns true if the stack should be visible.
      *
@@ -1557,22 +1573,15 @@
             return false;
         }
 
-        if (mStackSupervisor.isFrontStackOnDisplay(this) || mStackSupervisor.isFocusedStack(this)) {
+        final ActivityDisplay display = getDisplay();
+        if (isTopStackOnDisplay() || mStackSupervisor.isFocusedStack(this)) {
             return true;
         }
 
-        final ActivityDisplay display = getDisplay();
-        final ArrayList<ActivityStack> displayStacks = display.mStacks;
-        final int stackIndex = displayStacks.indexOf(this);
-
-        if (stackIndex == displayStacks.size() - 1) {
-            Slog.wtf(TAG,
-                    "Stack=" + this + " isn't front stack but is at the top of the stack list");
-            return false;
-        }
+        final int stackIndex = display.getIndexOf(this);
 
         // Check position and visibility of this stack relative to the front stack on its display.
-        final ActivityStack topStack = getTopStackOnDisplay();
+        final ActivityStack topStack = getDisplay().getTopStack();
         final int windowingMode = getWindowingMode();
         final int activityType = getActivityType();
 
@@ -1589,22 +1598,21 @@
         // A case would be if recents stack exists but has no tasks and is below the docked stack
         // and home stack is below recents
         if (activityType == ACTIVITY_TYPE_HOME) {
-            final ActivityStack splitScreenStack = display.getStack(
-                    WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
-            int dockedStackIndex = displayStacks.indexOf(splitScreenStack);
+            final ActivityStack splitScreenStack = display.getSplitScreenPrimaryStack();
+            int dockedStackIndex = display.getIndexOf(splitScreenStack);
             if (dockedStackIndex > stackIndex && stackIndex != dockedStackIndex - 1) {
                 return false;
             }
         }
 
         // Find the first stack behind front stack that actually got something visible.
-        int stackBehindTopIndex = displayStacks.indexOf(topStack) - 1;
+        int stackBehindTopIndex = display.getIndexOf(topStack) - 1;
         while (stackBehindTopIndex >= 0 &&
-                displayStacks.get(stackBehindTopIndex).topRunningActivityLocked() == null) {
+                display.getChildAt(stackBehindTopIndex).topRunningActivityLocked() == null) {
             stackBehindTopIndex--;
         }
         final ActivityStack stackBehindTop = (stackBehindTopIndex >= 0)
-                ? displayStacks.get(stackBehindTopIndex) : null;
+                ? display.getChildAt(stackBehindTopIndex) : null;
         int stackBehindTopWindowingMode = WINDOWING_MODE_UNDEFINED;
         int stackBehindTopActivityType = ACTIVITY_TYPE_UNDEFINED;
         if (stackBehindTop != null) {
@@ -1653,8 +1661,9 @@
             return false;
         }
 
-        for (int i = stackIndex + 1; i < displayStacks.size(); i++) {
-            final ActivityStack stack = displayStacks.get(i);
+        final int stackCount = display.getChildCount();
+        for (int i = stackIndex + 1; i < stackCount; i++) {
+            final ActivityStack stack = display.getChildAt(i);
 
             if (!stack.mFullscreen && !stack.hasFullscreenTask()) {
                 continue;
@@ -2183,7 +2192,7 @@
         mResumedActivity = r;
         r.state = ActivityState.RESUMED;
         mService.setResumedActivityUncheckLocked(r, reason);
-        mStackSupervisor.addRecentActivity(r);
+        mStackSupervisor.mRecentTasks.add(r.getTask());
     }
 
     private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
@@ -2590,8 +2599,8 @@
                     Slog.i(TAG, "Restarting because process died: " + next);
                     if (!next.hasBeenLaunched) {
                         next.hasBeenLaunched = true;
-                    } else  if (SHOW_APP_STARTING_PREVIEW && lastStack != null &&
-                            mStackSupervisor.isFrontStackOnDisplay(lastStack)) {
+                    } else  if (SHOW_APP_STARTING_PREVIEW && lastStack != null
+                            && lastStack.isTopStackOnDisplay()) {
                         next.showStartingWindow(null /* prev */, false /* newTask */,
                                 false /* taskSwitch */);
                     }
@@ -3203,15 +3212,8 @@
 
     final ActivityRecord resetTaskIfNeededLocked(ActivityRecord taskTop,
             ActivityRecord newActivity) {
-        boolean forceReset =
+        final boolean forceReset =
                 (newActivity.info.flags & ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
-        if (ACTIVITY_INACTIVE_RESET_TIME > 0
-                && taskTop.getTask().getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
-            if ((newActivity.info.flags & ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
-                forceReset = true;
-            }
-        }
-
         final TaskRecord task = taskTop.getTask();
 
         /** False until we evaluate the TaskRecord associated with taskTop. Switches to true
@@ -4453,7 +4455,7 @@
             AppTimeTracker timeTracker, String reason) {
         if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
 
-        final ActivityStack topStack = getTopStackOnDisplay();
+        final ActivityStack topStack = getDisplay().getTopStack();
         final ActivityRecord topActivity = topStack != null ? topStack.topActivity() : null;
         final int numTasks = mTaskHistory.size();
         final int index = mTaskHistory.indexOf(tr);
@@ -4481,7 +4483,9 @@
         // Don't refocus if invisible to current user
         final ActivityRecord top = tr.getTopActivity();
         if (top == null || !top.okToShowLocked()) {
-            mStackSupervisor.addRecentActivity(top);
+            if (top != null) {
+                mStackSupervisor.mRecentTasks.add(top.getTask());
+            }
             ActivityOptions.abort(options);
             return;
         }
@@ -4541,7 +4545,7 @@
         // If we have a watcher, preflight the move before committing to it.  First check
         // for *other* available tasks, but if none are available, then try again allowing the
         // current task to be selected.
-        if (mStackSupervisor.isFrontStackOnDisplay(this) && mService.mController != null) {
+        if (isTopStackOnDisplay() && mService.mController != null) {
             ActivityRecord next = topRunningActivityLocked(null, taskId);
             if (next == null) {
                 next = topRunningActivityLocked(null, 0);
@@ -4589,7 +4593,7 @@
         }
 
         if (inPinnedWindowingMode()) {
-            mStackSupervisor.removeStackLocked(mStackId);
+            mStackSupervisor.removeStack(this);
             return true;
         }
 
@@ -4621,15 +4625,6 @@
         return true;
     }
 
-    /**
-     * Get the topmost stack on the current display. It may be different from focused stack, because
-     * focus may be on another display.
-     */
-    private ActivityStack getTopStackOnDisplay() {
-        final ArrayList<ActivityStack> stacks = getDisplay().mStacks;
-        return stacks.isEmpty() ? null : stacks.get(stacks.size() - 1);
-    }
-
     static void logStartActivity(int tag, ActivityRecord r, TaskRecord task) {
         final Uri data = r.intent.getData();
         final String strData = data != null ? data.toSafeString() : null;
@@ -4906,7 +4901,7 @@
             if (focusedStack && topTask) {
                 // Give the latest time to ensure foreground task can be sorted
                 // at the first, because lastActiveTime of creating task is 0.
-                ci.lastActiveTime = System.currentTimeMillis();
+                ci.lastActiveTime = SystemClock.elapsedRealtime();
                 topTask = false;
             }
 
@@ -5086,7 +5081,7 @@
             if (task.autoRemoveFromRecents() || isVoiceSession) {
                 // Task creator asked to remove this when done, or this task was a voice
                 // interaction, so it should not remain on the recent tasks list.
-                mStackSupervisor.removeTaskFromRecents(task);
+                mStackSupervisor.mRecentTasks.remove(task);
             }
 
             task.removeWindowContainer();
@@ -5137,10 +5132,12 @@
     }
 
     boolean layoutTaskInStack(TaskRecord task, ActivityInfo.WindowLayout windowLayout) {
-        if (mTaskPositioner == null) {
+        if (!task.inFreeformWindowingMode()) {
             return false;
         }
-        mTaskPositioner.updateDefaultBounds(task, mTaskHistory, windowLayout);
+        mStackSupervisor.getLaunchingTaskPositioner()
+                .updateDefaultBounds(task, mTaskHistory, windowLayout);
+
         return true;
     }
 
@@ -5270,7 +5267,7 @@
                 + mTaskHistory.size() + " tasks}";
     }
 
-    void onLockTaskPackagesUpdatedLocked() {
+    void onLockTaskPackagesUpdated() {
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             mTaskHistory.get(taskNdx).setLockTaskAuth();
         }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index bac71c7..736a766 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -46,6 +46,7 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.Display.TYPE_VIRTUAL;
+
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
@@ -85,12 +86,13 @@
 import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
 import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
 import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
+import static com.android.server.am.proto.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER;
 import static com.android.server.am.proto.ActivityStackSupervisorProto.DISPLAYS;
 import static com.android.server.am.proto.ActivityStackSupervisorProto.FOCUSED_STACK_ID;
 import static com.android.server.am.proto.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER;
 import static com.android.server.am.proto.ActivityStackSupervisorProto.RESUMED_ACTIVITY;
-import static com.android.server.am.proto.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER;
 import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS;
+
 import static java.lang.Integer.MAX_VALUE;
 
 import android.Manifest;
@@ -101,7 +103,6 @@
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
-import android.app.ActivityManager.StackId;
 import android.app.ActivityManager.StackInfo;
 import android.app.ActivityManagerInternal.SleepToken;
 import android.app.ActivityOptions;
@@ -175,7 +176,8 @@
 import java.util.List;
 import java.util.Set;
 
-public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener {
+public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener,
+        RecentTasks.Callbacks {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
     private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
     private static final String TAG_IDLE = TAG + POSTFIX_IDLE;
@@ -285,7 +287,7 @@
 
     final ActivityManagerService mService;
 
-    private RecentTasks mRecentTasks;
+    RecentTasks mRecentTasks;
 
     final ActivityStackSupervisorHandler mHandler;
 
@@ -293,6 +295,8 @@
     WindowManagerService mWindowManager;
     DisplayManager mDisplayManager;
 
+    LaunchingTaskPositioner mTaskPositioner = new LaunchingTaskPositioner();
+
     /** Counter for next free stack ID to use for dynamic activity stacks. */
     private int mNextFreeStackId = 0;
 
@@ -575,6 +579,7 @@
 
     void setRecentTasks(RecentTasks recentTasks) {
         mRecentTasks = recentTasks;
+        mRecentTasks.registerCallback(this);
     }
 
     /**
@@ -626,15 +631,6 @@
         return stack != null && stack == mFocusedStack;
     }
 
-    /** The top most stack on its display. */
-    boolean isFrontStackOnDisplay(ActivityStack stack) {
-        return isFrontOfStackList(stack, stack.getDisplay().mStacks);
-    }
-
-    private boolean isFrontOfStackList(ActivityStack stack, List<ActivityStack> stackList) {
-        return stack == stackList.get((stackList.size() - 1));
-    }
-
     /** NOTE: Should only be called from {@link ActivityStack#moveToFront} */
     void setFocusStackUnchecked(String reason, ActivityStack focusCandidate) {
         if (!focusCandidate.isFocusable()) {
@@ -710,7 +706,7 @@
     }
 
     TaskRecord anyTaskForIdLocked(int id, @AnyTaskForIdMatchTaskMode int matchMode) {
-        return anyTaskForIdLocked(id, matchMode, null);
+        return anyTaskForIdLocked(id, matchMode, null, !ON_TOP);
     }
 
     /**
@@ -718,11 +714,11 @@
      * @param id Id of the task we would like returned.
      * @param matchMode The mode to match the given task id in.
      * @param aOptions The activity options to use for restoration. Can be null.
+     * @param onTop If the stack for the task should be the topmost on the display.
      */
     TaskRecord anyTaskForIdLocked(int id, @AnyTaskForIdMatchTaskMode int matchMode,
-            @Nullable ActivityOptions aOptions) {
-        // If there is a stack id set, ensure that we are attempting to actually restore a task
-        // TODO: Don't really know if this is needed...
+            @Nullable ActivityOptions aOptions, boolean onTop) {
+        // If options are set, ensure that we are attempting to actually restore a task
         if (matchMode != MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE && aOptions != null) {
             throw new IllegalArgumentException("Should not specify activity options for non-restore"
                     + " lookup");
@@ -730,13 +726,25 @@
 
         int numDisplays = mActivityDisplays.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 final TaskRecord task = stack.taskForIdLocked(id);
-                if (task != null) {
-                    return task;
+                if (task == null) {
+                    continue;
                 }
+                if (aOptions != null) {
+                    // Resolve the stack the task should be placed in now based on options
+                    // and reparent if needed.
+                    final ActivityStack launchStack = getLaunchStack(null, aOptions, task, onTop);
+                    if (launchStack != null && stack != launchStack) {
+                        final int reparentMode = onTop
+                                ? REPARENT_MOVE_STACK_TO_FRONT : REPARENT_LEAVE_STACK_IN_PLACE;
+                        task.reparent(launchStack, onTop, reparentMode, ANIMATE, DEFER_RESUME,
+                                "anyTaskForIdLocked");
+                    }
+                }
+                return task;
             }
         }
 
@@ -748,7 +756,7 @@
         // Otherwise, check the recent tasks and return if we find it there and we are not restoring
         // the task from recents
         if (DEBUG_RECENTS) Slog.v(TAG_RECENTS, "Looking for task id=" + id + " in recents");
-        final TaskRecord task = mRecentTasks.taskForIdLocked(id);
+        final TaskRecord task = mRecentTasks.getTask(id);
 
         if (task == null) {
             if (DEBUG_RECENTS) {
@@ -763,7 +771,7 @@
         }
 
         // Implicitly, this case is MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE
-        if (!restoreRecentTaskLocked(task, aOptions)) {
+        if (!restoreRecentTaskLocked(task, aOptions, onTop)) {
             if (DEBUG_RECENTS) Slog.w(TAG_RECENTS,
                     "Couldn't restore task id=" + id + " found in recents");
             return null;
@@ -775,9 +783,10 @@
     ActivityRecord isInAnyStackLocked(IBinder token) {
         int numDisplays = mActivityDisplays.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityRecord r = stacks.get(stackNdx).isInStackLocked(token);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
+                final ActivityRecord r = stack.isInStackLocked(token);
                 if (r != null) {
                     return r;
                 }
@@ -815,18 +824,21 @@
     void lockAllProfileTasks(@UserIdInt int userId) {
         mWindowManager.deferSurfaceLayout();
         try {
-            final List<ActivityStack> stacks = getStacks();
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; stackNdx--) {
-                final List<TaskRecord> tasks = stacks.get(stackNdx).getAllTasks();
-                for (int taskNdx = tasks.size() - 1; taskNdx >= 0; taskNdx--) {
-                    final TaskRecord task = tasks.get(taskNdx);
+            for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+                final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+                for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                    final ActivityStack stack = display.getChildAt(stackNdx);
+                    final List<TaskRecord> tasks = stack.getAllTasks();
+                    for (int taskNdx = tasks.size() - 1; taskNdx >= 0; taskNdx--) {
+                        final TaskRecord task = tasks.get(taskNdx);
 
-                    // Check the task for a top activity belonging to userId, or returning a result
-                    // to an activity belonging to userId. Example case: a document picker for
-                    // personal files, opened by a work app, should still get locked.
-                    if (taskTopActivityIsUser(task, userId)) {
-                        mService.mTaskChangeNotificationController.notifyTaskProfileLocked(
-                                task.taskId, userId);
+                        // Check the task for a top activity belonging to userId, or returning a
+                        // result to an activity belonging to userId. Example case: a document
+                        // picker for personal files, opened by a work app, should still get locked.
+                        if (taskTopActivityIsUser(task, userId)) {
+                            mService.mTaskChangeNotificationController.notifyTaskProfileLocked(
+                                    task.taskId, userId);
+                        }
                     }
                 }
             }
@@ -857,7 +869,7 @@
         // [u*MAX_TASK_IDS_PER_USER, (u+1)*MAX_TASK_IDS_PER_USER-1], so if MAX_TASK_IDS_PER_USER
         // was 10, user 0 could only have taskIds 0 to 9, user 1: 10 to 19, user 2: 20 to 29, so on.
         int candidateTaskId = nextTaskIdForUser(currentTaskId, userId);
-        while (mRecentTasks.taskIdTakenForUserLocked(candidateTaskId, userId)
+        while (mRecentTasks.containsTaskId(candidateTaskId, userId)
                 || anyTaskForIdLocked(
                         candidateTaskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS) != null) {
             candidateTaskId = nextTaskIdForUser(candidateTaskId, userId);
@@ -892,9 +904,9 @@
         final String processName = app.processName;
         boolean didSomething = false;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 if (!isFocusedStack(stack)) {
                     continue;
                 }
@@ -927,9 +939,9 @@
 
     boolean allResumedActivitiesIdle() {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 if (!isFocusedStack(stack) || stack.numActivities() == 0) {
                     continue;
                 }
@@ -948,9 +960,9 @@
 
     boolean allResumedActivitiesComplete() {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 if (isFocusedStack(stack)) {
                     final ActivityRecord r = stack.mResumedActivity;
                     if (r != null && r.state != RESUMED) {
@@ -967,12 +979,12 @@
         return true;
     }
 
-    boolean allResumedActivitiesVisible() {
+    private boolean allResumedActivitiesVisible() {
         boolean foundResumed = false;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 final ActivityRecord r = stack.mResumedActivity;
                 if (r != null) {
                     if (!r.nowVisible || mActivitiesWaitingForVisibleActivity.contains(r)) {
@@ -996,9 +1008,9 @@
     boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming, boolean dontWait) {
         boolean someActivityPaused = false;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 if (!isFocusedStack(stack) && stack.mResumedActivity != null) {
                     if (DEBUG_STATES) Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack +
                             " mResumedActivity=" + stack.mResumedActivity);
@@ -1013,9 +1025,9 @@
     boolean allPausedActivitiesComplete() {
         boolean pausing = true;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 final ActivityRecord r = stack.mPausingActivity;
                 if (r != null && r.state != PAUSED && r.state != STOPPED && r.state != STOPPING) {
                     if (DEBUG_STATES) {
@@ -1033,9 +1045,10 @@
 
     void cancelInitializingActivities() {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                stacks.get(stackNdx).cancelInitializingActivities();
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
+                stack.cancelInitializingActivities();
             }
         }
     }
@@ -1133,13 +1146,10 @@
 
         for (int i = mTmpOrderedDisplayIds.size() - 1; i >= 0; --i) {
             final int displayId = mTmpOrderedDisplayIds.get(i);
-            final List<ActivityStack> stacks = mActivityDisplays.get(displayId).mStacks;
-            if (stacks == null) {
-                continue;
-            }
-            for (int j = stacks.size() - 1; j >= 0; --j) {
-                final ActivityStack stack = stacks.get(j);
-                if (stack != focusedStack && isFrontStackOnDisplay(stack) && stack.isFocusable()) {
+            final ActivityDisplay display = mActivityDisplays.get(displayId);
+            for (int j = display.getChildCount() - 1; j >= 0; --j) {
+                final ActivityStack stack = display.getChildAt(j);
+                if (stack != focusedStack && stack.isTopStackOnDisplay() && stack.isFocusable()) {
                     r = stack.topRunningActivityLocked();
                     if (r != null) {
                         return r;
@@ -1155,9 +1165,9 @@
         ArrayList<ArrayList<RunningTaskInfo>> runningTaskLists = new ArrayList<>();
         final int numDisplays = mActivityDisplays.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 ArrayList<RunningTaskInfo> stackTaskList = new ArrayList<>();
                 runningTaskLists.add(stackTaskList);
                 stack.getTasksLocked(stackTaskList, callingUid, allowed);
@@ -1606,6 +1616,16 @@
                 Slog.w(TAG, msg);
                 throw new SecurityException(msg);
             }
+            // Check if someone tries to launch an unwhitelisted activity into LockTask mode.
+            final boolean lockTaskMode = options.getLockTaskMode();
+            if (lockTaskMode && !mService.mLockTaskController.isPackageWhitelisted(
+                    UserHandle.getUserId(callingUid), aInfo.packageName)) {
+                final String msg = "Permission Denial: starting " + intent.toString()
+                        + " from " + callerApp + " (pid=" + callingPid
+                        + ", uid=" + callingUid + ") with lockTaskMode=true";
+                Slog.w(TAG, msg);
+                throw new SecurityException(msg);
+            }
         }
 
         return true;
@@ -1927,9 +1947,10 @@
     boolean handleAppDiedLocked(ProcessRecord app) {
         boolean hasVisibleActivities = false;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                hasVisibleActivities |= stacks.get(stackNdx).handleAppDiedLocked(app);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
+                hasVisibleActivities |= stack.handleAppDiedLocked(app);
             }
         }
         return hasVisibleActivities;
@@ -1937,9 +1958,10 @@
 
     void closeSystemDialogsLocked() {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                stacks.get(stackNdx).closeSystemDialogsLocked();
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
+                stack.closeSystemDialogsLocked();
             }
         }
     }
@@ -1965,9 +1987,9 @@
             boolean doit, boolean evenPersistent, int userId) {
         boolean didSomething = false;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 if (stack.finishDisabledPackageActivitiesLocked(
                         packageName, filterByClasses, doit, evenPersistent, userId)) {
                     didSomething = true;
@@ -1987,9 +2009,9 @@
         // hosted by the process that is actually still the foreground.
         ProcessRecord fgApp = null;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 if (isFocusedStack(stack)) {
                     if (stack.mResumedActivity != null) {
                         fgApp = stack.mResumedActivity.app;
@@ -2039,9 +2061,10 @@
 
     void updateActivityApplicationInfoLocked(ApplicationInfo aInfo) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                stacks.get(stackNdx).updateActivityApplicationInfoLocked(aInfo);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
+                stack.updateActivityApplicationInfoLocked(aInfo);
             }
         }
     }
@@ -2050,10 +2073,10 @@
         TaskRecord finishedTask = null;
         ActivityStack focusedStack = getFocusedStack();
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            final int numStacks = stacks.size();
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            final int numStacks = display.getChildCount();
             for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 TaskRecord t = stack.finishTopRunningActivityLocked(app, reason);
                 if (stack == focusedStack || finishedTask == null) {
                     finishedTask = t;
@@ -2065,10 +2088,10 @@
 
     void finishVoiceTask(IVoiceInteractionSession session) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            final int numStacks = stacks.size();
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            final int numStacks = display.getChildCount();
             for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 stack.finishVoiceTask(session);
             }
         }
@@ -2124,7 +2147,7 @@
                 "findTaskToMoveToFront: moved to front of stack=" + currentStack);
 
         handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY,
-                currentStack.mStackId, forceNonResizeable);
+                currentStack, forceNonResizeable);
     }
 
     boolean canUseActivityOptionsLaunchBounds(ActivityOptions options) {
@@ -2138,6 +2161,10 @@
                 || mService.mSupportsFreeformWindowManagement;
     }
 
+    LaunchingTaskPositioner getLaunchingTaskPositioner() {
+        return mTaskPositioner;
+    }
+
     protected <T extends ActivityStack> T getStack(int stackId) {
         for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
             final T stack = mActivityDisplays.valueAt(i).getStack(stackId);
@@ -2233,11 +2260,13 @@
             }
         }
 
-        if (isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
+        if (windowingMode != WINDOWING_MODE_UNDEFINED
+                && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
                 supportsFreeform, supportsPip, activityType)) {
             return windowingMode;
         }
-        return WINDOWING_MODE_FULLSCREEN;
+        // Return root/systems windowing mode
+        return getWindowingMode();
     }
 
     int resolveActivityType(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
@@ -2251,7 +2280,10 @@
         if (activityType != ACTIVITY_TYPE_UNDEFINED) {
             return activityType;
         }
-        return options != null ? options.getLaunchActivityType() : ACTIVITY_TYPE_UNDEFINED;
+        if (options != null) {
+            activityType = options.getLaunchActivityType();
+        }
+        return activityType != ACTIVITY_TYPE_UNDEFINED ? activityType : ACTIVITY_TYPE_STANDARD;
     }
 
     <T extends ActivityStack> T getLaunchStack(@Nullable ActivityRecord r,
@@ -2289,7 +2321,7 @@
             // Temporarily set the task id to invalid in case in re-entry.
             options.setLaunchTaskId(INVALID_TASK_ID);
             final TaskRecord task = anyTaskForIdLocked(taskId,
-                    MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, options);
+                    MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, options, onTop);
             options.setLaunchTaskId(taskId);
             if (task != null) {
                 return task.getStack();
@@ -2315,13 +2347,10 @@
             }
             final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId);
             if (display != null) {
-                for (int i = display.mStacks.size() - 1; i >= 0; --i) {
-                    stack = (T) display.mStacks.get(i);
-                    if (stack.isCompatible(windowingMode, activityType)) {
-                        return stack;
-                    }
+                stack = display.getOrCreateStack(windowingMode, activityType, onTop);
+                if (stack != null) {
+                    return stack;
                 }
-                // TODO: We should create the stack we want on the display at this point.
             }
         }
 
@@ -2350,18 +2379,6 @@
             display = getDefaultDisplay();
         }
 
-        stack = display.getOrCreateStack(windowingMode, activityType, onTop);
-        if (stack != null) {
-            return stack;
-        }
-
-        // Whatever...return some default for now.
-        if (candidateTask != null && candidateTask.mBounds != null
-                && mService.mSupportsFreeformWindowManagement) {
-            windowingMode = WINDOWING_MODE_FREEFORM;
-        } else {
-            windowingMode = WINDOWING_MODE_FULLSCREEN;
-        }
         return display.getOrCreateStack(windowingMode, activityType, onTop);
     }
 
@@ -2384,8 +2401,8 @@
         }
 
         // Return the topmost valid stack on the display.
-        for (int i = activityDisplay.mStacks.size() - 1; i >= 0; --i) {
-            final ActivityStack stack = activityDisplay.mStacks.get(i);
+        for (int i = activityDisplay.getChildCount() - 1; i >= 0; --i) {
+            final ActivityStack stack = activityDisplay.getChildAt(i);
             if (isValidLaunchStack(stack, displayId, r)) {
                 return stack;
             }
@@ -2423,18 +2440,6 @@
         return false;
     }
 
-    ArrayList<ActivityStack> getStacks() {
-        ArrayList<ActivityStack> allStacks = new ArrayList<>();
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            allStacks.addAll(mActivityDisplays.valueAt(displayNdx).mStacks);
-        }
-        return allStacks;
-    }
-
-    ArrayList<ActivityStack> getStacksOnDefaultDisplay() {
-        return mActivityDisplays.valueAt(DEFAULT_DISPLAY).mStacks;
-    }
-
     /**
      * Get next focusable stack in the system. This will search across displays and stacks
      * in last-focused order for a focusable and visible stack, different from the target stack.
@@ -2449,10 +2454,9 @@
         for (int i = mTmpOrderedDisplayIds.size() - 1; i >= 0; --i) {
             final int displayId = mTmpOrderedDisplayIds.get(i);
             // If a display is registered in WM, it must also be available in AM.
-            @SuppressWarnings("ConstantConditions")
-            final List<ActivityStack> stacks = getActivityDisplayOrCreateLocked(displayId).mStacks;
-            for (int j = stacks.size() - 1; j >= 0; --j) {
-                final ActivityStack stack = stacks.get(j);
+            final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId);
+            for (int j = display.getChildCount() - 1; j >= 0; --j) {
+                final ActivityStack stack = display.getChildAt(j);
                 if (stack != currentFocus && stack.isFocusable()
                         && stack.shouldBeVisible(null)) {
                     return stack;
@@ -2520,7 +2524,7 @@
             return;
         }
 
-        final boolean splitScreenActive = getDefaultDisplay().hasSplitScreenStack();
+        final boolean splitScreenActive = getDefaultDisplay().hasSplitScreenPrimaryStack();
         if (!allowResizeInDockedMode
                 && !stack.getWindowConfiguration().tasksAreFloating() && splitScreenActive) {
             // If the docked stack exists, don't resize non-floating stacks independently of the
@@ -2595,9 +2599,8 @@
                 // We are moving all tasks from the docked stack to the fullscreen stack,
                 // which is dismissing the docked stack, so resize all other stacks to
                 // fullscreen here already so we don't end up with resize trashing.
-                final ArrayList<ActivityStack> displayStacks = toDisplay.mStacks;
-                for (int i = displayStacks.size() - 1; i >= 0; --i) {
-                    final ActivityStack otherStack = displayStacks.get(i);
+                for (int i = toDisplay.getChildCount() - 1; i >= 0; --i) {
+                    final ActivityStack otherStack = toDisplay.getChildAt(i);
                     if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
                         continue;
                     }
@@ -2692,8 +2695,7 @@
             return;
         }
 
-        final ActivityStack stack = getDefaultDisplay().getStack(
-                WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
+        final ActivityStack stack = getDefaultDisplay().getSplitScreenPrimaryStack();
         if (stack == null) {
             Slog.w(TAG, "resizeDockedStackLocked: docked stack not found");
             return;
@@ -2722,10 +2724,10 @@
                 // static stacks need to be adjusted so they don't overlap with the docked stack.
                 // We get the bounds to use from window manager which has been adjusted for any
                 // screen controls and is also the same for all stacks.
-                final ArrayList<ActivityStack> stacks = getStacksOnDefaultDisplay();
+                final ActivityDisplay display = getDefaultDisplay();
                 final Rect otherTaskRect = new Rect();
-                for (int i = stacks.size() - 1; i >= 0; --i) {
-                    final ActivityStack current = stacks.get(i);
+                for (int i = display.getChildCount() - 1; i >= 0; --i) {
+                    final ActivityStack current = display.getChildAt(i);
                     if (current.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
                         continue;
                     }
@@ -2757,8 +2759,7 @@
 
     void resizePinnedStackLocked(Rect pinnedBounds, Rect tempPinnedTaskBounds) {
         // TODO(multi-display): Pinned stack display should be passed in.
-        final PinnedActivityStack stack = getDefaultDisplay().getStack(
-                WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
+        final PinnedActivityStack stack = getDefaultDisplay().getPinnedStack();
         if (stack == null) {
             Slog.w(TAG, "resizePinnedStackLocked: pinned stack not found");
             return;
@@ -2796,12 +2797,7 @@
         }
     }
 
-    private void removeStackInSurfaceTransaction(int stackId) {
-        final ActivityStack stack = getStack(stackId);
-        if (stack == null) {
-            return;
-        }
-
+    private void removeStackInSurfaceTransaction(ActivityStack stack) {
         final ArrayList<TaskRecord> tasks = stack.getAllTasks();
         if (stack.getWindowingMode() == WINDOWING_MODE_PINNED) {
             /**
@@ -2831,12 +2827,12 @@
     }
 
     /**
-     * Removes the stack associated with the given {@param stackId}.  If the {@param stackId} is the
+     * Removes the stack associated with the given {@param stack}. If the {@param stack} is the
      * pinned stack, then its tasks are not explicitly removed when the stack is destroyed, but
      * instead moved back onto the fullscreen stack.
      */
-    void removeStackLocked(int stackId) {
-        mWindowManager.inSurfaceTransaction(() -> removeStackInSurfaceTransaction(stackId));
+    void removeStack(ActivityStack stack) {
+        mWindowManager.inSurfaceTransaction(() -> removeStackInSurfaceTransaction(stack));
     }
 
     /**
@@ -2887,23 +2883,9 @@
         return false;
     }
 
-    void addRecentActivity(ActivityRecord r) {
-        if (r == null) {
-            return;
-        }
-        final TaskRecord task = r.getTask();
-        mRecentTasks.addLocked(task);
-        task.touchActiveTime();
-    }
-
-    void removeTaskFromRecents(TaskRecord task) {
-        mRecentTasks.remove(task);
-        task.removedFromRecents();
-    }
-
     void cleanUpRemovedTaskLocked(TaskRecord tr, boolean killProcess, boolean removeFromRecents) {
         if (removeFromRecents) {
-            removeTaskFromRecents(tr);
+            mRecentTasks.remove(tr);
         }
         ComponentName component = tr.getBaseIntent().getComponent();
         if (component == null) {
@@ -2983,13 +2965,15 @@
     }
 
     /**
-     * Restores a recent task to a stack
+     * Called to restore the state of the task into the stack that it's supposed to go into.
+     *
      * @param task The recent task to be restored.
      * @param aOptions The activity options to use for restoration.
+     * @param onTop If the stack for the task should be the topmost on the display.
      * @return true if the task has been restored successfully.
      */
-    boolean restoreRecentTaskLocked(TaskRecord task, ActivityOptions aOptions) {
-        final ActivityStack stack = getLaunchStack(null, aOptions, task, !ON_TOP);
+    boolean restoreRecentTaskLocked(TaskRecord task, ActivityOptions aOptions, boolean onTop) {
+        final ActivityStack stack = getLaunchStack(null, aOptions, task, onTop);
         final ActivityStack currentStack = task.getStack();
         if (currentStack != null) {
             // Task has already been restored once. See if we need to do anything more
@@ -3002,9 +2986,9 @@
             currentStack.removeTask(task, "restoreRecentTaskLocked", REMOVE_TASK_MODE_MOVING);
         }
 
-        stack.addTask(task, !ON_TOP, "restoreRecentTask");
+        stack.addTask(task, onTop, "restoreRecentTask");
         // TODO: move call for creation here and other place into Stack.addTask()
-        task.createWindowContainer(!ON_TOP, true /* showForAllUsers */);
+        task.createWindowContainer(onTop, true /* showForAllUsers */);
         if (DEBUG_RECENTS) Slog.v(TAG_RECENTS,
                 "Added restored task=" + task + " to stack=" + stack);
         final ArrayList<ActivityRecord> activities = task.mActivities;
@@ -3014,6 +2998,22 @@
         return true;
     }
 
+    @Override
+    public void onRecentTaskAdded(TaskRecord task) {
+        task.touchActiveTime();
+    }
+
+    @Override
+    public void onRecentTaskRemoved(TaskRecord task, boolean wasTrimmed) {
+        if (wasTrimmed) {
+            // Task was trimmed from the recent tasks list -- remove the active task record as well
+            // since the user won't really be able to go back to it
+            removeTaskByIdLocked(task.taskId, false /* killProcess */,
+                    false /* removeFromRecents */);
+        }
+        task.removedFromRecents();
+    }
+
     /**
      * Move stack with all its existing content to specified display.
      * @param stackId Id of stack to move.
@@ -3251,9 +3251,9 @@
         ActivityRecord affinityMatch = null;
         if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r);
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 if (!r.hasCompatibleActivityType(stack)) {
                     if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) "
                             + stack);
@@ -3286,12 +3286,13 @@
     }
 
     ActivityRecord findActivityLocked(Intent intent, ActivityInfo info,
-                                      boolean compareIntentFilters) {
+            boolean compareIntentFilters) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityRecord ar = stacks.get(stackNdx)
-                        .findActivityLocked(intent, info, compareIntentFilters);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
+                final ActivityRecord ar = stack.findActivityLocked(
+                        intent, info, compareIntentFilters);
                 if (ar != null) {
                     return ar;
                 }
@@ -3385,9 +3386,8 @@
             }
 
             // Set the sleeping state of the stacks on the display.
-            final ArrayList<ActivityStack> stacks = display.mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 if (displayShouldSleep) {
                     stack.goToSleepIfPossible(false /* shuttingDown */);
                 } else {
@@ -3449,12 +3449,13 @@
     private boolean putStacksToSleepLocked(boolean allowDelay, boolean shuttingDown) {
         boolean allSleep = true;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 if (allowDelay) {
-                    allSleep &= stacks.get(stackNdx).goToSleepIfPossible(shuttingDown);
+                    allSleep &= stack.goToSleepIfPossible(shuttingDown);
                 } else {
-                    stacks.get(stackNdx).goToSleep();
+                    stack.goToSleep();
                 }
             }
         }
@@ -3479,11 +3480,10 @@
 
     void handleAppCrashLocked(ProcessRecord app) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            int stackNdx = stacks.size() - 1;
-            while (stackNdx >= 0) {
-                stacks.get(stackNdx).handleAppCrashLocked(app);
-                stackNdx--;
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
+                stack.handleAppCrashLocked(app);
             }
         }
     }
@@ -3494,7 +3494,7 @@
         final ActivityStack stack = task.getStack();
 
         r.mLaunchTaskBehind = false;
-        mRecentTasks.addLocked(task);
+        mRecentTasks.add(task);
         mService.mTaskChangeNotificationController.notifyTaskStackChanged();
         r.setVisibility(false);
 
@@ -3516,10 +3516,9 @@
         try {
             // First the front stacks. In case any are not fullscreen and are in front of home.
             for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-                final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-                final int topStackNdx = stacks.size() - 1;
-                for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) {
-                    final ActivityStack stack = stacks.get(stackNdx);
+                final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+                for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                    final ActivityStack stack = display.getChildAt(stackNdx);
                     stack.ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows);
                 }
             }
@@ -3530,10 +3529,9 @@
 
     void addStartingWindowsForVisibleActivities(boolean taskSwitch) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            final int topStackNdx = stacks.size() - 1;
-            for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 stack.addStartingWindowsForVisibleActivities(taskSwitch);
             }
         }
@@ -3549,20 +3547,20 @@
         }
         mTaskLayersChanged = false;
         for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); displayNdx++) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
             int baseLayer = 0;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                baseLayer += stacks.get(stackNdx).rankTaskLayers(baseLayer);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
+                baseLayer += stack.rankTaskLayers(baseLayer);
             }
         }
     }
 
     void clearOtherAppTimeTrackers(AppTimeTracker except) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            final int topStackNdx = stacks.size() - 1;
-            for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 stack.clearOtherAppTimeTrackers(except);
             }
         }
@@ -3570,10 +3568,9 @@
 
     void scheduleDestroyAllActivities(ProcessRecord app, String reason) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            final int numStacks = stacks.size();
-            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 stack.scheduleDestroyActivities(app, reason);
             }
         }
@@ -3625,10 +3622,11 @@
         // let's iterate through the tasks and release the oldest one.
         final int numDisplays = mActivityDisplays.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            final int stackCount = display.getChildCount();
             // Step through all stacks starting from behind, to hit the oldest things first.
-            for (int stackNdx = 0; stackNdx < stacks.size(); stackNdx++) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            for (int stackNdx = 0; stackNdx < stackCount; stackNdx++) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 // Try to release activities in this stack; if we manage to, we are done.
                 if (stack.releaseSomeActivitiesLocked(app, tasks, reason) > 0) {
                     return;
@@ -3640,7 +3638,7 @@
     boolean switchUserLocked(int userId, UserState uss) {
         final int focusStackId = mFocusedStack.getStackId();
         // We dismiss the docked stack whenever we switch users.
-        final ActivityStack dockedStack = getDefaultDisplay().getSplitScreenStack();
+        final ActivityStack dockedStack = getDefaultDisplay().getSplitScreenPrimaryStack();
         if (dockedStack != null) {
             moveTasksToFullscreenStackLocked(dockedStack, mFocusedStack == dockedStack);
         }
@@ -3655,9 +3653,9 @@
 
         mStartingUsers.add(uss);
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 stack.switchUserLocked(userId);
                 TaskRecord task = stack.topTask();
                 if (task != null) {
@@ -3755,9 +3753,9 @@
 
     void validateTopActivitiesLocked() {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 final ActivityRecord r = stack.topRunningActivityLocked();
                 final ActivityState state = r == null ? DESTROYED : r.state;
                 if (isFocusedStack(stack)) {
@@ -3792,7 +3790,7 @@
         pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront);
         for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
             final ActivityDisplay display = mActivityDisplays.valueAt(i);
-            pw.println(prefix + "displayId=" + display.mDisplayId + " mStacks=" + display.mStacks);
+            display.dump(pw, prefix);
         }
         if (!mWaitingForActivityVisible.isEmpty()) {
             pw.print(prefix); pw.println("mWaitingForActivityVisible=");
@@ -3805,8 +3803,7 @@
         mService.mLockTaskController.dump(pw, prefix);
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
-        final long token = proto.start(fieldId);
+    public void writeToProto(ProtoOutputStream proto) {
         super.writeToProto(proto, CONFIGURATION_CONTAINER);
         for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
             ActivityDisplay activityDisplay = mActivityDisplays.valueAt(displayNdx);
@@ -3822,7 +3819,6 @@
         } else {
             proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID);
         }
-        proto.end(token);
     }
 
     /**
@@ -3851,9 +3847,9 @@
             ArrayList<ActivityRecord> activities = new ArrayList<>();
             int numDisplays = mActivityDisplays.size();
             for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-                for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                    ActivityStack stack = stacks.get(stackNdx);
+                final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+                for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                    final ActivityStack stack = display.getChildAt(stackNdx);
                     if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) {
                         activities.addAll(stack.getDumpActivitiesLocked(name));
                     }
@@ -3886,13 +3882,13 @@
             ActivityDisplay activityDisplay = mActivityDisplays.valueAt(displayNdx);
             pw.print("Display #"); pw.print(activityDisplay.mDisplayId);
                     pw.println(" (activities from top to bottom):");
-            ArrayList<ActivityStack> stacks = activityDisplay.mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 pw.println();
                 pw.println("  Stack #" + stack.mStackId
-                        + ": type=" + activityTypeToString(getActivityType())
-                        + " mode=" + windowingModeToString(getWindowingMode()));
+                        + ": type=" + activityTypeToString(stack.getActivityType())
+                        + " mode=" + windowingModeToString(stack.getWindowingMode()));
                 pw.println("  mFullscreen=" + stack.mFullscreen);
                 pw.println("  isSleeping=" + stack.shouldSleepActivities());
                 pw.println("  mBounds=" + stack.mBounds);
@@ -4136,30 +4132,29 @@
         }
 
         synchronized (mService) {
-            ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
-            if (activityDisplay != null) {
-                final boolean destroyContentOnRemoval
-                        = activityDisplay.shouldDestroyContentOnRemove();
-                final ArrayList<ActivityStack> stacks = activityDisplay.mStacks;
-                while (!stacks.isEmpty()) {
-                    final ActivityStack stack = stacks.get(0);
-                    if (destroyContentOnRemoval) {
-                        moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY,
-                                false /* onTop */);
-                        stack.finishAllActivitiesLocked(true /* immediately */);
-                    } else {
-                        // Moving all tasks to fullscreen stack, because it's guaranteed to be
-                        // a valid launch stack for all activities. This way the task history from
-                        // external display will be preserved on primary after move.
-                        moveTasksToFullscreenStackLocked(stack, true /* onTop */);
-                    }
-                }
-
-                releaseSleepTokens(activityDisplay);
-
-                mActivityDisplays.remove(displayId);
-                mWindowManager.onDisplayRemoved(displayId);
+            final ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
+            if (activityDisplay == null) {
+                return;
             }
+            final boolean destroyContentOnRemoval
+                    = activityDisplay.shouldDestroyContentOnRemove();
+            while (activityDisplay.getChildCount() > 0) {
+                final ActivityStack stack = activityDisplay.getChildAt(0);
+                if (destroyContentOnRemoval) {
+                    moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY, false /* onTop */);
+                    stack.finishAllActivitiesLocked(true /* immediately */);
+                } else {
+                    // Moving all tasks to fullscreen stack, because it's guaranteed to be
+                    // a valid launch stack for all activities. This way the task history from
+                    // external display will be preserved on primary after move.
+                    moveTasksToFullscreenStackLocked(stack, true /* onTop */);
+                }
+            }
+
+            releaseSleepTokens(activityDisplay);
+
+            mActivityDisplays.remove(displayId);
+            mWindowManager.onDisplayRemoved(displayId);
         }
     }
 
@@ -4231,7 +4226,7 @@
         info.userId = stack.mCurrentUser;
         info.visible = stack.shouldBeVisible(null);
         // A stack might be not attached to a display.
-        info.position = display != null ? display.mStacks.indexOf(stack) : 0;
+        info.position = display != null ? display.getIndexOf(stack) : 0;
         info.configuration.setTo(stack.getConfiguration());
 
         ArrayList<TaskRecord> tasks = stack.getAllTasks();
@@ -4277,25 +4272,25 @@
     ArrayList<StackInfo> getAllStackInfosLocked() {
         ArrayList<StackInfo> list = new ArrayList<>();
         for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int ndx = stacks.size() - 1; ndx >= 0; --ndx) {
-                list.add(getStackInfo(stacks.get(ndx)));
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
+                list.add(getStackInfo(stack));
             }
         }
         return list;
     }
 
     void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredWindowingMode,
-            int preferredDisplayId, int actualStackId) {
+            int preferredDisplayId, ActivityStack actualStack) {
         handleNonResizableTaskIfNeeded(task, preferredWindowingMode, preferredDisplayId,
-                actualStackId, false /* forceNonResizable */);
+                actualStack, false /* forceNonResizable */);
     }
 
     void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredWindowingMode,
-            int preferredDisplayId, int actualStackId, boolean forceNonResizable) {
+            int preferredDisplayId, ActivityStack actualStack, boolean forceNonResizable) {
         final boolean isSecondaryDisplayPreferred =
                 (preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY);
-        final ActivityStack actualStack = getStack(actualStackId);
         final boolean inSplitScreenMode = actualStack != null
                 && actualStack.inSplitScreenWindowingMode();
         if (((!inSplitScreenMode && preferredWindowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
@@ -4342,10 +4337,9 @@
             // Dismiss docked stack. If task appeared to be in docked stack but is not resizable -
             // we need to move it to top of fullscreen stack, otherwise it will be covered.
 
-            final ActivityStack dockedStack = task.getStack().getDisplay().getSplitScreenStack();
+            final ActivityStack dockedStack = task.getStack().getDisplay().getSplitScreenPrimaryStack();
             if (dockedStack != null) {
-                moveTasksToFullscreenStackLocked(dockedStack,
-                        actualStackId == dockedStack.getStackId());
+                moveTasksToFullscreenStackLocked(dockedStack, actualStack == dockedStack);
             }
         } else if (topActivity != null && topActivity.isNonResizableOrForcedResizable()
                 && !topActivity.noDisplay) {
@@ -4557,14 +4551,13 @@
         if (display == null) {
             return null;
         }
-        final ArrayList<ActivityStack> stacks = display.mStacks;
-        for (int i = stacks.size() - 1; i >= 0; i--) {
-            if (stacks.get(i) == stack && i > 0) {
-                return stacks.get(i - 1);
+        for (int i = display.getChildCount() - 1; i >= 0; i--) {
+            if (display.getChildAt(i) == stack && i > 0) {
+                return display.getChildAt(i - 1);
             }
         }
         throw new IllegalStateException("Failed to find a stack behind stack=" + stack
-                + " in=" + stacks);
+                + " in=" + display);
     }
 
     /**
@@ -4577,7 +4570,7 @@
         task.setTaskDockedResizing(true);
     }
 
-    final int startActivityFromRecentsInner(int taskId, Bundle bOptions) {
+    int startActivityFromRecents(int taskId, Bundle bOptions) {
         final TaskRecord task;
         final int callingUid;
         final String callingPackage;
@@ -4592,7 +4585,7 @@
             windowingMode = activityOptions.getLaunchWindowingMode();
         }
         if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
-            throw new IllegalArgumentException("startActivityFromRecentsInner: Task "
+            throw new IllegalArgumentException("startActivityFromRecents: Task "
                     + taskId + " can't be launch in the home/recents stack.");
         }
 
@@ -4610,21 +4603,12 @@
             }
 
             task = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE,
-                    activityOptions);
+                    activityOptions, ON_TOP);
             if (task == null) {
                 continueUpdateBounds(ACTIVITY_TYPE_RECENTS);
                 mWindowManager.executeAppTransition();
                 throw new IllegalArgumentException(
-                        "startActivityFromRecentsInner: Task " + taskId + " not found.");
-            }
-
-            // Since we don't have an actual source record here, we assume that the currently
-            // focused activity was the source.
-            final ActivityStack stack = getLaunchStack(null, activityOptions, task, ON_TOP);
-
-            if (stack != null && task.getStack() != stack) {
-                task.reparent(stack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
-                        "startActivityFromRecents");
+                        "startActivityFromRecents: Task " + taskId + " not found.");
             }
 
             // If the user must confirm credentials (e.g. when first launching a work app and the
@@ -4677,8 +4661,8 @@
         for (int i = mActivityDisplays.size() - 1; i >= 0; i--) {
             final ActivityDisplay display = mActivityDisplays.valueAt(i);
             // Traverse all stacks on a display.
-            for (int j = display.mStacks.size() - 1; j >= 0; j--) {
-                final ActivityStack stack = display.mStacks.get(j);
+            for (int j = display.getChildCount() - 1; j >= 0; --j) {
+                final ActivityStack stack = display.getChildAt(j);
                 // Get top activity from a visible stack and add it to the list.
                 if (stack.shouldBeVisible(null /* starting */)) {
                     final ActivityRecord top = stack.topActivity();
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 8300083..6f74d85 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -29,7 +29,6 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
@@ -116,7 +115,6 @@
 import com.android.internal.app.IVoiceInteractor;
 import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch;
 import com.android.server.pm.InstantAppResolver;
-import com.android.server.wm.WindowManagerService;
 
 import java.io.PrintWriter;
 import java.text.DateFormat;
@@ -135,11 +133,11 @@
     private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
     private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
+    private static final int INVALID_LAUNCH_MODE = -1;
 
     private final ActivityManagerService mService;
     private final ActivityStackSupervisor mSupervisor;
     private final ActivityStartInterceptor mInterceptor;
-    private WindowManagerService mWindowManager;
 
     final ArrayList<PendingActivityLaunch> mPendingActivityLaunches = new ArrayList<>();
 
@@ -149,9 +147,7 @@
     private int mCallingUid;
     private ActivityOptions mOptions;
 
-    private boolean mLaunchSingleTop;
-    private boolean mLaunchSingleInstance;
-    private boolean mLaunchSingleTask;
+    private int mLaunchMode;
     private boolean mLaunchTaskBehind;
     private int mLaunchFlags;
 
@@ -161,6 +157,7 @@
     private boolean mDoResume;
     private int mStartFlags;
     private ActivityRecord mSourceRecord;
+
     // The display to launch the activity onto, barring any strong reason to do otherwise.
     private int mPreferredDisplayId;
 
@@ -190,8 +187,6 @@
     private IVoiceInteractionSession mVoiceSession;
     private IVoiceInteractor mVoiceInteractor;
 
-    private boolean mUsingVr2dDisplay;
-
     // Last home activity record we attempted to start
     private final ActivityRecord[] mLastHomeActivityStartRecord = new ActivityRecord[1];
     // The result of the last home activity we attempted to start.
@@ -211,11 +206,9 @@
         mCallingUid = -1;
         mOptions = null;
 
-        mLaunchSingleTop = false;
-        mLaunchSingleInstance = false;
-        mLaunchSingleTask = false;
         mLaunchTaskBehind = false;
         mLaunchFlags = 0;
+        mLaunchMode = INVALID_LAUNCH_MODE;
 
         mLaunchBounds = null;
 
@@ -243,16 +236,13 @@
         mVoiceSession = null;
         mVoiceInteractor = null;
 
-        mUsingVr2dDisplay = false;
-
         mIntentDelivered = false;
     }
 
-    ActivityStarter(ActivityManagerService service, ActivityStackSupervisor supervisor) {
+    ActivityStarter(ActivityManagerService service) {
         mService = service;
-        mSupervisor = supervisor;
+        mSupervisor = mService.mStackSupervisor;
         mInterceptor = new ActivityStartInterceptor(mService, mSupervisor);
-        mUsingVr2dDisplay = false;
     }
 
     int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
@@ -618,15 +608,14 @@
         }
 
         if (startedActivityStack.inSplitScreenPrimaryWindowingMode()) {
-            final ActivityStack homeStack = mSupervisor.getDefaultDisplay().getStack(
-                            WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME);
+            final ActivityStack homeStack = mSupervisor.mHomeStack;
             final boolean homeStackVisible = homeStack != null && homeStack.isVisible();
             if (homeStackVisible) {
                 // We launch an activity while being in home stack, which means either launcher or
                 // recents into docked stack. We don't want the launched activity to be alone in a
                 // docked stack, so we want to immediately launch recents too.
                 if (DEBUG_RECENTS) Slog.d(TAG, "Scheduling recents launch.");
-                mWindowManager.showRecentApps(true /* fromHome */);
+                mService.mWindowManager.showRecentApps(true /* fromHome */);
             }
             return;
         }
@@ -1061,7 +1050,7 @@
             // operations.
             if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                     || isDocumentLaunchesIntoExisting(mLaunchFlags)
-                    || mLaunchSingleInstance || mLaunchSingleTask) {
+                    || isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
                 final TaskRecord task = reusedActivity.getTask();
 
                 // In this situation we want to remove all activities from the task up to the one
@@ -1144,7 +1133,7 @@
                 && top.userId == mStartActivity.userId
                 && top.app != null && top.app.thread != null
                 && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
-                || mLaunchSingleTop || mLaunchSingleTask);
+                || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK));
         if (dontStart) {
             // For paranoia, make sure we have correctly resumed the top activity.
             topStack.mLastPausedActivity = null;
@@ -1163,7 +1152,7 @@
             // Don't use mStartActivity.task to show the toast. We're not starting a new activity
             // but reusing 'top'. Fields in mStartActivity may not be fully initialized.
             mSupervisor.handleNonResizableTaskIfNeeded(top.getTask(), preferredWindowingMode,
-                    preferredLaunchDisplayId, topStack.mStackId);
+                    preferredLaunchDisplayId, topStack);
 
             return START_DELIVERED_TO_TOP;
         }
@@ -1226,7 +1215,7 @@
                 mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                 // Go ahead and tell window manager to execute app transition for this activity
                 // since the app transition will not be triggered through the resume channel.
-                mWindowManager.executeAppTransition();
+                mService.mWindowManager.executeAppTransition();
             } else {
                 // If the target stack was not previously focusable (previous top running activity
                 // on that stack was not visible) then any prior calls to move the stack to the
@@ -1239,13 +1228,13 @@
                 mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                         mOptions);
             }
-        } else {
-            mSupervisor.addRecentActivity(mStartActivity);
+        } else if (mStartActivity != null) {
+            mSupervisor.mRecentTasks.add(mStartActivity.getTask());
         }
         mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
 
         mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredWindowingMode,
-                preferredLaunchDisplayId, mTargetStack.mStackId);
+                preferredLaunchDisplayId, mTargetStack);
 
         return START_SUCCESS;
     }
@@ -1267,13 +1256,13 @@
 
         mLaunchBounds = getOverrideBounds(r, options, inTask);
 
-        mLaunchSingleTop = r.launchMode == LAUNCH_SINGLE_TOP;
-        mLaunchSingleInstance = r.launchMode == LAUNCH_SINGLE_INSTANCE;
-        mLaunchSingleTask = r.launchMode == LAUNCH_SINGLE_TASK;
+        mLaunchMode = r.launchMode;
+
         mLaunchFlags = adjustLaunchFlagsToDocumentMode(
-                r, mLaunchSingleInstance, mLaunchSingleTask, mIntent.getFlags());
+                r, LAUNCH_SINGLE_INSTANCE == mLaunchMode,
+                LAUNCH_SINGLE_TASK == mLaunchMode, mIntent.getFlags());
         mLaunchTaskBehind = r.mLaunchTaskBehind
-                && !mLaunchSingleTask && !mLaunchSingleInstance
+                && !isLaunchModeOneOf(LAUNCH_SINGLE_TASK, LAUNCH_SINGLE_INSTANCE)
                 && (mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
 
         sendNewTaskResultRequestIfNeeded();
@@ -1383,7 +1372,7 @@
 
             // If this task is empty, then we are adding the first activity -- it
             // determines the root, and must be launching as a NEW_TASK.
-            if (mLaunchSingleInstance || mLaunchSingleTask) {
+            if (isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
                 if (!baseIntent.getComponent().equals(mStartActivity.intent.getComponent())) {
                     ActivityOptions.abort(mOptions);
                     throw new IllegalArgumentException("Trying to launch singleInstance/Task "
@@ -1445,7 +1434,7 @@
                 // instance...  this new activity it is starting must go on its
                 // own task.
                 mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
-            } else if (mLaunchSingleInstance || mLaunchSingleTask) {
+            } else if (isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
                 // The activity being started is a single instance...  it always
                 // gets launched into its own task.
                 mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
@@ -1496,7 +1485,7 @@
         // launch this as a new task behind the current one.
         boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
                 (mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
-                || mLaunchSingleInstance || mLaunchSingleTask;
+                || isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK);
         // If bring to front is requested, and no result is requested and we have not been given
         // an explicit task to launch in to, and we can find a task that was started with this
         // same component, then instead of launching bring that one to the front.
@@ -1506,7 +1495,7 @@
             final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId());
             intentActivity = task != null ? task.getTopActivity() : null;
         } else if (putIntoExistingTask) {
-            if (mLaunchSingleInstance) {
+            if (LAUNCH_SINGLE_INSTANCE == mLaunchMode) {
                 // There can be one and only one instance of single instance activity in the
                 // history, and it is always in its own unique task, so we do a special search.
                intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info,
@@ -1515,7 +1504,7 @@
                 // For the launch adjacent case we only want to put the activity in an existing
                 // task if the activity already exists in the history.
                 intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info,
-                        !mLaunchSingleTask);
+                        !(LAUNCH_SINGLE_TASK == mLaunchMode));
             } else {
                 // Otherwise find the best task to put the activity in.
                 intentActivity = mSupervisor.findTaskLocked(mStartActivity, mPreferredDisplayId);
@@ -1544,7 +1533,6 @@
             if (DEBUG_STACK) {
                 Slog.d(TAG, "getSourceDisplayId :" + displayId);
             }
-            mUsingVr2dDisplay = true;
             return displayId;
         }
 
@@ -1666,7 +1654,7 @@
         }
 
         mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.getTask(),
-                WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY, mTargetStack.mStackId);
+                WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY, mTargetStack);
 
         // If the caller has requested that the target task be reset, then do so.
         if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
@@ -1718,7 +1706,7 @@
             // mTaskToReturnTo values and we don't want to overwrite them accidentally.
             mMovedOtherTask = true;
         } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
-                || mLaunchSingleInstance || mLaunchSingleTask) {
+                || isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
             ActivityRecord top = intentActivity.getTask().performClearTaskLocked(mStartActivity,
                     mLaunchFlags);
             if (top == null) {
@@ -1747,7 +1735,8 @@
             // so we take that as a request to bring the task to the foreground. If the top
             // activity in the task is the root activity, deliver this new intent to it if it
             // desires.
-            if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop)
+            if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
+                        || LAUNCH_SINGLE_TOP == mLaunchMode)
                     && intentActivity.realActivity.equals(mStartActivity.realActivity)) {
                 if (intentActivity.frontOfTask) {
                     intentActivity.getTask().setIntent(mStartActivity);
@@ -1951,7 +1940,7 @@
         if (top != null && top.realActivity.equals(mStartActivity.realActivity)
                 && top.userId == mStartActivity.userId) {
             if ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
-                    || mLaunchSingleTop || mLaunchSingleTask) {
+                    || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK)) {
                 mTargetStack.moveTaskToFrontLocked(mInTask, mNoAnimation, mOptions,
                         mStartActivity.appTimeTracker, "inTaskToFront");
                 if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
@@ -2114,10 +2103,9 @@
         }
         if (stack == null) {
             // We first try to put the task in the first dynamic stack on home display.
-            final ArrayList<ActivityStack> homeDisplayStacks =
-                    mSupervisor.getStacksOnDefaultDisplay();
-            for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                stack = homeDisplayStacks.get(stackNdx);
+            final ActivityDisplay display = mSupervisor.getDefaultDisplay();
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                stack = display.getChildAt(stackNdx);
                 if (!stack.isOnHomeDisplay()) {
                     if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
                             "computeStackFocus: Setting focused stack=" + stack);
@@ -2175,7 +2163,8 @@
             return mReuseTask.getStack();
         }
 
-        final int vrDisplayId = mUsingVr2dDisplay ? mPreferredDisplayId : INVALID_DISPLAY;
+        final int vrDisplayId = mPreferredDisplayId == mService.mVr2dDisplayId
+                ? mPreferredDisplayId : INVALID_DISPLAY;
         final ActivityStack launchStack = mSupervisor.getLaunchStack(r, aOptions, task, ON_TOP,
                 vrDisplayId);
 
@@ -2213,8 +2202,8 @@
                 // If the parent is not in the docked stack, we check if there is docked window
                 // and if yes, we will launch into that stack. If not, we just put the new
                 // activity into parent's stack, because we can't find a better place.
-                final ActivityStack dockedStack = mSupervisor.getDefaultDisplay().getStack(
-                                WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
+                final ActivityStack dockedStack =
+                        mSupervisor.getDefaultDisplay().getSplitScreenPrimaryStack();
                 if (dockedStack != null && !dockedStack.shouldBeVisible(r)) {
                     // There is a docked stack, but it isn't visible, so we can't launch into that.
                     return null;
@@ -2234,8 +2223,8 @@
         return newBounds;
     }
 
-    void setWindowManager(WindowManagerService wm) {
-        mWindowManager = wm;
+    private boolean isLaunchModeOneOf(int mode1, int mode2) {
+        return mode1 == mLaunchMode || mode2 == mLaunchMode;
     }
 
     static boolean isDocumentLaunchesIntoExisting(int flags) {
@@ -2316,11 +2305,11 @@
         }
         pw.print(prefix);
         pw.print("mLaunchSingleTop=");
-        pw.print(mLaunchSingleTop);
+        pw.print(LAUNCH_SINGLE_TOP == mLaunchMode);
         pw.print(" mLaunchSingleInstance=");
-        pw.print(mLaunchSingleInstance);
+        pw.print(LAUNCH_SINGLE_INSTANCE == mLaunchMode);
         pw.print(" mLaunchSingleTask=");
-        pw.println(mLaunchSingleTask);
+        pw.println(LAUNCH_SINGLE_TASK == mLaunchMode);
         pw.print(prefix);
         pw.print("mLaunchFlags=0x");
         pw.print(Integer.toHexString(mLaunchFlags));
diff --git a/services/core/java/com/android/server/am/AppTaskImpl.java b/services/core/java/com/android/server/am/AppTaskImpl.java
new file mode 100644
index 0000000..d42a3b9
--- /dev/null
+++ b/services/core/java/com/android/server/am/AppTaskImpl.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
+
+import android.app.ActivityManager;
+import android.app.IAppTask;
+import android.app.IApplicationThread;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.UserHandle;
+
+/**
+ * An implementation of IAppTask, that allows an app to manage its own tasks via
+ * {@link android.app.ActivityManager.AppTask}.  We keep track of the callingUid to ensure that
+ * only the process that calls getAppTasks() can call the AppTask methods.
+ */
+class AppTaskImpl extends IAppTask.Stub {
+    private ActivityManagerService mService;
+
+    private int mTaskId;
+    private int mCallingUid;
+
+    public AppTaskImpl(ActivityManagerService service, int taskId, int callingUid) {
+        mService = service;
+        mTaskId = taskId;
+        mCallingUid = callingUid;
+    }
+
+    private void checkCaller() {
+        if (mCallingUid != Binder.getCallingUid()) {
+            throw new SecurityException("Caller " + mCallingUid
+                    + " does not match caller of getAppTasks(): " + Binder.getCallingUid());
+        }
+    }
+
+    @Override
+    public void finishAndRemoveTask() {
+        checkCaller();
+
+        synchronized (mService) {
+            long origId = Binder.clearCallingIdentity();
+            try {
+                // We remove the task from recents to preserve backwards
+                if (!mService.mStackSupervisor.removeTaskByIdLocked(mTaskId, false,
+                        REMOVE_FROM_RECENTS)) {
+                    throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
+        }
+    }
+
+    @Override
+    public ActivityManager.RecentTaskInfo getTaskInfo() {
+        checkCaller();
+
+        synchronized (mService) {
+            long origId = Binder.clearCallingIdentity();
+            try {
+                TaskRecord tr = mService.mStackSupervisor.anyTaskForIdLocked(mTaskId);
+                if (tr == null) {
+                    throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
+                }
+                return RecentTasks.createRecentTaskInfo(tr);
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
+        }
+    }
+
+    @Override
+    public void moveToFront() {
+        checkCaller();
+        // Will bring task to front if it already has a root activity.
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                mService.mStackSupervisor.startActivityFromRecents(mTaskId, null);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public int startActivity(IBinder whoThread, String callingPackage,
+            Intent intent, String resolvedType, Bundle bOptions) {
+        checkCaller();
+
+        int callingUser = UserHandle.getCallingUserId();
+        TaskRecord tr;
+        IApplicationThread appThread;
+        synchronized (mService) {
+            tr = mService.mStackSupervisor.anyTaskForIdLocked(mTaskId);
+            if (tr == null) {
+                throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
+            }
+            appThread = IApplicationThread.Stub.asInterface(whoThread);
+            if (appThread == null) {
+                throw new IllegalArgumentException("Bad app thread " + appThread);
+            }
+        }
+        return mService.mActivityStarter.startActivityMayWait(appThread, -1, callingPackage,
+                intent, resolvedType, null, null, null, null, 0, 0, null, null,
+                null, bOptions, false, callingUser, tr, "AppTaskImpl");
+    }
+
+    @Override
+    public void setExcludeFromRecents(boolean exclude) {
+        checkCaller();
+
+        synchronized (mService) {
+            long origId = Binder.clearCallingIdentity();
+            try {
+                TaskRecord tr = mService.mStackSupervisor.anyTaskForIdLocked(mTaskId);
+                if (tr == null) {
+                    throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
+                }
+                Intent intent = tr.getBaseIntent();
+                if (exclude) {
+                    intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                } else {
+                    intent.setFlags(intent.getFlags()
+                            & ~Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 7c9cd00..68ed9ae 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -297,26 +297,12 @@
     void noteProcessStart(String name, int uid) {
         synchronized (mStats) {
             mStats.noteProcessStartLocked(name, uid);
-
-            // TODO: remove this once we figure out properly where and how
-            // PROCESS_EVENT = 1112
-            // KEY_STATE = 1
-            // KEY_PACKAGE_NAME: 1002
-            // KEY_UID: 2
-            StatsLog.writeArray(1112, 1, 1, 1002, name, 2, uid);
         }
     }
 
     void noteProcessCrash(String name, int uid) {
         synchronized (mStats) {
             mStats.noteProcessCrashLocked(name, uid);
-
-            // TODO: remove this once we figure out properly where and how
-            // PROCESS_EVENT = 1112
-            // KEY_STATE = 1
-            // KEY_PACKAGE_NAME: 1002
-            // KEY_UID: 2
-            StatsLog.writeArray(1112, 1, 2, 1002, name, 2, uid);
         }
     }
 
@@ -334,6 +320,9 @@
 
     void noteUidProcessState(int uid, int state) {
         synchronized (mStats) {
+            // TODO: remove this once we figure out properly where and how
+            StatsLog.write(StatsLog.PROCESS_STATE_CHANGED, uid, state);
+
             mStats.noteUidProcessStateLocked(uid, state);
         }
     }
@@ -548,12 +537,10 @@
         enforceCallingPermission();
         if (DBG) Slog.d(TAG, "begin noteScreenState");
         synchronized (mStats) {
-            mStats.noteScreenStateLocked(state);
             // TODO: remove this once we figure out properly where and how
-            // SCREEN_EVENT = 2
-            // KEY_STATE: 1
-            // State value: state. We can change this to our own def later.
-            StatsLog.writeArray(2, 1, state);
+            StatsLog.write(StatsLog.SCREEN_STATE_CHANGED, state);
+
+            mStats.noteScreenStateLocked(state);
         }
         if (DBG) Slog.d(TAG, "end noteScreenState");
     }
diff --git a/services/core/java/com/android/server/am/BroadcastFilter.java b/services/core/java/com/android/server/am/BroadcastFilter.java
index f96b06f..7ff227f 100644
--- a/services/core/java/com/android/server/am/BroadcastFilter.java
+++ b/services/core/java/com/android/server/am/BroadcastFilter.java
@@ -19,6 +19,9 @@
 import android.content.IntentFilter;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.server.am.proto.BroadcastFilterProto;
 
 import java.io.PrintWriter;
 
@@ -44,27 +47,38 @@
         instantApp = _instantApp;
         visibleToInstantApp = _visibleToInstantApp;
     }
-    
+
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        long token = proto.start(fieldId);
+        super.writeToProto(proto, BroadcastFilterProto.INTENT_FILTER);
+        if (requiredPermission != null) {
+            proto.write(BroadcastFilterProto.REQUIRED_PERMISSION, requiredPermission);
+        }
+        proto.write(BroadcastFilterProto.HEX_HASH, Integer.toHexString(System.identityHashCode(this)));
+        proto.write(BroadcastFilterProto.OWNING_USER_ID, owningUserId);
+        proto.end(token);
+    }
+
     public void dump(PrintWriter pw, String prefix) {
         dumpInReceiverList(pw, new PrintWriterPrinter(pw), prefix);
         receiverList.dumpLocal(pw, prefix);
     }
-    
+
     public void dumpBrief(PrintWriter pw, String prefix) {
         dumpBroadcastFilterState(pw, prefix);
     }
-    
+
     public void dumpInReceiverList(PrintWriter pw, Printer pr, String prefix) {
         super.dump(pr, prefix);
         dumpBroadcastFilterState(pw, prefix);
     }
-    
+
     void dumpBroadcastFilterState(PrintWriter pw, String prefix) {
         if (requiredPermission != null) {
             pw.print(prefix); pw.print("requiredPermission="); pw.println(requiredPermission);
         }
     }
-    
+
     public String toString() {
         StringBuilder sb = new StringBuilder();
         sb.append("BroadcastFilter{");
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index d835454..c62cc38 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -51,9 +51,12 @@
 import android.util.EventLog;
 import android.util.Slog;
 import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
 
 import static com.android.server.am.ActivityManagerDebugConfig.*;
 
+import com.android.server.am.proto.BroadcastQueueProto;
+
 /**
  * BROADCASTS
  *
@@ -1585,6 +1588,55 @@
                 && (mPendingBroadcast == null);
     }
 
+    void writeToProto(ProtoOutputStream proto, long fieldId) {
+        long token = proto.start(fieldId);
+        proto.write(BroadcastQueueProto.QUEUE_NAME, mQueueName);
+        int N;
+        N = mParallelBroadcasts.size();
+        for (int i = N - 1; i >= 0; i--) {
+            mParallelBroadcasts.get(i).writeToProto(proto, BroadcastQueueProto.PARALLEL_BROADCASTS);
+        }
+        N = mOrderedBroadcasts.size();
+        for (int i = N - 1; i >= 0; i--) {
+            mOrderedBroadcasts.get(i).writeToProto(proto, BroadcastQueueProto.ORDERED_BROADCASTS);
+        }
+        if (mPendingBroadcast != null) {
+            mPendingBroadcast.writeToProto(proto, BroadcastQueueProto.PENDING_BROADCAST);
+        }
+
+        int lastIndex = mHistoryNext;
+        int ringIndex = lastIndex;
+        do {
+            // increasing index = more recent entry, and we want to print the most
+            // recent first and work backwards, so we roll through the ring backwards.
+            ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_HISTORY);
+            BroadcastRecord r = mBroadcastHistory[ringIndex];
+            if (r != null) {
+                r.writeToProto(proto, BroadcastQueueProto.HISTORICAL_BROADCASTS);
+            }
+        } while (ringIndex != lastIndex);
+
+        lastIndex = ringIndex = mSummaryHistoryNext;
+        do {
+            ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_SUMMARY_HISTORY);
+            Intent intent = mBroadcastSummaryHistory[ringIndex];
+            if (intent == null) {
+                continue;
+            }
+            long summaryToken = proto.start(BroadcastQueueProto.HISTORICAL_BROADCASTS_SUMMARY);
+            intent.writeToProto(proto, BroadcastQueueProto.BroadcastSummary.INTENT,
+                    false, true, true, false);
+            proto.write(BroadcastQueueProto.BroadcastSummary.ENQUEUE_CLOCK_TIME_MS,
+                    mSummaryHistoryEnqueueTime[ringIndex]);
+            proto.write(BroadcastQueueProto.BroadcastSummary.DISPATCH_CLOCK_TIME_MS,
+                    mSummaryHistoryDispatchTime[ringIndex]);
+            proto.write(BroadcastQueueProto.BroadcastSummary.FINISH_CLOCK_TIME_MS,
+                    mSummaryHistoryFinishTime[ringIndex]);
+            proto.end(summaryToken);
+        } while (ringIndex != lastIndex);
+        proto.end(token);
+    }
+
     final boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, String dumpPackage, boolean needSep) {
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 6bc0744..5b3b2a8 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -30,6 +30,9 @@
 import android.os.UserHandle;
 import android.util.PrintWriterPrinter;
 import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.server.am.proto.BroadcastRecordProto;
 
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
@@ -331,9 +334,17 @@
         return didSomething;
     }
 
+    @Override
     public String toString() {
         return "BroadcastRecord{"
             + Integer.toHexString(System.identityHashCode(this))
             + " u" + userId + " " + intent.getAction() + "}";
     }
+
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        long token = proto.start(fieldId);
+        proto.write(BroadcastRecordProto.USER_ID, userId);
+        proto.write(BroadcastRecordProto.INTENT_ACTION, intent.getAction());
+        proto.end(token);
+    }
 }
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index ba541e6..c3fed17 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -46,7 +46,6 @@
 import com.android.server.wm.WindowManagerService;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
 
 /**
  * Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are
@@ -237,9 +236,9 @@
         final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity;
         mOccluded = false;
         mDismissingKeyguardActivity = null;
-        final ArrayList<ActivityStack> stacks = mStackSupervisor.getStacksOnDefaultDisplay();
-        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = stacks.get(stackNdx);
+        final ActivityDisplay display = mStackSupervisor.getDefaultDisplay();
+        for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = display.getChildAt(stackNdx);
 
             // Only the focused stack top activity may control occluded state
             if (mStackSupervisor.isFocusedStack(stack)) {
@@ -341,7 +340,7 @@
             // show on top of the lock screen. In this can we want to dismiss the docked
             // stack since it will be complicated/risky to try to put the activity on top
             // of the lock screen in the right fullscreen configuration.
-            final ActivityStack stack = mStackSupervisor.getDefaultDisplay().getSplitScreenStack();
+            final ActivityStack stack = mStackSupervisor.getDefaultDisplay().getSplitScreenPrimaryStack();
             if (stack == null) {
                 return;
             }
diff --git a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
index 2c161cd..0dc73e9 100644
--- a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
+++ b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
@@ -64,23 +64,12 @@
     private static final int SHIFT_POLICY_HORIZONTAL_RIGHT = 2;
     private static final int SHIFT_POLICY_HORIZONTAL_LEFT = 3;
 
-    private boolean mDefaultStartBoundsConfigurationSet = false;
     private final Rect mAvailableRect = new Rect();
     private final Rect mTmpProposal = new Rect();
     private final Rect mTmpOriginal = new Rect();
 
-    private int mDefaultFreeformStartX;
-    private int mDefaultFreeformStartY;
-    private int mDefaultFreeformWidth;
-    private int mDefaultFreeformHeight;
-    private int mDefaultFreeformStepHorizontal;
-    private int mDefaultFreeformStepVertical;
     private final Point mDisplaySize = new Point();
 
-    void setDisplaySize(Point size) {
-        mDisplaySize.set(size.x, size.y);
-    }
-
     /**
      * Tries to set task's bound in a way that it won't collide with any other task. By colliding
      * we mean that two tasks have left-top corner very close to each other, so one might get
@@ -93,52 +82,47 @@
      */
     void updateDefaultBounds(TaskRecord task, ArrayList<TaskRecord> tasks,
             @Nullable ActivityInfo.WindowLayout windowLayout) {
-        if (!mDefaultStartBoundsConfigurationSet) {
-            return;
-        }
+        updateAvailableRect(task, mAvailableRect);
+
         if (windowLayout == null) {
-            positionCenter(task, tasks, mDefaultFreeformWidth, mDefaultFreeformHeight);
+            positionCenter(task, tasks, mAvailableRect, getFreeformWidth(mAvailableRect),
+                    getFreeformHeight(mAvailableRect));
             return;
         }
-        int width = getFinalWidth(windowLayout);
-        int height = getFinalHeight(windowLayout);
+        int width = getFinalWidth(windowLayout, mAvailableRect);
+        int height = getFinalHeight(windowLayout, mAvailableRect);
         int verticalGravity = windowLayout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
         int horizontalGravity = windowLayout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
         if (verticalGravity == Gravity.TOP) {
             if (horizontalGravity == Gravity.RIGHT) {
-                positionTopRight(task, tasks, width, height);
+                positionTopRight(task, tasks, mAvailableRect, width, height);
             } else {
-                positionTopLeft(task, tasks, width, height);
+                positionTopLeft(task, tasks, mAvailableRect, width, height);
             }
         } else if (verticalGravity == Gravity.BOTTOM) {
             if (horizontalGravity == Gravity.RIGHT) {
-                positionBottomRight(task, tasks, width, height);
+                positionBottomRight(task, tasks, mAvailableRect, width, height);
             } else {
-                positionBottomLeft(task, tasks, width, height);
+                positionBottomLeft(task, tasks, mAvailableRect, width, height);
             }
         } else {
             // Some fancy gravity setting that we don't support yet. We just put the activity in the
             // center.
             Slog.w(TAG, "Received unsupported gravity: " + windowLayout.gravity
                     + ", positioning in the center instead.");
-            positionCenter(task, tasks, width, height);
+            positionCenter(task, tasks, mAvailableRect, width, height);
         }
     }
 
-    void configure(Rect availableSpace) {
-        if (availableSpace == null) {
-            mAvailableRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
-        } else {
-            mAvailableRect.set(availableSpace);
-        }
+    private void updateAvailableRect(TaskRecord task, Rect availableRect) {
+        final Rect stackBounds = task.getStack().mBounds;
 
-        mDefaultFreeformStartX = getFreeformStartLeft(mAvailableRect);
-        mDefaultFreeformStartY = getFreeformStartTop(mAvailableRect);
-        mDefaultFreeformWidth = getFreeformWidth(mAvailableRect);
-        mDefaultFreeformHeight = getFreeformHeight(mAvailableRect);
-        mDefaultFreeformStepHorizontal = getHorizontalStep(mAvailableRect);
-        mDefaultFreeformStepVertical = getVerticalStep(mAvailableRect);
-        mDefaultStartBoundsConfigurationSet = true;
+        if (stackBounds != null) {
+            availableRect.set(stackBounds);
+        } else {
+            task.getStack().getDisplay().mDisplay.getSize(mDisplaySize);
+            availableRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
+        }
     }
 
     @VisibleForTesting
@@ -173,72 +157,79 @@
 
 
 
-    private int getFinalWidth(ActivityInfo.WindowLayout windowLayout) {
-        int width = mDefaultFreeformWidth;
+    private int getFinalWidth(ActivityInfo.WindowLayout windowLayout, Rect availableRect) {
+        int width = getFreeformWidth(availableRect);
         if (windowLayout.width > 0) {
             width = windowLayout.width;
         }
         if (windowLayout.widthFraction > 0) {
-            width = (int) (mAvailableRect.width() * windowLayout.widthFraction);
+            width = (int) (availableRect.width() * windowLayout.widthFraction);
         }
         return width;
     }
 
-    private int getFinalHeight(ActivityInfo.WindowLayout windowLayout) {
-        int height = mDefaultFreeformHeight;
+    private int getFinalHeight(ActivityInfo.WindowLayout windowLayout, Rect availableRect) {
+        int height = getFreeformHeight(availableRect);
         if (windowLayout.height > 0) {
             height = windowLayout.height;
         }
         if (windowLayout.heightFraction > 0) {
-            height = (int) (mAvailableRect.height() * windowLayout.heightFraction);
+            height = (int) (availableRect.height() * windowLayout.heightFraction);
         }
         return height;
     }
 
-    private void positionBottomLeft(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
-            int height) {
-        mTmpProposal.set(mAvailableRect.left, mAvailableRect.bottom - height,
-                mAvailableRect.left + width, mAvailableRect.bottom);
-        position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT);
+    private void positionBottomLeft(TaskRecord task, ArrayList<TaskRecord> tasks,
+            Rect availableRect, int width, int height) {
+        mTmpProposal.set(availableRect.left, availableRect.bottom - height,
+                availableRect.left + width, availableRect.bottom);
+        position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART,
+                SHIFT_POLICY_HORIZONTAL_RIGHT);
     }
 
-    private void positionBottomRight(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
-            int height) {
-        mTmpProposal.set(mAvailableRect.right - width, mAvailableRect.bottom - height,
-                mAvailableRect.right, mAvailableRect.bottom);
-        position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT);
+    private void positionBottomRight(TaskRecord task, ArrayList<TaskRecord> tasks,
+            Rect availableRect, int width, int height) {
+        mTmpProposal.set(availableRect.right - width, availableRect.bottom - height,
+                availableRect.right, availableRect.bottom);
+        position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART,
+                SHIFT_POLICY_HORIZONTAL_LEFT);
     }
 
-    private void positionTopLeft(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
-            int height) {
-        mTmpProposal.set(mAvailableRect.left, mAvailableRect.top,
-                mAvailableRect.left + width, mAvailableRect.top + height);
-        position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT);
+    private void positionTopLeft(TaskRecord task, ArrayList<TaskRecord> tasks,
+            Rect availableRect, int width, int height) {
+        mTmpProposal.set(availableRect.left, availableRect.top,
+                availableRect.left + width, availableRect.top + height);
+        position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART,
+                SHIFT_POLICY_HORIZONTAL_RIGHT);
     }
 
-    private void positionTopRight(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
-            int height) {
-        mTmpProposal.set(mAvailableRect.right - width, mAvailableRect.top,
-                mAvailableRect.right, mAvailableRect.top + height);
-        position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT);
+    private void positionTopRight(TaskRecord task, ArrayList<TaskRecord> tasks,
+            Rect availableRect, int width, int height) {
+        mTmpProposal.set(availableRect.right - width, availableRect.top,
+                availableRect.right, availableRect.top + height);
+        position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART,
+                SHIFT_POLICY_HORIZONTAL_LEFT);
     }
 
-    private void positionCenter(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
-            int height) {
-        mTmpProposal.set(mDefaultFreeformStartX, mDefaultFreeformStartY,
-                mDefaultFreeformStartX + width, mDefaultFreeformStartY + height);
-        position(task, tasks, mTmpProposal, ALLOW_RESTART, SHIFT_POLICY_DIAGONAL_DOWN);
+    private void positionCenter(TaskRecord task, ArrayList<TaskRecord> tasks,
+            Rect availableRect, int width, int height) {
+        final int defaultFreeformLeft = getFreeformStartLeft(availableRect);
+        final int defaultFreeformTop = getFreeformStartTop(availableRect);
+        mTmpProposal.set(defaultFreeformLeft, defaultFreeformTop,
+                defaultFreeformLeft + width, defaultFreeformTop + height);
+        position(task, tasks, availableRect, mTmpProposal, ALLOW_RESTART,
+                SHIFT_POLICY_DIAGONAL_DOWN);
     }
 
-    private void position(TaskRecord task, ArrayList<TaskRecord> tasks, Rect proposal,
-            boolean allowRestart, int shiftPolicy) {
+    private void position(TaskRecord task, ArrayList<TaskRecord> tasks, Rect availableRect,
+            Rect proposal, boolean allowRestart, int shiftPolicy) {
         mTmpOriginal.set(proposal);
         boolean restarted = false;
         while (boundsConflict(proposal, tasks)) {
             // Unfortunately there is already a task at that spot, so we need to look for some
             // other place.
-            shiftStartingPoint(proposal, shiftPolicy);
-            if (shiftedTooFar(proposal, shiftPolicy)) {
+            shiftStartingPoint(proposal, availableRect, shiftPolicy);
+            if (shiftedTooFar(proposal, availableRect, shiftPolicy)) {
                 // We don't want the task to go outside of the stack, because it won't look
                 // nice. Depending on the starting point we either restart, or immediately give up.
                 if (!allowRestart) {
@@ -247,13 +238,13 @@
                 }
                 // We must have started not from the top. Let's restart from there because there
                 // might be some space there.
-                proposal.set(mAvailableRect.left, mAvailableRect.top,
-                        mAvailableRect.left + proposal.width(),
-                        mAvailableRect.top + proposal.height());
+                proposal.set(availableRect.left, availableRect.top,
+                        availableRect.left + proposal.width(),
+                        availableRect.top + proposal.height());
                 restarted = true;
             }
-            if (restarted && (proposal.left > mDefaultFreeformStartX
-                    || proposal.top > mDefaultFreeformStartY)) {
+            if (restarted && (proposal.left > getFreeformStartLeft(availableRect)
+                    || proposal.top > getFreeformStartTop(availableRect))) {
                 // If we restarted and crossed the initial position, let's not struggle anymore.
                 // The user already must have ton of tasks visible, we can just smack the new
                 // one in the center.
@@ -264,27 +255,30 @@
         task.updateOverrideConfiguration(proposal);
     }
 
-    private boolean shiftedTooFar(Rect start, int shiftPolicy) {
+    private boolean shiftedTooFar(Rect start, Rect availableRect, int shiftPolicy) {
         switch (shiftPolicy) {
             case SHIFT_POLICY_HORIZONTAL_LEFT:
-                return start.left < mAvailableRect.left;
+                return start.left < availableRect.left;
             case SHIFT_POLICY_HORIZONTAL_RIGHT:
-                return start.right > mAvailableRect.right;
+                return start.right > availableRect.right;
             default: // SHIFT_POLICY_DIAGONAL_DOWN
-                return start.right > mAvailableRect.right || start.bottom > mAvailableRect.bottom;
+                return start.right > availableRect.right || start.bottom > availableRect.bottom;
         }
     }
 
-    private void shiftStartingPoint(Rect posposal, int shiftPolicy) {
+    private void shiftStartingPoint(Rect posposal, Rect availableRect, int shiftPolicy) {
+        final int defaultFreeformStepHorizontal = getHorizontalStep(availableRect);
+        final int defaultFreeformStepVertical = getVerticalStep(availableRect);
+
         switch (shiftPolicy) {
             case SHIFT_POLICY_HORIZONTAL_LEFT:
-                posposal.offset(-mDefaultFreeformStepHorizontal, 0);
+                posposal.offset(-defaultFreeformStepHorizontal, 0);
                 break;
             case SHIFT_POLICY_HORIZONTAL_RIGHT:
-                posposal.offset(mDefaultFreeformStepHorizontal, 0);
+                posposal.offset(defaultFreeformStepHorizontal, 0);
                 break;
             default: // SHIFT_POLICY_DIAGONAL_DOWN:
-                posposal.offset(mDefaultFreeformStepHorizontal, mDefaultFreeformStepVertical);
+                posposal.offset(defaultFreeformStepHorizontal, defaultFreeformStepVertical);
                 break;
         }
     }
@@ -323,8 +317,4 @@
         return Math.abs(first.right - second.right) < BOUNDS_CONFLICT_MIN_DISTANCE
                 && Math.abs(first.bottom - second.bottom) < BOUNDS_CONFLICT_MIN_DISTANCE;
     }
-
-    void reset() {
-        mDefaultStartBoundsConfigurationSet = false;
-    }
 }
diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java
index 72b5de8..1c094c1 100644
--- a/services/core/java/com/android/server/am/LockTaskController.java
+++ b/services/core/java/com/android/server/am/LockTaskController.java
@@ -19,7 +19,6 @@
 import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
 import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.StatusBarManager.DISABLE_BACK;
 import static android.app.StatusBarManager.DISABLE_HOME;
 import static android.app.StatusBarManager.DISABLE_MASK;
@@ -59,7 +58,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.widget.LockPatternUtils;
@@ -329,7 +327,9 @@
             if (getDevicePolicyManager() != null) {
                 getDevicePolicyManager().notifyLockTaskModeChanged(false, null, userId);
             }
-            getLockTaskNotify().show(false);
+            if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) {
+                getLockTaskNotify().showPinningExitToast();
+            }
             try {
                 boolean shouldLockKeyguard = Settings.Secure.getIntForUser(
                         mContext.getContentResolver(),
@@ -351,10 +351,13 @@
     }
 
     /**
-     * Show the lock task violation toast.
+     * Show the lock task violation toast. Currently we only show toast for screen pinning mode, and
+     * no-op if the device is in locked mode.
      */
     void showLockTaskToast() {
-        mHandler.post(() -> getLockTaskNotify().showToast(mLockTaskModeState));
+        if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) {
+            mHandler.post(() -> getLockTaskNotify().showEscapeToast());
+        }
     }
 
     // Starting lock task
@@ -433,7 +436,7 @@
             mWindowManager.executeAppTransition();
         } else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
             mSupervisor.handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED,
-                    DEFAULT_DISPLAY, task.getStackId(), true /* forceNonResizable */);
+                    DEFAULT_DISPLAY, task.getStack(), true /* forceNonResizable */);
         }
     }
 
@@ -441,7 +444,9 @@
     private void performStartLockTask(String packageName, int userId, int lockTaskModeState) {
         // When lock task starts, we disable the status bars.
         try {
-            getLockTaskNotify().show(true);
+            if (lockTaskModeState == LOCK_TASK_MODE_PINNED) {
+                getLockTaskNotify().showPinningStartToast();
+            }
             mLockTaskModeState = lockTaskModeState;
             if (getStatusBarService() != null) {
                 int flags = 0;
@@ -494,11 +499,7 @@
         }
 
         for (int displayNdx = mSupervisor.getChildCount() - 1; displayNdx >= 0; --displayNdx) {
-            ArrayList<ActivityStack> stacks = mSupervisor.getChildAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
-                stack.onLockTaskPackagesUpdatedLocked();
-            }
+            mSupervisor.getChildAt(displayNdx).onLockTaskPackagesUpdated();
         }
 
         final ActivityRecord r = mSupervisor.topRunningActivityLocked();
diff --git a/services/core/java/com/android/server/am/LockTaskNotify.java b/services/core/java/com/android/server/am/LockTaskNotify.java
index 0412db5..5d6e9b5 100644
--- a/services/core/java/com/android/server/am/LockTaskNotify.java
+++ b/services/core/java/com/android/server/am/LockTaskNotify.java
@@ -16,7 +16,6 @@
 
 package com.android.server.am;
 
-import android.app.ActivityManager;
 import android.content.Context;
 import android.os.Handler;
 import android.os.Message;
@@ -29,7 +28,7 @@
 
 /**
  *  Helper to manage showing/hiding a image to notify them that they are entering
- *  or exiting lock-to-app mode.
+ *  or exiting screen pinning mode.
  */
 public class LockTaskNotify {
     private static final String TAG = "LockTaskNotify";
@@ -45,20 +44,22 @@
         mHandler = new H();
     }
 
-    public void showToast(int lockTaskModeState) {
-        mHandler.obtainMessage(H.SHOW_TOAST, lockTaskModeState, 0 /* Not used */).sendToTarget();
+    /** Show "Screen pinned" toast. */
+    void showPinningStartToast() {
+        makeAllUserToastAndShow(R.string.lock_to_app_start);
     }
 
-    public void handleShowToast(int lockTaskModeState) {
-        String text = null;
-        if (lockTaskModeState == ActivityManager.LOCK_TASK_MODE_LOCKED) {
-            text = mContext.getString(R.string.lock_to_app_toast_locked);
-        } else if (lockTaskModeState == ActivityManager.LOCK_TASK_MODE_PINNED) {
-            text = mContext.getString(R.string.lock_to_app_toast);
-        }
-        if (text == null) {
-            return;
-        }
+    /** Show "Screen unpinned" toast. */
+    void showPinningExitToast() {
+        makeAllUserToastAndShow(R.string.lock_to_app_exit);
+    }
+
+    /** Show a toast that describes the gesture the user should use to escape pinned mode. */
+    void showEscapeToast() {
+        mHandler.obtainMessage(H.SHOW_ESCAPE_TOAST).sendToTarget();
+    }
+
+    private void handleShowEscapeToast() {
         long showToastTime = SystemClock.elapsedRealtime();
         if ((showToastTime - mLastShowToastTime) < SHOW_TOAST_MINIMUM_INTERVAL) {
             Slog.i(TAG, "Ignore toast since it is requested in very short interval.");
@@ -67,20 +68,12 @@
         if (mLastToast != null) {
             mLastToast.cancel();
         }
-        mLastToast = makeAllUserToastAndShow(text);
+        mLastToast = makeAllUserToastAndShow(R.string.lock_to_app_toast);
         mLastShowToastTime = showToastTime;
     }
 
-    public void show(boolean starting) {
-        int showString = R.string.lock_to_app_exit;
-        if (starting) {
-            showString = R.string.lock_to_app_start;
-        }
-        makeAllUserToastAndShow(mContext.getString(showString));
-    }
-
-    private Toast makeAllUserToastAndShow(String text) {
-        Toast toast = Toast.makeText(mContext, text, Toast.LENGTH_LONG);
+    private Toast makeAllUserToastAndShow(int resId) {
+        Toast toast = Toast.makeText(mContext, resId, Toast.LENGTH_LONG);
         toast.getWindowParams().privateFlags |=
                 WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
         toast.show();
@@ -88,13 +81,13 @@
     }
 
     private final class H extends Handler {
-        private static final int SHOW_TOAST = 3;
+        private static final int SHOW_ESCAPE_TOAST = 3;
 
         @Override
         public void handleMessage(Message msg) {
             switch(msg.what) {
-                case SHOW_TOAST:
-                    handleShowToast(msg.arg1);
+                case SHOW_ESCAPE_TOAST:
+                    handleShowEscapeToast();
                     break;
             }
         }
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 0e318d9..e847723 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -27,6 +27,7 @@
 import com.android.internal.app.procstats.ProcessStats;
 import com.android.internal.app.procstats.ProcessState;
 import com.android.internal.os.BatteryStatsImpl;
+import com.android.server.am.proto.ProcessRecordProto;
 
 import android.app.ActivityManager;
 import android.app.Dialog;
@@ -44,6 +45,7 @@
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -621,6 +623,22 @@
         }
     }
 
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        long token = proto.start(fieldId);
+        proto.write(ProcessRecordProto.PID, pid);
+        proto.write(ProcessRecordProto.PROCESS_NAME, processName);
+        if (info.uid < Process.FIRST_APPLICATION_UID) {
+            proto.write(ProcessRecordProto.UID, uid);
+        } else {
+            proto.write(ProcessRecordProto.USER_ID, userId);
+            proto.write(ProcessRecordProto.APP_ID, UserHandle.getAppId(info.uid));
+            if (uid != info.uid) {
+                proto.write(ProcessRecordProto.ISOLATED_APP_ID, UserHandle.getAppId(uid));
+            }
+        }
+        proto.end(token);
+    }
+
     public String toShortString() {
         if (shortStringName != null) {
             return shortStringName;
diff --git a/services/core/java/com/android/server/am/ReceiverList.java b/services/core/java/com/android/server/am/ReceiverList.java
index 6ade736..a989063 100644
--- a/services/core/java/com/android/server/am/ReceiverList.java
+++ b/services/core/java/com/android/server/am/ReceiverList.java
@@ -21,6 +21,8 @@
 import android.os.IBinder;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
+import android.util.proto.ProtoOutputStream;
+import com.android.server.am.proto.ReceiverListProto;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -41,7 +43,7 @@
     boolean linkedToDeath = false;
 
     String stringName;
-    
+
     ReceiverList(ActivityManagerService _owner, ProcessRecord _app,
             int _pid, int _uid, int _userId, IIntentReceiver _receiver) {
         owner = _owner;
@@ -59,12 +61,31 @@
     public int hashCode() {
         return System.identityHashCode(this);
     }
-    
+
     public void binderDied() {
         linkedToDeath = false;
         owner.unregisterReceiver(receiver);
     }
-    
+
+    void writeToProto(ProtoOutputStream proto, long fieldId) {
+        long token = proto.start(fieldId);
+        app.writeToProto(proto, ReceiverListProto.APP);
+        proto.write(ReceiverListProto.PID, pid);
+        proto.write(ReceiverListProto.UID, uid);
+        proto.write(ReceiverListProto.USER, userId);
+        if (curBroadcast != null) {
+            curBroadcast.writeToProto(proto, ReceiverListProto.CURRENT);
+        }
+        proto.write(ReceiverListProto.LINKED_TO_DEATH, linkedToDeath);
+        final int N = size();
+        for (int i=0; i<N; i++) {
+            BroadcastFilter bf = get(i);
+            bf.writeToProto(proto, ReceiverListProto.FILTERS);
+        }
+        proto.write(ReceiverListProto.HEX_HASH, Integer.toHexString(System.identityHashCode(this)));
+        proto.end(token);
+    }
+
     void dumpLocal(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("app="); pw.print(app != null ? app.toShortString() : null);
             pw.print(" pid="); pw.print(pid); pw.print(" uid="); pw.print(uid);
@@ -74,7 +95,7 @@
                 pw.print(" linkedToDeath="); pw.println(linkedToDeath);
         }
     }
-    
+
     void dump(PrintWriter pw, String prefix) {
         Printer pr = new PrintWriterPrinter(pw);
         dumpLocal(pw, prefix);
@@ -89,7 +110,7 @@
             bf.dumpInReceiverList(pw, pr, p2);
         }
     }
-    
+
     public String toString() {
         if (stringName != null) {
             return stringName;
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index 365c5b1..ed3f503 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -16,15 +16,25 @@
 
 package com.android.server.am;
 
+import static android.app.ActivityManager.FLAG_AND_UNLOCKED;
+import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
+import static android.app.ActivityManager.RECENT_WITH_EXCLUDED;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS_TRIM_TASKS;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
 import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
 
 import com.google.android.collect.Sets;
@@ -37,43 +47,87 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.os.Bundle;
 import android.os.Environment;
+import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.util.ArraySet;
+import android.util.MutableBoolean;
+import android.util.MutableInt;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.am.ActivityStack.ActivityState;
+
 import java.io.File;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 /**
- * Class for managing the recent tasks list.
+ * Class for managing the recent tasks list. The list is ordered by most recent (index 0) to the
+ * least recent.
  */
-class RecentTasks extends ArrayList<TaskRecord> {
+class RecentTasks {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "RecentTasks" : TAG_AM;
     private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
     private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
+    private static final boolean TRIMMED = true;
 
-    // Maximum number recent bitmaps to keep in memory.
-    private static final int MAX_RECENT_BITMAPS = 3;
     private static final int DEFAULT_INITIAL_CAPACITY = 5;
 
     // Whether or not to move all affiliated tasks to the front when one of the tasks is launched
     private static final boolean MOVE_AFFILIATED_TASKS_TO_FRONT = false;
 
+    // Comparator to sort by taskId
+    private static final Comparator<TaskRecord> TASK_ID_COMPARATOR =
+            (lhs, rhs) -> rhs.taskId - lhs.taskId;
+
+    // Placeholder variables to keep track of activities/apps that are no longer avialble while
+    // iterating through the recents list
+    private static final ActivityInfo NO_ACTIVITY_INFO_TOKEN = new ActivityInfo();
+    private static final ApplicationInfo NO_APPLICATION_INFO_TOKEN = new ApplicationInfo();
+
+    /**
+     * Callbacks made when manipulating the list.
+     */
+    interface Callbacks {
+        /**
+         * Called when a task is added to the recent tasks list.
+         */
+        void onRecentTaskAdded(TaskRecord task);
+
+        /**
+         * Called when a task is removed from the recent tasks list.
+         */
+        void onRecentTaskRemoved(TaskRecord task, boolean wasTrimmed);
+    }
+
     /**
      * Save recent tasks information across reboots.
      */
     private final TaskPersister mTaskPersister;
     private final ActivityManagerService mService;
+    private final UserController mUserController;
+
+    /**
+     * Mapping of user id -> whether recent tasks have been loaded for that user.
+     */
     private final SparseBooleanArray mUsersWithRecentsLoaded = new SparseBooleanArray(
             DEFAULT_INITIAL_CAPACITY);
 
@@ -81,21 +135,106 @@
      * Stores for each user task ids that are taken by tasks residing in persistent storage. These
      * tasks may or may not currently be in memory.
      */
-    final SparseArray<SparseBooleanArray> mPersistedTaskIds = new SparseArray<>(
+    private final SparseArray<SparseBooleanArray> mPersistedTaskIds = new SparseArray<>(
             DEFAULT_INITIAL_CAPACITY);
 
+    // List of all active recent tasks
+    private final ArrayList<TaskRecord> mTasks = new ArrayList<>();
+    private final ArrayList<Callbacks> mCallbacks = new ArrayList<>();
+
+    // These values are generally loaded from resources, but can be set dynamically in the tests
+    private boolean mHasVisibleRecentTasks;
+    private int mGlobalMaxNumTasks;
+    private int mMinNumVisibleTasks;
+    private int mMaxNumVisibleTasks;
+    private long mActiveTasksSessionDurationMs;
+
     // Mainly to avoid object recreation on multiple calls.
-    private final ArrayList<TaskRecord> mTmpRecents = new ArrayList<TaskRecord>();
+    private final ArrayList<TaskRecord> mTmpRecents = new ArrayList<>();
     private final HashMap<ComponentName, ActivityInfo> mTmpAvailActCache = new HashMap<>();
     private final HashMap<String, ApplicationInfo> mTmpAvailAppCache = new HashMap<>();
-    private final ActivityInfo mTmpActivityInfo = new ActivityInfo();
-    private final ApplicationInfo mTmpAppInfo = new ApplicationInfo();
+    private final SparseBooleanArray mTmpQuietProfileUserIds = new SparseBooleanArray();
 
-    RecentTasks(ActivityManagerService service, ActivityStackSupervisor mStackSupervisor) {
-        File systemDir = Environment.getDataSystemDirectory();
+    @VisibleForTesting
+    RecentTasks(ActivityManagerService service, TaskPersister taskPersister,
+            UserController userController) {
         mService = service;
-        mTaskPersister = new TaskPersister(systemDir, mStackSupervisor, service, this);
-        mStackSupervisor.setRecentTasks(this);
+        mUserController = userController;
+        mTaskPersister = taskPersister;
+        mGlobalMaxNumTasks = ActivityManager.getMaxRecentTasksStatic();
+        mHasVisibleRecentTasks = true;
+    }
+
+    RecentTasks(ActivityManagerService service, ActivityStackSupervisor stackSupervisor) {
+        final File systemDir = Environment.getDataSystemDirectory();
+        final Resources res = service.mContext.getResources();
+        mService = service;
+        mUserController = service.mUserController;
+        mTaskPersister = new TaskPersister(systemDir, stackSupervisor, service, this);
+        mGlobalMaxNumTasks = ActivityManager.getMaxRecentTasksStatic();
+        mHasVisibleRecentTasks = res.getBoolean(com.android.internal.R.bool.config_hasRecents);
+        loadParametersFromResources(service.mContext.getResources());
+    }
+
+    @VisibleForTesting
+    void setParameters(int minNumVisibleTasks, int maxNumVisibleTasks,
+            long activeSessionDurationMs) {
+        mMinNumVisibleTasks = minNumVisibleTasks;
+        mMaxNumVisibleTasks = maxNumVisibleTasks;
+        mActiveTasksSessionDurationMs = activeSessionDurationMs;
+    }
+
+    @VisibleForTesting
+    void setGlobalMaxNumTasks(int globalMaxNumTasks) {
+        mGlobalMaxNumTasks = globalMaxNumTasks;
+    }
+
+    /**
+     * Loads the parameters from the system resources.
+     */
+    @VisibleForTesting
+    void loadParametersFromResources(Resources res) {
+        if (ActivityManager.isLowRamDeviceStatic()) {
+            mMinNumVisibleTasks = res.getInteger(
+                    com.android.internal.R.integer.config_minNumVisibleRecentTasks_lowRam);
+            mMaxNumVisibleTasks = res.getInteger(
+                    com.android.internal.R.integer.config_maxNumVisibleRecentTasks_lowRam);
+        } else if (SystemProperties.getBoolean("ro.recents.grid", false)) {
+            mMinNumVisibleTasks = res.getInteger(
+                    com.android.internal.R.integer.config_minNumVisibleRecentTasks_grid);
+            mMaxNumVisibleTasks = res.getInteger(
+                    com.android.internal.R.integer.config_maxNumVisibleRecentTasks_grid);
+        } else {
+            mMinNumVisibleTasks = res.getInteger(
+                    com.android.internal.R.integer.config_minNumVisibleRecentTasks);
+            mMaxNumVisibleTasks = res.getInteger(
+                    com.android.internal.R.integer.config_maxNumVisibleRecentTasks);
+        }
+        final int sessionDurationHrs = res.getInteger(
+                com.android.internal.R.integer.config_activeTaskDurationHours);
+        mActiveTasksSessionDurationMs = (sessionDurationHrs > 0)
+                ? TimeUnit.HOURS.toMillis(sessionDurationHrs)
+                : -1;
+    }
+
+    void registerCallback(Callbacks callback) {
+        mCallbacks.add(callback);
+    }
+
+    void unregisterCallback(Callbacks callback) {
+        mCallbacks.remove(callback);
+    }
+
+    private void notifyTaskAdded(TaskRecord task) {
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            mCallbacks.get(i).onRecentTaskAdded(task);
+        }
+    }
+
+    private void notifyTaskRemoved(TaskRecord task, boolean wasTrimmed) {
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            mCallbacks.get(i).onRecentTaskRemoved(task, wasTrimmed);
+        }
     }
 
     /**
@@ -106,6 +245,7 @@
      */
     void loadUserRecentsLocked(int userId) {
         if (mUsersWithRecentsLoaded.get(userId)) {
+            // User already loaded, return early
             return;
         }
 
@@ -114,14 +254,14 @@
 
         // Check if any tasks are added before recents is loaded
         final SparseBooleanArray preaddedTasks = new SparseBooleanArray();
-        for (final TaskRecord task : this) {
+        for (final TaskRecord task : mTasks) {
             if (task.userId == userId && shouldPersistTaskLocked(task)) {
                 preaddedTasks.put(task.taskId, true);
             }
         }
 
         Slog.i(TAG, "Loading recents for user " + userId + " into memory.");
-        addAll(mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks));
+        mTasks.addAll(mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks));
         cleanupLocked(userId);
         mUsersWithRecentsLoaded.put(userId, true);
 
@@ -140,11 +280,25 @@
         }
     }
 
-    boolean taskIdTakenForUserLocked(int taskId, int userId) {
+    /**
+     * @return whether the {@param taskId} is currently in use for the given user.
+     */
+    boolean containsTaskId(int taskId, int userId) {
         loadPersistedTaskIdsForUserLocked(userId);
         return mPersistedTaskIds.get(userId).get(taskId);
     }
 
+    /**
+     * @return all the task ids for the user with the given {@param userId}.
+     */
+    SparseBooleanArray getTaskIdsForUser(int userId) {
+        loadPersistedTaskIdsForUserLocked(userId);
+        return mPersistedTaskIds.get(userId);
+    }
+
+    /**
+     * Kicks off the task persister to write any pending tasks to disk.
+     */
     void notifyTaskPersisterLocked(TaskRecord task, boolean flush) {
         final ActivityStack stack = task != null ? task.getStack() : null;
         if (stack != null && stack.isHomeOrRecentsStack()) {
@@ -164,8 +318,8 @@
                 mPersistedTaskIds.valueAt(i).clear();
             }
         }
-        for (int i = size() - 1; i >= 0; i--) {
-            final TaskRecord task = get(i);
+        for (int i = mTasks.size() - 1; i >= 0; i--) {
+            final TaskRecord task = mTasks.get(i);
             if (shouldPersistTaskLocked(task)) {
                 // Set of persisted taskIds for task.userId should not be null here
                 // TODO Investigate why it can happen. For now initialize with an empty set
@@ -180,12 +334,12 @@
     }
 
     private static boolean shouldPersistTaskLocked(TaskRecord task) {
-        final ActivityStack<?> stack = task.getStack();
+        final ActivityStack stack = task.getStack();
         return task.isPersistable && (stack == null || !stack.isHomeOrRecentsStack());
     }
 
     void onSystemReadyLocked() {
-        clear();
+        mTasks.clear();
         mTaskPersister.startPersisting();
     }
 
@@ -225,14 +379,6 @@
         return usersWithRecentsLoaded;
     }
 
-    private void unloadUserRecentsLocked(int userId) {
-        if (mUsersWithRecentsLoaded.get(userId)) {
-            Slog.i(TAG, "Unloading recents for user " + userId + " from memory.");
-            mUsersWithRecentsLoaded.delete(userId);
-            removeTasksForUserLocked(userId);
-        }
-    }
-
     /**
      * Removes recent tasks and any other state kept in memory for the passed in user. Does not
      * touch the information present on persistent storage.
@@ -240,44 +386,36 @@
      * @param userId the id of the user
      */
     void unloadUserDataFromMemoryLocked(int userId) {
-        unloadUserRecentsLocked(userId);
+        if (mUsersWithRecentsLoaded.get(userId)) {
+            Slog.i(TAG, "Unloading recents for user " + userId + " from memory.");
+            mUsersWithRecentsLoaded.delete(userId);
+            removeTasksForUserLocked(userId);
+        }
         mPersistedTaskIds.delete(userId);
         mTaskPersister.unloadUserDataFromMemory(userId);
     }
 
-    TaskRecord taskForIdLocked(int id) {
-        final int recentsCount = size();
-        for (int i = 0; i < recentsCount; i++) {
-            TaskRecord tr = get(i);
-            if (tr.taskId == id) {
-                return tr;
-            }
-        }
-        return null;
-    }
-
     /** Remove recent tasks for a user. */
-    void removeTasksForUserLocked(int userId) {
+    private void removeTasksForUserLocked(int userId) {
         if(userId <= 0) {
             Slog.i(TAG, "Can't remove recent task on user " + userId);
             return;
         }
 
-        for (int i = size() - 1; i >= 0; --i) {
-            TaskRecord tr = get(i);
+        for (int i = mTasks.size() - 1; i >= 0; --i) {
+            TaskRecord tr = mTasks.get(i);
             if (tr.userId == userId) {
                 if(DEBUG_TASKS) Slog.i(TAG_TASKS,
                         "remove RecentTask " + tr + " when finishing user" + userId);
-                remove(i);
-                tr.removedFromRecents();
+                remove(mTasks.get(i));
             }
         }
     }
 
     void onPackagesSuspendedChanged(String[] packages, boolean suspended, int userId) {
         final Set<String> packageNames = Sets.newHashSet(packages);
-        for (int i = size() - 1; i >= 0; --i) {
-            final TaskRecord tr = get(i);
+        for (int i = mTasks.size() - 1; i >= 0; --i) {
+            final TaskRecord tr = mTasks.get(i);
             if (tr.realActivity != null
                     && packageNames.contains(tr.realActivity.getPackageName())
                     && tr.userId == userId
@@ -286,7 +424,36 @@
                notifyTaskPersisterLocked(tr, false);
             }
         }
+    }
 
+    void removeTasksByPackageName(String packageName, int userId) {
+        for (int i = mTasks.size() - 1; i >= 0; --i) {
+            final TaskRecord tr = mTasks.get(i);
+            final String taskPackageName =
+                    tr.getBaseIntent().getComponent().getPackageName();
+            if (tr.userId != userId) return;
+            if (!taskPackageName.equals(packageName)) return;
+
+            mService.mStackSupervisor.removeTaskByIdLocked(tr.taskId, true, REMOVE_FROM_RECENTS);
+        }
+    }
+
+    void cleanupDisabledPackageTasksLocked(String packageName, Set<String> filterByClasses,
+            int userId) {
+        for (int i = mTasks.size() - 1; i >= 0; --i) {
+            final TaskRecord tr = mTasks.get(i);
+            if (userId != UserHandle.USER_ALL && tr.userId != userId) {
+                continue;
+            }
+
+            ComponentName cn = tr.intent.getComponent();
+            final boolean sameComponent = cn != null && cn.getPackageName().equals(packageName)
+                    && (filterByClasses == null || filterByClasses.contains(cn.getClassName()));
+            if (sameComponent) {
+                mService.mStackSupervisor.removeTaskByIdLocked(tr.taskId, false,
+                        REMOVE_FROM_RECENTS);
+            }
+        }
     }
 
     /**
@@ -295,24 +462,28 @@
      * of affiliations.
      */
     void cleanupLocked(int userId) {
-        int recentsCount = size();
+        int recentsCount = mTasks.size();
         if (recentsCount == 0) {
             // Happens when called from the packagemanager broadcast before boot,
             // or just any empty list.
             return;
         }
 
+        // Clear the temp lists
+        mTmpAvailActCache.clear();
+        mTmpAvailAppCache.clear();
+
         final IPackageManager pm = AppGlobals.getPackageManager();
         for (int i = recentsCount - 1; i >= 0; i--) {
-            final TaskRecord task = get(i);
+            final TaskRecord task = mTasks.get(i);
             if (userId != UserHandle.USER_ALL && task.userId != userId) {
                 // Only look at tasks for the user ID of interest.
                 continue;
             }
             if (task.autoRemoveRecents && task.getTopActivity() == null) {
                 // This situation is broken, and we should just get rid of it now.
-                remove(i);
-                task.removedFromRecents();
+                mTasks.remove(i);
+                notifyTaskRemoved(task, !TRIMMED);
                 Slog.w(TAG, "Removing auto-remove without activity: " + task);
                 continue;
             }
@@ -331,11 +502,11 @@
                         continue;
                     }
                     if (ai == null) {
-                        ai = mTmpActivityInfo;
+                        ai = NO_ACTIVITY_INFO_TOKEN;
                     }
                     mTmpAvailActCache.put(task.realActivity, ai);
                 }
-                if (ai == mTmpActivityInfo) {
+                if (ai == NO_ACTIVITY_INFO_TOKEN) {
                     // This could be either because the activity no longer exists, or the
                     // app is temporarily gone. For the former we want to remove the recents
                     // entry; for the latter we want to mark it as unavailable.
@@ -350,15 +521,15 @@
                             continue;
                         }
                         if (app == null) {
-                            app = mTmpAppInfo;
+                            app = NO_APPLICATION_INFO_TOKEN;
                         }
                         mTmpAvailAppCache.put(task.realActivity.getPackageName(), app);
                     }
-                    if (app == mTmpAppInfo
+                    if (app == NO_APPLICATION_INFO_TOKEN
                             || (app.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
                         // Doesn't exist any more! Good-bye.
-                        remove(i);
-                        task.removedFromRecents();
+                        mTasks.remove(i);
+                        notifyTaskRemoved(task, !TRIMMED);
                         Slog.w(TAG, "Removing no longer valid recent: " + task);
                         continue;
                     } else {
@@ -390,15 +561,670 @@
 
         // Verify the affiliate chain for each task.
         int i = 0;
-        recentsCount = size();
+        recentsCount = mTasks.size();
         while (i < recentsCount) {
             i = processNextAffiliateChainLocked(i);
         }
         // recent tasks are now in sorted, affiliated order.
     }
 
-    private final boolean moveAffiliatedTasksToFront(TaskRecord task, int taskIndex) {
-        int recentsCount = size();
+    /**
+     * @return whether the given {@param task} can be added to the list without causing another
+     * task to be trimmed as a result of that add.
+     */
+    private boolean canAddTaskWithoutTrim(TaskRecord task) {
+        return findTrimIndexForAddTask(task) == -1;
+    }
+
+    /**
+     * Returns the list of {@link ActivityManager.AppTask}s.
+     */
+    ArrayList<IBinder> getAppTasksList(int callingUid, String callingPackage) {
+        final ArrayList<IBinder> list = new ArrayList<>();
+        final int size = mTasks.size();
+        for (int i = 0; i < size; i++) {
+            final TaskRecord tr = mTasks.get(i);
+            // Skip tasks that do not match the caller.  We don't need to verify
+            // callingPackage, because we are also limiting to callingUid and know
+            // that will limit to the correct security sandbox.
+            if (tr.effectiveUid != callingUid) {
+                continue;
+            }
+            Intent intent = tr.getBaseIntent();
+            if (intent == null || !callingPackage.equals(intent.getComponent().getPackageName())) {
+                continue;
+            }
+            ActivityManager.RecentTaskInfo taskInfo = createRecentTaskInfo(tr);
+            AppTaskImpl taskImpl = new AppTaskImpl(mService, taskInfo.persistentId, callingUid);
+            list.add(taskImpl.asBinder());
+        }
+        return list;
+    }
+
+    /**
+     * @return the list of recent tasks for presentation.
+     */
+    ParceledListSlice<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, int flags,
+            boolean getTasksAllowed, boolean getDetailedTasks, int userId, int callingUid) {
+        final boolean withExcluded = (flags & RECENT_WITH_EXCLUDED) != 0;
+
+        if (!mService.isUserRunning(userId, FLAG_AND_UNLOCKED)) {
+            Slog.i(TAG, "user " + userId + " is still locked. Cannot load recents");
+            return ParceledListSlice.emptyList();
+        }
+        loadUserRecentsLocked(userId);
+
+        final Set<Integer> includedUsers = mUserController.getProfileIds(userId);
+        includedUsers.add(Integer.valueOf(userId));
+
+        final ArrayList<ActivityManager.RecentTaskInfo> res = new ArrayList<>();
+        final int size = mTasks.size();
+        int numVisibleTasks = 0;
+        for (int i = 0; i < size; i++) {
+            final TaskRecord tr = mTasks.get(i);
+
+            if (isVisibleRecentTask(tr)) {
+                numVisibleTasks++;
+                if (isInVisibleRange(tr, numVisibleTasks)) {
+                    // Fall through
+                } else {
+                    // Not in visible range
+                    continue;
+                }
+            } else {
+                // Not visible
+                continue;
+            }
+
+            // Skip remaining tasks once we reach the requested size
+            if (res.size() >= maxNum) {
+                continue;
+            }
+
+            // Only add calling user or related users recent tasks
+            if (!includedUsers.contains(Integer.valueOf(tr.userId))) {
+                if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + tr);
+                continue;
+            }
+
+            if (tr.realActivitySuspended) {
+                if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, activity suspended: " + tr);
+                continue;
+            }
+
+            // Return the entry if desired by the caller.  We always return
+            // the first entry, because callers always expect this to be the
+            // foreground app.  We may filter others if the caller has
+            // not supplied RECENT_WITH_EXCLUDED and there is some reason
+            // we should exclude the entry.
+
+            if (i == 0
+                    || withExcluded
+                    || (tr.intent == null)
+                    || ((tr.intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+                    == 0)) {
+                if (!getTasksAllowed) {
+                    // If the caller doesn't have the GET_TASKS permission, then only
+                    // allow them to see a small subset of tasks -- their own and home.
+                    if (!tr.isActivityTypeHome() && tr.effectiveUid != callingUid) {
+                        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + tr);
+                        continue;
+                    }
+                }
+                if (tr.autoRemoveRecents && tr.getTopActivity() == null) {
+                    // Don't include auto remove tasks that are finished or finishing.
+                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+                            "Skipping, auto-remove without activity: " + tr);
+                    continue;
+                }
+                if ((flags & RECENT_IGNORE_UNAVAILABLE) != 0 && !tr.isAvailable) {
+                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+                            "Skipping, unavail real act: " + tr);
+                    continue;
+                }
+
+                if (!tr.mUserSetupComplete) {
+                    // Don't include task launched while user is not done setting-up.
+                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+                            "Skipping, user setup not complete: " + tr);
+                    continue;
+                }
+
+                ActivityManager.RecentTaskInfo rti = RecentTasks.createRecentTaskInfo(tr);
+                if (!getDetailedTasks) {
+                    rti.baseIntent.replaceExtras((Bundle)null);
+                }
+
+                res.add(rti);
+            }
+        }
+        return new ParceledListSlice<>(res);
+    }
+
+    /**
+     * @return the list of persistable task ids.
+     */
+    void getPersistableTaskIds(ArraySet<Integer> persistentTaskIds) {
+        final int size = mTasks.size();
+        for (int i = 0; i < size; i++) {
+            final TaskRecord task = mTasks.get(i);
+            if (TaskPersister.DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task
+                    + " persistable=" + task.isPersistable);
+            final ActivityStack stack = task.getStack();
+            if ((task.isPersistable || task.inRecents)
+                    && (stack == null || !stack.isHomeOrRecentsStack())) {
+                if (TaskPersister.DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task);
+                persistentTaskIds.add(task.taskId);
+            } else {
+                if (TaskPersister.DEBUG) Slog.d(TAG, "omitting from persistentTaskIds task="
+                        + task);
+            }
+        }
+    }
+
+    @VisibleForTesting
+    ArrayList<TaskRecord> getRawTasks() {
+        return mTasks;
+    }
+
+    /**
+     * @return the task in the task list with the given {@param id} if one exists.
+     */
+    TaskRecord getTask(int id) {
+        final int recentsCount = mTasks.size();
+        for (int i = 0; i < recentsCount; i++) {
+            TaskRecord tr = mTasks.get(i);
+            if (tr.taskId == id) {
+                return tr;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Add a new task to the recent tasks list.
+     */
+    void add(TaskRecord task) {
+        if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "add: task=" + task);
+
+        final boolean isAffiliated = task.mAffiliatedTaskId != task.taskId
+                || task.mNextAffiliateTaskId != INVALID_TASK_ID
+                || task.mPrevAffiliateTaskId != INVALID_TASK_ID;
+
+        int recentsCount = mTasks.size();
+        // Quick case: never add voice sessions.
+        // TODO: VI what about if it's just an activity?
+        // Probably nothing to do here
+        if (task.voiceSession != null) {
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+                    "addRecent: not adding voice interaction " + task);
+            return;
+        }
+        // Another quick case: check if the top-most recent task is the same.
+        if (!isAffiliated && recentsCount > 0 && mTasks.get(0) == task) {
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: already at top: " + task);
+            return;
+        }
+        // Another quick case: check if this is part of a set of affiliated
+        // tasks that are at the top.
+        if (isAffiliated && recentsCount > 0 && task.inRecents
+                && task.mAffiliatedTaskId == mTasks.get(0).mAffiliatedTaskId) {
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: affiliated " + mTasks.get(0)
+                    + " at top when adding " + task);
+            return;
+        }
+
+        boolean needAffiliationFix = false;
+
+        // Slightly less quick case: the task is already in recents, so all we need
+        // to do is move it.
+        if (task.inRecents) {
+            int taskIndex = mTasks.indexOf(task);
+            if (taskIndex >= 0) {
+                if (!isAffiliated || !MOVE_AFFILIATED_TASKS_TO_FRONT) {
+                    // Simple case: this is not an affiliated task, so we just move it to the front.
+                    mTasks.remove(taskIndex);
+                    mTasks.add(0, task);
+                    notifyTaskPersisterLocked(task, false);
+                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving to top " + task
+                            + " from " + taskIndex);
+                    return;
+                } else {
+                    // More complicated: need to keep all affiliated tasks together.
+                    if (moveAffiliatedTasksToFront(task, taskIndex)) {
+                        // All went well.
+                        return;
+                    }
+
+                    // Uh oh...  something bad in the affiliation chain, try to rebuild
+                    // everything and then go through our general path of adding a new task.
+                    needAffiliationFix = true;
+                }
+            } else {
+                Slog.wtf(TAG, "Task with inRecent not in recents: " + task);
+                needAffiliationFix = true;
+            }
+        }
+
+        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: trimming tasks for " + task);
+        trimForAddTask(task);
+
+        task.inRecents = true;
+        if (!isAffiliated || needAffiliationFix) {
+            // If this is a simple non-affiliated task, or we had some failure trying to
+            // handle it as part of an affilated task, then just place it at the top.
+            mTasks.add(0, task);
+            notifyTaskAdded(task);
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding " + task);
+        } else if (isAffiliated) {
+            // If this is a new affiliated task, then move all of the affiliated tasks
+            // to the front and insert this new one.
+            TaskRecord other = task.mNextAffiliate;
+            if (other == null) {
+                other = task.mPrevAffiliate;
+            }
+            if (other != null) {
+                int otherIndex = mTasks.indexOf(other);
+                if (otherIndex >= 0) {
+                    // Insert new task at appropriate location.
+                    int taskIndex;
+                    if (other == task.mNextAffiliate) {
+                        // We found the index of our next affiliation, which is who is
+                        // before us in the list, so add after that point.
+                        taskIndex = otherIndex+1;
+                    } else {
+                        // We found the index of our previous affiliation, which is who is
+                        // after us in the list, so add at their position.
+                        taskIndex = otherIndex;
+                    }
+                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+                            "addRecent: new affiliated task added at " + taskIndex + ": " + task);
+                    mTasks.add(taskIndex, task);
+                    notifyTaskAdded(task);
+
+                    // Now move everything to the front.
+                    if (moveAffiliatedTasksToFront(task, taskIndex)) {
+                        // All went well.
+                        return;
+                    }
+
+                    // Uh oh...  something bad in the affiliation chain, try to rebuild
+                    // everything and then go through our general path of adding a new task.
+                    needAffiliationFix = true;
+                } else {
+                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+                            "addRecent: couldn't find other affiliation " + other);
+                    needAffiliationFix = true;
+                }
+            } else {
+                if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+                        "addRecent: adding affiliated task without next/prev:" + task);
+                needAffiliationFix = true;
+            }
+        }
+
+        if (needAffiliationFix) {
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: regrouping affiliations");
+            cleanupLocked(task.userId);
+        }
+
+        // Trim the set of tasks to the active set
+        trimInactiveRecentTasks();
+    }
+
+    /**
+     * Add the task to the bottom if possible.
+     */
+    boolean addToBottom(TaskRecord task) {
+        if (!canAddTaskWithoutTrim(task)) {
+            // Adding this task would cause the task to be removed (since it's appended at
+            // the bottom and would be trimmed) so just return now
+            return false;
+        }
+
+        add(task);
+        return true;
+    }
+
+    /**
+     * Remove a task from the recent tasks list.
+     */
+    void remove(TaskRecord task) {
+        mTasks.remove(task);
+        notifyTaskRemoved(task, !TRIMMED);
+    }
+
+    /**
+     * Trims the recents task list to the global max number of recents.
+     */
+    private void trimInactiveRecentTasks() {
+        int recentsCount = mTasks.size();
+
+        // Remove from the end of the list until we reach the max number of recents
+        while (recentsCount > mGlobalMaxNumTasks) {
+            final TaskRecord tr = mTasks.remove(recentsCount - 1);
+            notifyTaskRemoved(tr, TRIMMED);
+            recentsCount--;
+            if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming over max-recents task=" + tr
+                    + " max=" + mGlobalMaxNumTasks);
+        }
+
+        // Remove any tasks that belong to currently quiet profiles
+        final int[] profileUserIds = mUserController.getCurrentProfileIds();
+        mTmpQuietProfileUserIds.clear();
+        for (int userId : profileUserIds) {
+            final UserInfo userInfo = mUserController.getUserInfo(userId);
+            if (userInfo != null && userInfo.isManagedProfile() && userInfo.isQuietModeEnabled()) {
+                mTmpQuietProfileUserIds.put(userId, true);
+            }
+            if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "User: " + userInfo
+                    + " quiet=" + mTmpQuietProfileUserIds.get(userId));
+        }
+
+        // Remove any inactive tasks, calculate the latest set of visible tasks
+        int numVisibleTasks = 0;
+        for (int i = 0; i < mTasks.size();) {
+            final TaskRecord task = mTasks.get(i);
+
+            if (isActiveRecentTask(task, mTmpQuietProfileUserIds)) {
+                if (!mHasVisibleRecentTasks) {
+                    // Keep all active tasks if visible recent tasks is not supported
+                    i++;
+                    continue;
+                }
+
+                if (!isVisibleRecentTask(task)) {
+                    // Keep all active-but-invisible tasks
+                    i++;
+                    continue;
+                } else {
+                    numVisibleTasks++;
+                    if (isInVisibleRange(task, numVisibleTasks)) {
+                        // Keep visible tasks in range
+                        i++;
+                        continue;
+                    } else {
+                        // Fall through to trim visible tasks that are no longer in range
+                        if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG,
+                                "Trimming out-of-range visible task=" + task);
+                    }
+                }
+            } else {
+                // Fall through to trim inactive tasks
+                if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming inactive task=" + task);
+            }
+
+            // Task is no longer active, trim it from the list
+            mTasks.remove(task);
+            notifyTaskRemoved(task, TRIMMED);
+            notifyTaskPersisterLocked(task, false /* flush */);
+        }
+    }
+
+    /**
+     * @return whether the given task should be considered active.
+     */
+    private boolean isActiveRecentTask(TaskRecord task, SparseBooleanArray quietProfileUserIds) {
+        if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "isActiveRecentTask: task=" + task
+                + " globalMax=" + mGlobalMaxNumTasks);
+
+        if (quietProfileUserIds.get(task.userId)) {
+            // Quiet profile user's tasks are never active
+            if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\tisQuietProfileTask=true");
+            return false;
+        }
+
+        if (task.mAffiliatedTaskId != INVALID_TASK_ID && task.mAffiliatedTaskId != task.taskId) {
+            // Keep the task active if its affiliated task is also active
+            final TaskRecord affiliatedTask = getTask(task.mAffiliatedTaskId);
+            if (affiliatedTask != null) {
+                if (!isActiveRecentTask(affiliatedTask, quietProfileUserIds)) {
+                    if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG,
+                            "\taffiliatedWithTask=" + affiliatedTask + " is not active");
+                    return false;
+                }
+            }
+        }
+
+        // All other tasks are considered active
+        return true;
+    }
+
+    /**
+     * @return whether the given active task should be presented to the user through SystemUI.
+     */
+    private boolean isVisibleRecentTask(TaskRecord task) {
+        if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "isVisibleRecentTask: task=" + task
+                + " minVis=" + mMinNumVisibleTasks + " maxVis=" + mMaxNumVisibleTasks
+                + " sessionDuration=" + mActiveTasksSessionDurationMs
+                + " inactiveDuration=" + task.getInactiveDuration()
+                + " activityType=" + task.getActivityType()
+                + " windowingMode=" + task.getWindowingMode());
+
+        // Ignore certain activity types completely
+        switch (task.getActivityType()) {
+            case ACTIVITY_TYPE_HOME:
+            case ACTIVITY_TYPE_RECENTS:
+                return false;
+        }
+
+        // Ignore certain windowing modes
+        switch (task.getWindowingMode()) {
+            case WINDOWING_MODE_PINNED:
+                return false;
+            case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
+                if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\ttop=" + task.getStack().topTask());
+                final ActivityStack stack = task.getStack();
+                if (stack != null && stack.topTask() == task) {
+                    // Only the non-top task of the primary split screen mode is visible
+                    return false;
+                }
+        }
+
+        return true;
+    }
+
+    /**
+     * @return whether the given visible task is within the policy range.
+     */
+    private boolean isInVisibleRange(TaskRecord task, int numVisibleTasks) {
+        // Keep the last most task even if it is excluded from recents
+        final boolean isExcludeFromRecents =
+                (task.getBaseIntent().getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+                        == Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+        if (isExcludeFromRecents) {
+            if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\texcludeFromRecents=true");
+            return numVisibleTasks == 1;
+        }
+
+        if (mMinNumVisibleTasks >= 0 && numVisibleTasks <= mMinNumVisibleTasks) {
+            // Always keep up to the min number of recent tasks, after that fall through to the
+            // checks below
+            return true;
+        }
+
+        if (mMaxNumVisibleTasks >= 0) {
+            // Always keep up to the max number of recent tasks, but return false afterwards
+            return numVisibleTasks <= mMaxNumVisibleTasks;
+        }
+
+        if (mActiveTasksSessionDurationMs > 0) {
+            // Keep the task if the inactive time is within the session window, this check must come
+            // after the checks for the min/max visible task range
+            if (task.getInactiveDuration() <= mActiveTasksSessionDurationMs) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * If needed, remove oldest existing entries in recents that are for the same kind
+     * of task as the given one.
+     */
+    private void trimForAddTask(TaskRecord task) {
+        final int removeIndex = findTrimIndexForAddTask(task);
+        if (removeIndex == -1) {
+            // Nothing to trim
+            return;
+        }
+
+        // There is a similar task that will be removed for the addition of {@param task}, but it
+        // can be the same task, and if so, the task will be re-added in add(), so skip the
+        // callbacks here.
+        final TaskRecord removedTask = mTasks.remove(removeIndex);
+        if (removedTask != task) {
+            notifyTaskRemoved(removedTask, TRIMMED);
+            if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming task=" + removedTask
+                    + " for addition of task=" + task);
+        }
+        notifyTaskPersisterLocked(removedTask, false /* flush */);
+    }
+
+    /**
+     * Find the task that would be removed if the given {@param task} is added to the recent tasks
+     * list (if any).
+     */
+    private int findTrimIndexForAddTask(TaskRecord task) {
+        int recentsCount = mTasks.size();
+        final Intent intent = task.intent;
+        final boolean document = intent != null && intent.isDocument();
+        int maxRecents = task.maxRecents - 1;
+        final ActivityStack stack = task.getStack();
+        for (int i = 0; i < recentsCount; i++) {
+            final TaskRecord tr = mTasks.get(i);
+            final ActivityStack trStack = tr.getStack();
+
+            if (task != tr) {
+                if (stack != null && trStack != null && stack != trStack) {
+                    continue;
+                }
+                if (task.userId != tr.userId) {
+                    continue;
+                }
+                final Intent trIntent = tr.intent;
+                final boolean sameAffinity =
+                        task.affinity != null && task.affinity.equals(tr.affinity);
+                final boolean sameIntent = intent != null && intent.filterEquals(trIntent);
+                boolean multiTasksAllowed = false;
+                final int flags = intent.getFlags();
+                if ((flags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NEW_DOCUMENT)) != 0
+                        && (flags & FLAG_ACTIVITY_MULTIPLE_TASK) != 0) {
+                    multiTasksAllowed = true;
+                }
+                final boolean trIsDocument = trIntent != null && trIntent.isDocument();
+                final boolean bothDocuments = document && trIsDocument;
+                if (!sameAffinity && !sameIntent && !bothDocuments) {
+                    continue;
+                }
+
+                if (bothDocuments) {
+                    // Do these documents belong to the same activity?
+                    final boolean sameActivity = task.realActivity != null
+                            && tr.realActivity != null
+                            && task.realActivity.equals(tr.realActivity);
+                    if (!sameActivity) {
+                        // If the document is open in another app or is not the same document, we
+                        // don't need to trim it.
+                        continue;
+                    } else if (maxRecents > 0) {
+                        // Otherwise only trim if we are over our max recents for this task
+                        --maxRecents;
+                        if (!sameIntent || multiTasksAllowed) {
+                            // We don't want to trim if we are not over the max allowed entries and
+                            // the tasks are not of the same intent filter, or multiple entries for
+                            // the task is allowed.
+                            continue;
+                        }
+                    }
+                    // Hit the maximum number of documents for this task. Fall through
+                    // and remove this document from recents.
+                } else if (document || trIsDocument) {
+                    // Only one of these is a document. Not the droid we're looking for.
+                    continue;
+                }
+            }
+            return i;
+        }
+        return -1;
+    }
+
+    // Extract the affiliates of the chain containing recent at index start.
+    private int processNextAffiliateChainLocked(int start) {
+        final TaskRecord startTask = mTasks.get(start);
+        final int affiliateId = startTask.mAffiliatedTaskId;
+
+        // Quick identification of isolated tasks. I.e. those not launched behind.
+        if (startTask.taskId == affiliateId && startTask.mPrevAffiliate == null &&
+                startTask.mNextAffiliate == null) {
+            // There is still a slim chance that there are other tasks that point to this task
+            // and that the chain is so messed up that this task no longer points to them but
+            // the gain of this optimization outweighs the risk.
+            startTask.inRecents = true;
+            return start + 1;
+        }
+
+        // Remove all tasks that are affiliated to affiliateId and put them in mTmpRecents.
+        mTmpRecents.clear();
+        for (int i = mTasks.size() - 1; i >= start; --i) {
+            final TaskRecord task = mTasks.get(i);
+            if (task.mAffiliatedTaskId == affiliateId) {
+                mTasks.remove(i);
+                mTmpRecents.add(task);
+            }
+        }
+
+        // Sort them all by taskId. That is the order they were create in and that order will
+        // always be correct.
+        Collections.sort(mTmpRecents, TASK_ID_COMPARATOR);
+
+        // Go through and fix up the linked list.
+        // The first one is the end of the chain and has no next.
+        final TaskRecord first = mTmpRecents.get(0);
+        first.inRecents = true;
+        if (first.mNextAffiliate != null) {
+            Slog.w(TAG, "Link error 1 first.next=" + first.mNextAffiliate);
+            first.setNextAffiliate(null);
+            notifyTaskPersisterLocked(first, false);
+        }
+        // Everything in the middle is doubly linked from next to prev.
+        final int tmpSize = mTmpRecents.size();
+        for (int i = 0; i < tmpSize - 1; ++i) {
+            final TaskRecord next = mTmpRecents.get(i);
+            final TaskRecord prev = mTmpRecents.get(i + 1);
+            if (next.mPrevAffiliate != prev) {
+                Slog.w(TAG, "Link error 2 next=" + next + " prev=" + next.mPrevAffiliate +
+                        " setting prev=" + prev);
+                next.setPrevAffiliate(prev);
+                notifyTaskPersisterLocked(next, false);
+            }
+            if (prev.mNextAffiliate != next) {
+                Slog.w(TAG, "Link error 3 prev=" + prev + " next=" + prev.mNextAffiliate +
+                        " setting next=" + next);
+                prev.setNextAffiliate(next);
+                notifyTaskPersisterLocked(prev, false);
+            }
+            prev.inRecents = true;
+        }
+        // The last one is the beginning of the list and has no prev.
+        final TaskRecord last = mTmpRecents.get(tmpSize - 1);
+        if (last.mPrevAffiliate != null) {
+            Slog.w(TAG, "Link error 4 last.prev=" + last.mPrevAffiliate);
+            last.setPrevAffiliate(null);
+            notifyTaskPersisterLocked(last, false);
+        }
+
+        // Insert the group back into mTmpTasks at start.
+        mTasks.addAll(start, mTmpRecents);
+        mTmpRecents.clear();
+
+        // Let the caller know where we left off.
+        return start + tmpSize;
+    }
+
+    private boolean moveAffiliatedTasksToFront(TaskRecord task, int taskIndex) {
+        int recentsCount = mTasks.size();
         TaskRecord top = task;
         int topIndex = taskIndex;
         while (top.mNextAffiliate != null && topIndex > 0) {
@@ -412,7 +1238,7 @@
         int endIndex = topIndex;
         TaskRecord prev = top;
         while (endIndex < recentsCount) {
-            TaskRecord cur = get(endIndex);
+            TaskRecord cur = mTasks.get(endIndex);
             if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: looking at next chain @"
                     + endIndex + " " + cur);
             if (cur == top) {
@@ -487,8 +1313,8 @@
             for (int i=topIndex; i<=endIndex; i++) {
                 if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving affiliated " + task
                         + " from " + i + " to " + (i-topIndex));
-                TaskRecord cur = remove(i);
-                add(i - topIndex, cur);
+                TaskRecord cur = mTasks.remove(i);
+                mTasks.add(i - topIndex, cur);
             }
             if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: done moving tasks  " +  topIndex
                     + " to " + endIndex);
@@ -499,301 +1325,87 @@
         return false;
     }
 
-    final void addLocked(TaskRecord task) {
-        final boolean isAffiliated = task.mAffiliatedTaskId != task.taskId
-                || task.mNextAffiliateTaskId != INVALID_TASK_ID
-                || task.mPrevAffiliateTaskId != INVALID_TASK_ID;
-
-        int recentsCount = size();
-        // Quick case: never add voice sessions.
-        // TODO: VI what about if it's just an activity?
-        // Probably nothing to do here
-        if (task.voiceSession != null) {
-            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
-                    "addRecent: not adding voice interaction " + task);
-            return;
-        }
-        // Another quick case: check if the top-most recent task is the same.
-        if (!isAffiliated && recentsCount > 0 && get(0) == task) {
-            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: already at top: " + task);
-            return;
-        }
-        // Another quick case: check if this is part of a set of affiliated
-        // tasks that are at the top.
-        if (isAffiliated && recentsCount > 0 && task.inRecents
-                && task.mAffiliatedTaskId == get(0).mAffiliatedTaskId) {
-            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: affiliated " + get(0)
-                    + " at top when adding " + task);
+    void dump(PrintWriter pw, boolean dumpAll, String dumpPackage) {
+        pw.println("ACTIVITY MANAGER RECENT TASKS (dumpsys activity recents)");
+        if (mTasks.isEmpty()) {
             return;
         }
 
-        boolean needAffiliationFix = false;
+        final MutableBoolean printedAnything = new MutableBoolean(false);
+        final MutableBoolean printedHeader = new MutableBoolean(false);
+        final int size = mTasks.size();
+        for (int i = 0; i < size; i++) {
+            final TaskRecord tr = mTasks.get(i);
+            if (dumpPackage != null && (tr.realActivity == null ||
+                    !dumpPackage.equals(tr.realActivity.getPackageName()))) {
+                continue;
+            }
 
-        // Slightly less quick case: the task is already in recents, so all we need
-        // to do is move it.
-        if (task.inRecents) {
-            int taskIndex = indexOf(task);
-            if (taskIndex >= 0) {
-                if (!isAffiliated || MOVE_AFFILIATED_TASKS_TO_FRONT) {
-                    // Simple case: this is not an affiliated task, so we just move it to the front.
-                    remove(taskIndex);
-                    add(0, task);
-                    notifyTaskPersisterLocked(task, false);
-                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving to top " + task
-                            + " from " + taskIndex);
-                    return;
-                } else {
-                    // More complicated: need to keep all affiliated tasks together.
-                    if (moveAffiliatedTasksToFront(task, taskIndex)) {
-                        // All went well.
-                        return;
-                    }
-
-                    // Uh oh...  something bad in the affiliation chain, try to rebuild
-                    // everything and then go through our general path of adding a new task.
-                    needAffiliationFix = true;
-                }
-            } else {
-                Slog.wtf(TAG, "Task with inRecent not in recents: " + task);
-                needAffiliationFix = true;
+            if (!printedHeader.value) {
+                pw.println("  Recent tasks:");
+                printedHeader.value = true;
+                printedAnything.value = true;
+            }
+            pw.print("  * Recent #"); pw.print(i); pw.print(": ");
+            pw.println(tr);
+            if (dumpAll) {
+                tr.dump(pw, "    ");
             }
         }
 
-        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: trimming tasks for " + task);
-        trimForTaskLocked(task, true);
-
-        recentsCount = size();
-        final int maxRecents = ActivityManager.getMaxRecentTasksStatic();
-        while (recentsCount >= maxRecents) {
-            final TaskRecord tr = remove(recentsCount - 1);
-            tr.removedFromRecents();
-            recentsCount--;
-        }
-        task.inRecents = true;
-        if (!isAffiliated || needAffiliationFix) {
-            // If this is a simple non-affiliated task, or we had some failure trying to
-            // handle it as part of an affilated task, then just place it at the top.
-            add(0, task);
-            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding " + task);
-        } else if (isAffiliated) {
-            // If this is a new affiliated task, then move all of the affiliated tasks
-            // to the front and insert this new one.
-            TaskRecord other = task.mNextAffiliate;
-            if (other == null) {
-                other = task.mPrevAffiliate;
-            }
-            if (other != null) {
-                int otherIndex = indexOf(other);
-                if (otherIndex >= 0) {
-                    // Insert new task at appropriate location.
-                    int taskIndex;
-                    if (other == task.mNextAffiliate) {
-                        // We found the index of our next affiliation, which is who is
-                        // before us in the list, so add after that point.
-                        taskIndex = otherIndex+1;
-                    } else {
-                        // We found the index of our previous affiliation, which is who is
-                        // after us in the list, so add at their position.
-                        taskIndex = otherIndex;
-                    }
-                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
-                            "addRecent: new affiliated task added at " + taskIndex + ": " + task);
-                    add(taskIndex, task);
-
-                    // Now move everything to the front.
-                    if (moveAffiliatedTasksToFront(task, taskIndex)) {
-                        // All went well.
-                        return;
-                    }
-
-                    // Uh oh...  something bad in the affiliation chain, try to rebuild
-                    // everything and then go through our general path of adding a new task.
-                    needAffiliationFix = true;
-                } else {
-                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
-                            "addRecent: couldn't find other affiliation " + other);
-                    needAffiliationFix = true;
-                }
-            } else {
-                if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
-                        "addRecent: adding affiliated task without next/prev:" + task);
-                needAffiliationFix = true;
-            }
-        }
-
-        if (needAffiliationFix) {
-            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: regrouping affiliations");
-            cleanupLocked(task.userId);
+        if (!printedAnything.value) {
+            pw.println("  (nothing)");
         }
     }
 
     /**
-     * If needed, remove oldest existing entries in recents that are for the same kind
-     * of task as the given one.
+     * Creates a new RecentTaskInfo from a TaskRecord.
      */
-    int trimForTaskLocked(TaskRecord task, boolean doTrim) {
-        int recentsCount = size();
-        final Intent intent = task.intent;
-        final boolean document = intent != null && intent.isDocument();
-        int maxRecents = task.maxRecents - 1;
-        final ActivityStack stack = task.getStack();
-        for (int i = 0; i < recentsCount; i++) {
-            final TaskRecord tr = get(i);
-            final ActivityStack trStack = tr.getStack();
-            if (task != tr) {
-                if (stack != null && trStack != null && stack != trStack) {
-                    continue;
-                }
-                if (task.userId != tr.userId) {
-                    continue;
-                }
-                final Intent trIntent = tr.intent;
-                final boolean sameAffinity =
-                        task.affinity != null && task.affinity.equals(tr.affinity);
-                final boolean sameIntentFilter = intent != null && intent.filterEquals(trIntent);
-                boolean multiTasksAllowed = false;
-                final int flags = intent.getFlags();
-                if ((flags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NEW_DOCUMENT)) != 0
-                        && (flags & FLAG_ACTIVITY_MULTIPLE_TASK) != 0) {
-                    multiTasksAllowed = true;
-                }
-                final boolean trIsDocument = trIntent != null && trIntent.isDocument();
-                final boolean bothDocuments = document && trIsDocument;
-                if (!sameAffinity && !sameIntentFilter && !bothDocuments) {
-                    continue;
-                }
+    static ActivityManager.RecentTaskInfo createRecentTaskInfo(TaskRecord tr) {
+        // Update the task description to reflect any changes in the task stack
+        tr.updateTaskDescription();
 
-                if (bothDocuments) {
-                    // Do these documents belong to the same activity?
-                    final boolean sameActivity = task.realActivity != null
-                            && tr.realActivity != null
-                            && task.realActivity.equals(tr.realActivity);
-                    // If the document is open in another app or is not the same
-                    // document, we don't need to trim it.
-                    if (!sameActivity) {
-                        continue;
-                    // Otherwise only trim if we are over our max recents for this task
-                    } else if (maxRecents > 0) {
-                        --maxRecents;
-                        if (!doTrim || !sameIntentFilter || multiTasksAllowed) {
-                            // We don't want to trim if we are not over the max allowed entries and
-                            // the caller doesn't want us to trim, the tasks are not of the same
-                            // intent filter, or multiple entries fot the task is allowed.
-                            continue;
-                        }
-                    }
-                    // Hit the maximum number of documents for this task. Fall through
-                    // and remove this document from recents.
-                } else if (document || trIsDocument) {
-                    // Only one of these is a document. Not the droid we're looking for.
-                    continue;
-                }
-            }
+        // Compose the recent task info
+        ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
+        rti.id = tr.getTopActivity() == null ? INVALID_TASK_ID : tr.taskId;
+        rti.persistentId = tr.taskId;
+        rti.baseIntent = new Intent(tr.getBaseIntent());
+        rti.origActivity = tr.origActivity;
+        rti.realActivity = tr.realActivity;
+        rti.description = tr.lastDescription;
+        rti.stackId = tr.getStackId();
+        rti.userId = tr.userId;
+        rti.taskDescription = new ActivityManager.TaskDescription(tr.lastTaskDescription);
+        rti.lastActiveTime = tr.lastActiveTime;
+        rti.affiliatedTaskId = tr.mAffiliatedTaskId;
+        rti.affiliatedTaskColor = tr.mAffiliatedTaskColor;
+        rti.numActivities = 0;
+        if (tr.mBounds != null) {
+            rti.bounds = new Rect(tr.mBounds);
+        }
+        rti.supportsSplitScreenMultiWindow = tr.supportsSplitScreenWindowingMode();
+        rti.resizeMode = tr.mResizeMode;
+        rti.configuration.setTo(tr.getConfiguration());
 
-            if (!doTrim) {
-                // If the caller is not actually asking for a trim, just tell them we reached
-                // a point where the trim would happen.
-                return i;
-            }
+        ActivityRecord base = null;
+        ActivityRecord top = null;
+        ActivityRecord tmp;
 
-            // Either task and tr are the same or, their affinities match or their intents match
-            // and neither of them is a document, or they are documents using the same activity
-            // and their maxRecents has been reached.
-            remove(i);
-            if (task != tr) {
-                tr.removedFromRecents();
+        for (int i = tr.mActivities.size() - 1; i >= 0; --i) {
+            tmp = tr.mActivities.get(i);
+            if (tmp.finishing) {
+                continue;
             }
-            i--;
-            recentsCount--;
-            if (task.intent == null) {
-                // If the new recent task we are adding is not fully
-                // specified, then replace it with the existing recent task.
-                task = tr;
+            base = tmp;
+            if (top == null || (top.state == ActivityState.INITIALIZING)) {
+                top = base;
             }
-            notifyTaskPersisterLocked(tr, false);
+            rti.numActivities++;
         }
 
-        return -1;
-    }
+        rti.baseActivity = (base != null) ? base.intent.getComponent() : null;
+        rti.topActivity = (top != null) ? top.intent.getComponent() : null;
 
-    // Sort by taskId
-    private static Comparator<TaskRecord> sTaskRecordComparator = new Comparator<TaskRecord>() {
-        @Override
-        public int compare(TaskRecord lhs, TaskRecord rhs) {
-            return rhs.taskId - lhs.taskId;
-        }
-    };
-
-    // Extract the affiliates of the chain containing recent at index start.
-    private int processNextAffiliateChainLocked(int start) {
-        final TaskRecord startTask = get(start);
-        final int affiliateId = startTask.mAffiliatedTaskId;
-
-        // Quick identification of isolated tasks. I.e. those not launched behind.
-        if (startTask.taskId == affiliateId && startTask.mPrevAffiliate == null &&
-                startTask.mNextAffiliate == null) {
-            // There is still a slim chance that there are other tasks that point to this task
-            // and that the chain is so messed up that this task no longer points to them but
-            // the gain of this optimization outweighs the risk.
-            startTask.inRecents = true;
-            return start + 1;
-        }
-
-        // Remove all tasks that are affiliated to affiliateId and put them in mTmpRecents.
-        mTmpRecents.clear();
-        for (int i = size() - 1; i >= start; --i) {
-            final TaskRecord task = get(i);
-            if (task.mAffiliatedTaskId == affiliateId) {
-                remove(i);
-                mTmpRecents.add(task);
-            }
-        }
-
-        // Sort them all by taskId. That is the order they were create in and that order will
-        // always be correct.
-        Collections.sort(mTmpRecents, sTaskRecordComparator);
-
-        // Go through and fix up the linked list.
-        // The first one is the end of the chain and has no next.
-        final TaskRecord first = mTmpRecents.get(0);
-        first.inRecents = true;
-        if (first.mNextAffiliate != null) {
-            Slog.w(TAG, "Link error 1 first.next=" + first.mNextAffiliate);
-            first.setNextAffiliate(null);
-            notifyTaskPersisterLocked(first, false);
-        }
-        // Everything in the middle is doubly linked from next to prev.
-        final int tmpSize = mTmpRecents.size();
-        for (int i = 0; i < tmpSize - 1; ++i) {
-            final TaskRecord next = mTmpRecents.get(i);
-            final TaskRecord prev = mTmpRecents.get(i + 1);
-            if (next.mPrevAffiliate != prev) {
-                Slog.w(TAG, "Link error 2 next=" + next + " prev=" + next.mPrevAffiliate +
-                        " setting prev=" + prev);
-                next.setPrevAffiliate(prev);
-                notifyTaskPersisterLocked(next, false);
-            }
-            if (prev.mNextAffiliate != next) {
-                Slog.w(TAG, "Link error 3 prev=" + prev + " next=" + prev.mNextAffiliate +
-                        " setting next=" + next);
-                prev.setNextAffiliate(next);
-                notifyTaskPersisterLocked(prev, false);
-            }
-            prev.inRecents = true;
-        }
-        // The last one is the beginning of the list and has no prev.
-        final TaskRecord last = mTmpRecents.get(tmpSize - 1);
-        if (last.mPrevAffiliate != null) {
-            Slog.w(TAG, "Link error 4 last.prev=" + last.mPrevAffiliate);
-            last.setPrevAffiliate(null);
-            notifyTaskPersisterLocked(last, false);
-        }
-
-        // Insert the group back into mRecentTasks at start.
-        addAll(start, mTmpRecents);
-        mTmpRecents.clear();
-
-        // Let the caller know where we left off.
-        return start + tmpSize;
+        return rti;
     }
 }
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 61994b5..2689d6a 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -567,7 +567,7 @@
         SparseArray<SparseBooleanArray> changedTaskIdsPerUser = new SparseArray<>();
         synchronized (mService) {
             for (int userId : mRecentTasks.usersWithRecentsLoadedLocked()) {
-                SparseBooleanArray taskIdsToSave = mRecentTasks.mPersistedTaskIds.get(userId);
+                SparseBooleanArray taskIdsToSave = mRecentTasks.getTaskIdsForUser(userId);
                 SparseBooleanArray persistedIdsInFile = mTaskIdsInFile.get(userId);
                 if (persistedIdsInFile != null && persistedIdsInFile.equals(taskIdsToSave)) {
                     continue;
@@ -640,7 +640,7 @@
         @Override
         public void run() {
             Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-            ArraySet<Integer> persistentTaskIds = new ArraySet<Integer>();
+            ArraySet<Integer> persistentTaskIds = new ArraySet<>();
             while (true) {
                 // We can't lock mService while holding TaskPersister.this, but we don't want to
                 // call removeObsoleteFiles every time through the loop, only the last time before
@@ -654,20 +654,7 @@
                     persistentTaskIds.clear();
                     synchronized (mService) {
                         if (DEBUG) Slog.d(TAG, "mRecents=" + mRecentTasks);
-                        for (int taskNdx = mRecentTasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                            final TaskRecord task = mRecentTasks.get(taskNdx);
-                            if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task +
-                                    " persistable=" + task.isPersistable);
-                            final ActivityStack stack = task.getStack();
-                            if ((task.isPersistable || task.inRecents)
-                                    && (stack == null || !stack.isHomeOrRecentsStack())) {
-                                if (DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task);
-                                persistentTaskIds.add(task.taskId);
-                            } else {
-                                if (DEBUG) Slog.d(TAG,
-                                        "omitting from persistentTaskIds task=" + task);
-                            }
-                        }
+                        mRecentTasks.getPersistableTaskIds(persistentTaskIds);
                         mService.mWindowManager.removeObsoleteTaskFiles(persistentTaskIds,
                                 mRecentTasks.usersWithRecentsLoadedLocked());
                     }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 5491da10..c451235 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -43,7 +43,6 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
-import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
 import static android.view.Display.DEFAULT_DISPLAY;
@@ -61,6 +60,7 @@
 import static com.android.server.am.ActivityRecord.STARTING_WINDOW_SHOWN;
 import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING;
 import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING_TO_TOP;
+import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
 import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY;
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.am.proto.TaskRecordProto.ACTIVITIES;
@@ -84,7 +84,6 @@
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.ActivityManager;
-import android.app.ActivityManager.StackId;
 import android.app.ActivityManager.TaskDescription;
 import android.app.ActivityManager.TaskSnapshot;
 import android.app.ActivityOptions;
@@ -100,6 +99,7 @@
 import android.graphics.Rect;
 import android.os.Debug;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -153,8 +153,6 @@
     private static final String ATTR_EFFECTIVE_UID = "effective_uid";
     @Deprecated
     private static final String ATTR_TASKTYPE = "task_type";
-    private static final String ATTR_FIRSTACTIVETIME = "first_active_time";
-    private static final String ATTR_LASTACTIVETIME = "last_active_time";
     private static final String ATTR_LASTDESCRIPTION = "last_description";
     private static final String ATTR_LASTTIMEMOVED = "last_time_moved";
     private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity";
@@ -166,7 +164,6 @@
     private static final String ATTR_CALLING_PACKAGE = "calling_package";
     private static final String ATTR_SUPPORTS_PICTURE_IN_PICTURE = "supports_picture_in_picture";
     private static final String ATTR_RESIZE_MODE = "resize_mode";
-    private static final String ATTR_PRIVILEGED = "privileged";
     private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";
     private static final String ATTR_MIN_WIDTH = "min_width";
     private static final String ATTR_MIN_HEIGHT = "min_height";
@@ -210,9 +207,10 @@
     ComponentName realActivity; // The actual activity component that started the task.
     boolean realActivitySuspended; // True if the actual activity component that started the
                                    // task is suspended.
-    long firstActiveTime;   // First time this task was active.
-    long lastActiveTime;    // Last time this task was active, including sleep.
     boolean inRecents;      // Actually in the recents list?
+    long lastActiveTime;    // Last time this task was active in the current device session,
+                            // including sleep. This time is initialized to the elapsed time when
+                            // restored from disk.
     boolean isAvailable;    // Is the activity available to be launched?
     boolean rootWasReset;   // True if the intent at the root of the task had
                             // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
@@ -235,10 +233,6 @@
             // of the root activity.
     boolean mTemporarilyUnresizable; // Separate flag from mResizeMode used to suppress resize
                                      // changes on a temporary basis.
-    private int mLockTaskMode;  // Which tasklock mode to launch this task in. One of
-                                // ActivityManager.LOCK_TASK_LAUNCH_MODE_*
-    private boolean mPrivileged;    // The root activity application of this task holds
-                                    // privileged permissions.
 
     /** Can't be put in lockTask mode. */
     final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
@@ -337,6 +331,7 @@
                 TaskPersister.IMAGE_EXTENSION;
         userId = UserHandle.getUserId(info.applicationInfo.uid);
         taskId = _taskId;
+        lastActiveTime = SystemClock.elapsedRealtime();
         mAffiliatedTaskId = _taskId;
         voiceSession = _voiceSession;
         voiceInteractor = _voiceInteractor;
@@ -357,6 +352,7 @@
                 TaskPersister.IMAGE_EXTENSION;
         userId = UserHandle.getUserId(info.applicationInfo.uid);
         taskId = _taskId;
+        lastActiveTime = SystemClock.elapsedRealtime();
         mAffiliatedTaskId = _taskId;
         voiceSession = null;
         voiceInteractor = null;
@@ -383,12 +379,11 @@
             ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
             boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId,
             int _effectiveUid, String _lastDescription, ArrayList<ActivityRecord> activities,
-            long _firstActiveTime, long _lastActiveTime, long lastTimeMoved,
-            boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription,
-            int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor,
-            int callingUid, String callingPackage, int resizeMode, boolean supportsPictureInPicture,
-            boolean privileged, boolean _realActivitySuspended, boolean userSetupComplete,
-            int minWidth, int minHeight) {
+            long lastTimeMoved, boolean neverRelinquishIdentity,
+            TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId,
+            int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
+            int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended,
+            boolean userSetupComplete, int minWidth, int minHeight) {
         mService = service;
         mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
                 TaskPersister.IMAGE_EXTENSION;
@@ -410,8 +405,7 @@
         userId = _userId;
         mUserSetupComplete = userSetupComplete;
         effectiveUid = _effectiveUid;
-        firstActiveTime = _firstActiveTime;
-        lastActiveTime = _lastActiveTime;
+        lastActiveTime = SystemClock.elapsedRealtime();
         lastDescription = _lastDescription;
         mActivities = activities;
         mLastTimeMoved = lastTimeMoved;
@@ -425,7 +419,6 @@
         mCallingPackage = callingPackage;
         mResizeMode = resizeMode;
         mSupportsPictureInPicture = supportsPictureInPicture;
-        mPrivileged = privileged;
         mMinWidth = minWidth;
         mMinHeight = minHeight;
         mService.mTaskChangeNotificationController.notifyTaskCreated(_taskId, realActivity);
@@ -520,7 +513,7 @@
             updateOverrideConfiguration(bounds);
             if (!inFreeformWindowingMode()) {
                 // re-restore the task so it can have the proper stack association.
-                mService.mStackSupervisor.restoreRecentTaskLocked(this, null);
+                mService.mStackSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP);
             }
             return true;
         }
@@ -657,7 +650,7 @@
             // In some cases the focused stack isn't the front stack. E.g. pinned stack.
             // Whenever we are moving the top activity from the front stack we want to make sure to
             // move the stack to the front.
-            final boolean wasFront = r != null && supervisor.isFrontStackOnDisplay(sourceStack)
+            final boolean wasFront = r != null && sourceStack.isTopStackOnDisplay()
                     && (sourceStack.topRunningActivityLocked() == r);
 
             // Adjust the position for the new parent stack as needed.
@@ -746,9 +739,9 @@
         }
 
         // TODO: Handle incorrect request to move before the actual move, not after.
-        final boolean inSplitScreenMode = supervisor.getDefaultDisplay().hasSplitScreenStack();
+        final boolean inSplitScreenMode = supervisor.getDefaultDisplay().hasSplitScreenPrimaryStack();
         supervisor.handleNonResizableTaskIfNeeded(this, preferredStack.getWindowingMode(),
-                DEFAULT_DISPLAY, toStack.mStackId);
+                DEFAULT_DISPLAY, toStack);
 
         boolean successful = (preferredStack == toStack);
         if (successful && toStack.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
@@ -789,14 +782,11 @@
     }
 
     void touchActiveTime() {
-        lastActiveTime = System.currentTimeMillis();
-        if (firstActiveTime == 0) {
-            firstActiveTime = lastActiveTime;
-        }
+        lastActiveTime = SystemClock.elapsedRealtime();
     }
 
     long getInactiveDuration() {
-        return System.currentTimeMillis() - lastActiveTime;
+        return SystemClock.elapsedRealtime() - lastActiveTime;
     }
 
     /** Sets the original intent, and the calling uid and package. */
@@ -804,6 +794,7 @@
         mCallingUid = r.launchedFromUid;
         mCallingPackage = r.launchedFromPackage;
         setIntent(r.intent, r.info);
+        setLockTaskAuth(r);
     }
 
     /** Sets the original intent, _without_ updating the calling uid or package. */
@@ -887,14 +878,6 @@
         }
         mResizeMode = info.resizeMode;
         mSupportsPictureInPicture = info.supportsPictureInPicture();
-        mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0;
-        mLockTaskMode = info.lockTaskLaunchMode;
-        if (!mPrivileged && (mLockTaskMode == LOCK_TASK_LAUNCH_MODE_ALWAYS
-                || mLockTaskMode == LOCK_TASK_LAUNCH_MODE_NEVER)) {
-            // Non-priv apps are not allowed to use always or never, fall back to default
-            mLockTaskMode = LOCK_TASK_LAUNCH_MODE_DEFAULT;
-        }
-        setLockTaskAuth();
     }
 
     /** Sets the original minimal width and height. */
@@ -1431,8 +1414,17 @@
     }
 
     void setLockTaskAuth() {
+        setLockTaskAuth(getRootActivity());
+    }
+
+    private void setLockTaskAuth(@Nullable ActivityRecord r) {
+        if (r == null) {
+            mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
+            return;
+        }
+
         final String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
-        switch (mLockTaskMode) {
+        switch (r.lockTaskLaunchMode) {
             case LOCK_TASK_LAUNCH_MODE_DEFAULT:
                 mLockTaskAuth = mService.mLockTaskController.isPackageWhitelisted(userId, pkg)
                         ? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
@@ -1568,6 +1560,7 @@
             // values in the TaskRecord.
             String label = null;
             String iconFilename = null;
+            int iconResource = -1;
             int colorPrimary = 0;
             int colorBackground = 0;
             int statusBarColor = 0;
@@ -1579,6 +1572,9 @@
                     if (label == null) {
                         label = r.taskDescription.getLabel();
                     }
+                    if (iconResource == -1) {
+                        iconResource = r.taskDescription.getIconResource();
+                    }
                     if (iconFilename == null) {
                         iconFilename = r.taskDescription.getIconFilename();
                     }
@@ -1593,8 +1589,8 @@
                 }
                 topActivity = false;
             }
-            lastTaskDescription = new TaskDescription(label, null, iconFilename, colorPrimary,
-                    colorBackground, statusBarColor, navigationBarColor);
+            lastTaskDescription = new TaskDescription(label, null, iconResource, iconFilename,
+                    colorPrimary, colorBackground, statusBarColor, navigationBarColor);
             if (mWindowContainerController != null) {
                 mWindowContainerController.setTaskDescription(lastTaskDescription);
             }
@@ -1656,8 +1652,6 @@
         out.attribute(null, ATTR_USERID, String.valueOf(userId));
         out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete));
         out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
-        out.attribute(null, ATTR_FIRSTACTIVETIME, String.valueOf(firstActiveTime));
-        out.attribute(null, ATTR_LASTACTIVETIME, String.valueOf(lastActiveTime));
         out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
         out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
         if (lastDescription != null) {
@@ -1675,7 +1669,6 @@
         out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
         out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE,
                 String.valueOf(mSupportsPictureInPicture));
-        out.attribute(null, ATTR_PRIVILEGED, String.valueOf(mPrivileged));
         if (mLastNonFullscreenBounds != null) {
             out.attribute(
                     null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
@@ -1730,8 +1723,6 @@
         boolean userSetupComplete = true;
         int effectiveUid = -1;
         String lastDescription = null;
-        long firstActiveTime = -1;
-        long lastActiveTime = -1;
         long lastTimeOnTop = 0;
         boolean neverRelinquishIdentity = true;
         int taskId = INVALID_TASK_ID;
@@ -1745,7 +1736,6 @@
         String callingPackage = "";
         int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
         boolean supportsPictureInPicture = false;
-        boolean privileged = false;
         Rect bounds = null;
         int minWidth = INVALID_MIN_SIZE;
         int minHeight = INVALID_MIN_SIZE;
@@ -1783,10 +1773,6 @@
                 effectiveUid = Integer.parseInt(attrValue);
             } else if (ATTR_TASKTYPE.equals(attrName)) {
                 taskType = Integer.parseInt(attrValue);
-            } else if (ATTR_FIRSTACTIVETIME.equals(attrName)) {
-                firstActiveTime = Long.parseLong(attrValue);
-            } else if (ATTR_LASTACTIVETIME.equals(attrName)) {
-                lastActiveTime = Long.parseLong(attrValue);
             } else if (ATTR_LASTDESCRIPTION.equals(attrName)) {
                 lastDescription = attrValue;
             } else if (ATTR_LASTTIMEMOVED.equals(attrName)) {
@@ -1811,8 +1797,6 @@
                 resizeMode = Integer.parseInt(attrValue);
             } else if (ATTR_SUPPORTS_PICTURE_IN_PICTURE.equals(attrName)) {
                 supportsPictureInPicture = Boolean.parseBoolean(attrValue);
-            } else if (ATTR_PRIVILEGED.equals(attrName)) {
-                privileged = Boolean.parseBoolean(attrValue);
             } else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) {
                 bounds = Rect.unflattenFromString(attrValue);
             } else if (ATTR_MIN_WIDTH.equals(attrName)) {
@@ -1897,10 +1881,10 @@
         final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent,
                 affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset,
                 autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription,
-                activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
-                taskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor,
-                callingUid, callingPackage, resizeMode, supportsPictureInPicture, privileged,
-                realActivitySuspended, userSetupComplete, minWidth, minHeight);
+                activities, lastTimeOnTop, neverRelinquishIdentity, taskDescription,
+                taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid,
+                callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended,
+                userSetupComplete, minWidth, minHeight);
         task.updateOverrideConfiguration(bounds);
 
         for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
@@ -2229,7 +2213,6 @@
                 pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode));
                 pw.print(" mSupportsPictureInPicture=" + mSupportsPictureInPicture);
                 pw.print(" isResizeable=" + isResizeable());
-                pw.print(" firstActiveTime=" + firstActiveTime);
                 pw.print(" lastActiveTime=" + lastActiveTime);
                 pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
     }
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 5a29594..4aa8adb9 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -67,6 +67,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.UserManagerInternal;
@@ -79,6 +80,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
+import android.util.TimingsTraceLog;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
@@ -232,6 +234,7 @@
         mUiHandler = mInjector.getUiHandler(this);
         // User 0 is the first and only user that runs at boot.
         final UserState uss = new UserState(UserHandle.SYSTEM);
+        uss.mUnlockProgress.addListener(new UserProgressListener());
         mStartedUsers.put(UserHandle.USER_SYSTEM, uss);
         mUserLru.add(UserHandle.USER_SYSTEM);
         mLockPatternUtils = mInjector.getLockPatternUtils();
@@ -903,6 +906,7 @@
                 uss = mStartedUsers.get(userId);
                 if (uss == null) {
                     uss = new UserState(UserHandle.of(userId));
+                    uss.mUnlockProgress.addListener(new UserProgressListener());
                     mStartedUsers.put(userId, uss);
                     updateStartedUserArrayLU();
                     needStart = true;
@@ -1854,6 +1858,33 @@
         return false;
     }
 
+    private static class UserProgressListener extends IProgressListener.Stub {
+        private volatile long mUnlockStarted;
+        @Override
+        public void onStarted(int id, Bundle extras) throws RemoteException {
+            Slog.d(TAG, "Started unlocking user " + id);
+            mUnlockStarted = SystemClock.uptimeMillis();
+        }
+
+        @Override
+        public void onProgress(int id, int progress, Bundle extras) throws RemoteException {
+            Slog.d(TAG, "Unlocking user " + id + " progress " + progress);
+        }
+
+        @Override
+        public void onFinished(int id, Bundle extras) throws RemoteException {
+            long unlockTime = SystemClock.uptimeMillis() - mUnlockStarted;
+
+            // Report system user unlock time to perf dashboard
+            if (id == UserHandle.USER_SYSTEM) {
+                new TimingsTraceLog("SystemServerTiming", Trace.TRACE_TAG_SYSTEM_SERVER)
+                        .logDuration("SystemUserUnlock", unlockTime);
+            } else {
+                Slog.d(TAG, "Unlocking user " + id + " took " + unlockTime + " ms");
+            }
+        }
+    };
+
     @VisibleForTesting
     static class Injector {
         private final ActivityManagerService mService;
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 6506cf7..4943173 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -184,11 +184,15 @@
         }
     }
 
+    private static final int FLAGS_FOR_SILENCE_OVERRIDE =
+            AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY |
+            AudioAttributes.FLAG_BYPASS_MUTE;
+
     private void checkVolumeForPrivilegedAlarm(AudioPlaybackConfiguration apc, int event) {
         if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED ||
                 apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
-            if ((apc.getAudioAttributes().getAllFlags() &
-                    AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0 &&
+            if ((apc.getAudioAttributes().getAllFlags() & FLAGS_FOR_SILENCE_OVERRIDE)
+                        == FLAGS_FOR_SILENCE_OVERRIDE  &&
                     apc.getAudioAttributes().getUsage() == AudioAttributes.USAGE_ALARM &&
                     mContext.checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
                             apc.getClientPid(), apc.getClientUid()) ==
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index e6228d4..0c9d70a 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -435,11 +435,12 @@
     }
 
     private boolean isDeviceLocked() {
+        int callingUserId = UserHandle.getCallingUserId();
         final long token = Binder.clearCallingIdentity();
         try {
             final KeyguardManager keyguardManager = getContext().getSystemService(
                     KeyguardManager.class);
-            return keyguardManager != null && keyguardManager.isDeviceLocked();
+            return keyguardManager != null && keyguardManager.isDeviceLocked(callingUserId);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
diff --git a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
index 0539c02..78b4160 100644
--- a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -167,6 +167,7 @@
 
     @Override
     public void dumpControllerStateLocked(final PrintWriter pw, final int filterUid) {
+        pw.println("BackgroundJobsController");
         pw.print("Foreground uids: [");
         for (int i = 0; i < mForegroundUids.size(); i++) {
             if (mForegroundUids.valueAt(i)) pw.print(mForegroundUids.keyAt(i) + " ");
diff --git a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
index 85993b9..374ab43 100644
--- a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
@@ -22,6 +22,7 @@
 import android.content.IntentFilter;
 import android.os.PowerManager;
 import android.os.UserHandle;
+import android.util.ArraySet;
 import android.util.Slog;
 
 import com.android.internal.util.ArrayUtils;
@@ -55,6 +56,9 @@
      */
     private boolean mDeviceIdleMode;
     private int[] mDeviceIdleWhitelistAppIds;
+    private int[] mPowerSaveTempWhitelistAppIds;
+    // These jobs were added when the app was in temp whitelist, these should be exempted from doze
+    private final ArraySet<JobStatus> mTempWhitelistedJobs;
 
     final JobStore.JobStatusFunctor mUpdateFunctor = new JobStore.JobStatusFunctor() {
         @Override public void process(JobStatus jobStatus) {
@@ -79,15 +83,39 @@
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            final String action = intent.getAction();
-            if (PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED.equals(action)
-                    || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
-                updateIdleMode(mPowerManager != null
-                        ? (mPowerManager.isDeviceIdleMode()
-                                || mPowerManager.isLightDeviceIdleMode())
-                        : false);
-            } else if (PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED.equals(action)) {
-                updateWhitelist();
+            switch (intent.getAction()) {
+                case PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED:
+                case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED:
+                    updateIdleMode(mPowerManager != null && (mPowerManager.isDeviceIdleMode()
+                            || mPowerManager.isLightDeviceIdleMode()));
+                    break;
+                case PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED:
+                    synchronized (mLock) {
+                        mDeviceIdleWhitelistAppIds =
+                                mLocalDeviceIdleController.getPowerSaveWhitelistUserAppIds();
+                        if (LOG_DEBUG) {
+                            Slog.d(LOG_TAG, "Got whitelist "
+                                    + Arrays.toString(mDeviceIdleWhitelistAppIds));
+                        }
+                    }
+                    break;
+                case PowerManager.ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED:
+                    synchronized (mLock) {
+                        mPowerSaveTempWhitelistAppIds =
+                                mLocalDeviceIdleController.getPowerSaveTempWhitelistAppIds();
+                        if (LOG_DEBUG) {
+                            Slog.d(LOG_TAG, "Got temp whitelist "
+                                    + Arrays.toString(mPowerSaveTempWhitelistAppIds));
+                        }
+                        boolean changed = false;
+                        for (int i = 0; i < mTempWhitelistedJobs.size(); i ++) {
+                            changed |= updateTaskStateLocked(mTempWhitelistedJobs.valueAt(i));
+                        }
+                        if (changed) {
+                            mStateChangedListener.onControllerStateChanged();
+                        }
+                    }
+                    break;
             }
         }
     };
@@ -101,20 +129,21 @@
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mLocalDeviceIdleController =
                 LocalServices.getService(DeviceIdleController.LocalService.class);
+        mDeviceIdleWhitelistAppIds = mLocalDeviceIdleController.getPowerSaveWhitelistUserAppIds();
+        mPowerSaveTempWhitelistAppIds =
+                mLocalDeviceIdleController.getPowerSaveTempWhitelistAppIds();
+        mTempWhitelistedJobs = new ArraySet<>();
         final IntentFilter filter = new IntentFilter();
         filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
         filter.addAction(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED);
         filter.addAction(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
+        filter.addAction(PowerManager.ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED);
         mContext.registerReceiverAsUser(
                 mBroadcastReceiver, UserHandle.ALL, filter, null, null);
     }
 
     void updateIdleMode(boolean enabled) {
         boolean changed = false;
-        // Need the whitelist to be ready when going into idle
-        if (mDeviceIdleWhitelistAppIds == null) {
-            updateWhitelist();
-        }
         synchronized (mLock) {
             if (mDeviceIdleMode != enabled) {
                 changed = true;
@@ -130,46 +159,42 @@
     }
 
     /**
-     * Fetches the latest whitelist from the device idle controller.
-     */
-    void updateWhitelist() {
-        synchronized (mLock) {
-            if (mLocalDeviceIdleController != null) {
-                mDeviceIdleWhitelistAppIds =
-                        mLocalDeviceIdleController.getPowerSaveWhitelistUserAppIds();
-                if (LOG_DEBUG) {
-                    Slog.d(LOG_TAG, "Got whitelist " + Arrays.toString(mDeviceIdleWhitelistAppIds));
-                }
-            }
-        }
-    }
-
-    /**
      * Checks if the given job's scheduling app id exists in the device idle user whitelist.
      */
     boolean isWhitelistedLocked(JobStatus job) {
-        if (mDeviceIdleWhitelistAppIds != null
-                && ArrayUtils.contains(mDeviceIdleWhitelistAppIds,
-                        UserHandle.getAppId(job.getSourceUid()))) {
-            return true;
-        }
-        return false;
+        return ArrayUtils.contains(mDeviceIdleWhitelistAppIds,
+                UserHandle.getAppId(job.getSourceUid()));
     }
 
-    private void updateTaskStateLocked(JobStatus task) {
-        final boolean whitelisted = isWhitelistedLocked(task);
+    /**
+     * Checks if the given job's scheduling app id exists in the device idle temp whitelist.
+     */
+    boolean isTempWhitelistedLocked(JobStatus job) {
+        return ArrayUtils.contains(mPowerSaveTempWhitelistAppIds,
+                UserHandle.getAppId(job.getSourceUid()));
+    }
+
+    private boolean updateTaskStateLocked(JobStatus task) {
+        final boolean whitelisted = isWhitelistedLocked(task)
+                || (mTempWhitelistedJobs.contains(task) && isTempWhitelistedLocked(task));
         final boolean enableTask = !mDeviceIdleMode || whitelisted;
-        task.setDeviceNotDozingConstraintSatisfied(enableTask, whitelisted);
+        return task.setDeviceNotDozingConstraintSatisfied(enableTask, whitelisted);
     }
 
     @Override
     public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
-        updateTaskStateLocked(jobStatus);
+        if (isTempWhitelistedLocked(jobStatus)) {
+            mTempWhitelistedJobs.add(jobStatus);
+            jobStatus.setDeviceNotDozingConstraintSatisfied(true, true);
+        } else {
+            updateTaskStateLocked(jobStatus);
+        }
     }
 
     @Override
     public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
             boolean forUpdate) {
+        mTempWhitelistedJobs.remove(jobStatus);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
index d90699a..ee4c606 100644
--- a/services/core/java/com/android/server/job/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -110,7 +110,7 @@
             maybeUpdateAlarmsLocked(
                     job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE,
                     job.hasDeadlineConstraint() ? job.getLatestRunTimeElapsed() : Long.MAX_VALUE,
-                    job.getSourceUid());
+                    new WorkSource(job.getSourceUid(), job.getSourcePackageName()));
         }
     }
 
@@ -156,6 +156,7 @@
         synchronized (mLock) {
             long nextExpiryTime = Long.MAX_VALUE;
             int nextExpiryUid = 0;
+            String nextExpiryPackageName = null;
             final long nowElapsedMillis = SystemClock.elapsedRealtime();
 
             Iterator<JobStatus> it = mTrackedJobs.iterator();
@@ -171,10 +172,13 @@
                 } else {  // Sorted by expiry time, so take the next one and stop.
                     nextExpiryTime = job.getLatestRunTimeElapsed();
                     nextExpiryUid = job.getSourceUid();
+                    nextExpiryPackageName = job.getSourcePackageName();
                     break;
                 }
             }
-            setDeadlineExpiredAlarmLocked(nextExpiryTime, nextExpiryUid);
+            setDeadlineExpiredAlarmLocked(nextExpiryTime, nextExpiryPackageName != null
+                    ? new WorkSource(nextExpiryUid, nextExpiryPackageName)
+                    : new WorkSource(nextExpiryUid));
         }
     }
 
@@ -200,6 +204,7 @@
             final long nowElapsedMillis = SystemClock.elapsedRealtime();
             long nextDelayTime = Long.MAX_VALUE;
             int nextDelayUid = 0;
+            String nextDelayPackageName = null;
             boolean ready = false;
             Iterator<JobStatus> it = mTrackedJobs.iterator();
             while (it.hasNext()) {
@@ -221,13 +226,16 @@
                     if (nextDelayTime > jobDelayTime) {
                         nextDelayTime = jobDelayTime;
                         nextDelayUid = job.getSourceUid();
+                        nextDelayPackageName = job.getSourcePackageName();
                     }
                 }
             }
             if (ready) {
                 mStateChangedListener.onControllerStateChanged();
             }
-            setDelayExpiredAlarmLocked(nextDelayTime, nextDelayUid);
+            setDelayExpiredAlarmLocked(nextDelayTime, nextDelayPackageName != null
+                    ? new WorkSource(nextDelayUid, nextDelayPackageName)
+                    : new WorkSource(nextDelayUid));
         }
     }
 
@@ -241,12 +249,12 @@
     }
 
     private void maybeUpdateAlarmsLocked(long delayExpiredElapsed, long deadlineExpiredElapsed,
-            int uid) {
+            WorkSource ws) {
         if (delayExpiredElapsed < mNextDelayExpiredElapsedMillis) {
-            setDelayExpiredAlarmLocked(delayExpiredElapsed, uid);
+            setDelayExpiredAlarmLocked(delayExpiredElapsed, ws);
         }
         if (deadlineExpiredElapsed < mNextJobExpiredElapsedMillis) {
-            setDeadlineExpiredAlarmLocked(deadlineExpiredElapsed, uid);
+            setDeadlineExpiredAlarmLocked(deadlineExpiredElapsed, ws);
         }
     }
 
@@ -255,11 +263,11 @@
      * delay will expire.
      * This alarm <b>will</b> wake up the phone.
      */
-    private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis, int uid) {
+    private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) {
         alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
         mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis;
         updateAlarmWithListenerLocked(DELAY_TAG, mNextDelayExpiredListener,
-                mNextDelayExpiredElapsedMillis, uid);
+                mNextDelayExpiredElapsedMillis, ws);
     }
 
     /**
@@ -267,11 +275,11 @@
      * deadline will expire.
      * This alarm <b>will</b> wake up the phone.
      */
-    private void setDeadlineExpiredAlarmLocked(long alarmTimeElapsedMillis, int uid) {
+    private void setDeadlineExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) {
         alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
         mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis;
         updateAlarmWithListenerLocked(DEADLINE_TAG, mDeadlineExpiredListener,
-                mNextJobExpiredElapsedMillis, uid);
+                mNextJobExpiredElapsedMillis, ws);
     }
 
     private long maybeAdjustAlarmTime(long proposedAlarmTimeElapsedMillis) {
@@ -283,7 +291,7 @@
     }
 
     private void updateAlarmWithListenerLocked(String tag, OnAlarmListener listener,
-            long alarmTimeElapsed, int uid) {
+            long alarmTimeElapsed, WorkSource ws) {
         ensureAlarmServiceLocked();
         if (alarmTimeElapsed == Long.MAX_VALUE) {
             mAlarmService.cancel(listener);
@@ -292,7 +300,7 @@
                 Slog.d(TAG, "Setting " + tag + " for: " + alarmTimeElapsed);
             }
             mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTimeElapsed,
-                    AlarmManager.WINDOW_HEURISTIC, 0, tag, listener, null, new WorkSource(uid));
+                    AlarmManager.WINDOW_HEURISTIC, 0, tag, listener, null, ws);
         }
     }
 
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 0aa6a90..e41c17d 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -417,7 +417,11 @@
     // stops output right at 600m/s, depriving this of the information of a device that reaches
     // greater than 600m/s, and higher than the speed of sound to avoid impacting most use cases.
     private static final float ITAR_SPEED_LIMIT_METERS_PER_SECOND = 400.0F;
-    private boolean mItarSpeedLimitExceeded = false;
+
+    // TODO: improve comment
+    // Volatile to ensure that potentially near-concurrent outputs from HAL
+    // react to this value change promptly
+    private volatile boolean mItarSpeedLimitExceeded = false;
 
     // GNSS Metrics
     private GnssMetrics mGnssMetrics;
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 0b11479..664d2f97 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -784,6 +784,14 @@
                 mService.enforcePhoneStatePermission(pid, uid);
             }
             mFlags = flags;
+            if ((flags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
+                final long token = Binder.clearCallingIdentity();
+                try {
+                    mService.setGlobalPrioritySession(MediaSessionRecord.this);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
             mHandler.post(MessageHandler.MSG_UPDATE_SESSION_STATE);
         }
 
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index b102dde..aa65244 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -178,17 +178,6 @@
                 return;
             }
             if ((record.getFlags() & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
-                if (mGlobalPrioritySession != record) {
-                    Log.d(TAG, "Global priority session is changed from " + mGlobalPrioritySession
-                            + " to " + record);
-                    mGlobalPrioritySession = record;
-                    if (user != null && user.mPriorityStack.contains(record)) {
-                        // Handle the global priority session separately.
-                        // Otherwise, it will be the media button session even after it becomes
-                        // inactive because it has been the lastly played media app.
-                        user.mPriorityStack.removeSession(record);
-                    }
-                }
                 if (DEBUG_KEY_EVENT) {
                     Log.d(TAG, "Global priority session is updated, active=" + record.isActive());
                 }
@@ -204,6 +193,24 @@
         }
     }
 
+    public void setGlobalPrioritySession(MediaSessionRecord record) {
+        synchronized (mLock) {
+            FullUserRecord user = getFullUserRecordLocked(record.getUserId());
+            if (mGlobalPrioritySession != record) {
+                Log.d(TAG, "Global priority session is changed from " + mGlobalPrioritySession
+                        + " to " + record);
+                mGlobalPrioritySession = record;
+                if (user != null && user.mPriorityStack.contains(record)) {
+                    // Handle the global priority session separately.
+                    // Otherwise, it can be the media button session regardless of the active state
+                    // because it or other system components might have been the lastly played media
+                    // app.
+                    user.mPriorityStack.removeSession(record);
+                }
+            }
+        }
+    }
+
     private List<MediaSessionRecord> getActiveSessionsLocked(int userId) {
         List<MediaSessionRecord> records = new ArrayList<>();
         if (userId == UserHandle.USER_ALL) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 168f070..238d87b 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -133,7 +133,6 @@
 import android.service.notification.NotificationRankingUpdate;
 import android.service.notification.NotificationRecordProto;
 import android.service.notification.NotificationServiceDumpProto;
-import android.service.notification.NotificationServiceProto;
 import android.service.notification.NotificationStats;
 import android.service.notification.SnoozeCriterion;
 import android.service.notification.StatusBarNotification;
@@ -3263,7 +3262,7 @@
                     final NotificationRecord nr = mNotificationList.get(i);
                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
                     nr.dump(proto, filter.redact);
-                    proto.write(NotificationRecordProto.STATE, NotificationServiceProto.POSTED);
+                    proto.write(NotificationRecordProto.STATE, NotificationRecordProto.POSTED);
                 }
             }
             N = mEnqueuedNotifications.size();
@@ -3272,7 +3271,7 @@
                     final NotificationRecord nr = mEnqueuedNotifications.get(i);
                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
                     nr.dump(proto, filter.redact);
-                    proto.write(NotificationRecordProto.STATE, NotificationServiceProto.ENQUEUED);
+                    proto.write(NotificationRecordProto.STATE, NotificationRecordProto.ENQUEUED);
                 }
             }
             List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
@@ -3282,7 +3281,7 @@
                     final NotificationRecord nr = snoozed.get(i);
                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
                     nr.dump(proto, filter.redact);
-                    proto.write(NotificationRecordProto.STATE, NotificationServiceProto.SNOOZED);
+                    proto.write(NotificationRecordProto.STATE, NotificationRecordProto.SNOOZED);
                 }
             }
             proto.end(records);
diff --git a/services/core/java/com/android/server/notification/ZenModeFiltering.java b/services/core/java/com/android/server/notification/ZenModeFiltering.java
index a7a2743..abf2900 100644
--- a/services/core/java/com/android/server/notification/ZenModeFiltering.java
+++ b/services/core/java/com/android/server/notification/ZenModeFiltering.java
@@ -117,15 +117,19 @@
                 ZenLog.traceIntercepted(record, "alarmsOnly");
                 return true;
             case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
-                if (isAlarm(record)) {
-                    // Alarms are always priority
-                    return false;
-                }
                 // allow user-prioritized packages through in priority mode
                 if (record.getPackagePriority() == Notification.PRIORITY_MAX) {
                     ZenLog.traceNotIntercepted(record, "priorityApp");
                     return false;
                 }
+
+                if (isAlarm(record)) {
+                    if (!config.allowAlarms) {
+                        ZenLog.traceIntercepted(record, "!allowAlarms");
+                        return true;
+                    }
+                    return false;
+                }
                 if (isCall(record)) {
                     if (config.allowRepeatCallers
                             && REPEAT_CALLERS.isRepeat(mContext, extras(record))) {
@@ -159,6 +163,15 @@
                     }
                     return false;
                 }
+                AudioAttributes aa = record.getAudioAttributes();
+                if (aa != null && AudioAttributes.SUPPRESSIBLE_USAGES.get(aa.getUsage()) ==
+                        AudioAttributes.SUPPRESSIBLE_MEDIA_SYSTEM_OTHER) {
+                    if (!config.allowMediaSystemOther) {
+                        ZenLog.traceIntercepted(record, "!allowMediaSystemOther");
+                        return true;
+                    }
+                    return false;
+                }
                 ZenLog.traceIntercepted(record, "!priority");
                 return true;
             default:
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 9fcc67d..f61cec9 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -59,6 +59,7 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.server.LocalServices;
 
@@ -87,7 +88,7 @@
     private final Context mContext;
     private final H mHandler;
     private final SettingsObserver mSettingsObserver;
-    private final AppOpsManager mAppOps;
+    @VisibleForTesting protected final AppOpsManager mAppOps;
     protected ZenModeConfig mDefaultConfig;
     private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
     private final ZenModeFiltering mFiltering;
@@ -102,9 +103,9 @@
     private final String SCHEDULED_DEFAULT_RULE_1 = "SCHEDULED_DEFAULT_RULE_1";
     private final String SCHEDULED_DEFAULT_RULE_2 = "SCHEDULED_DEFAULT_RULE_2";
 
-    private int mZenMode;
+    @VisibleForTesting protected int mZenMode;
     private int mUser = UserHandle.USER_SYSTEM;
-    protected ZenModeConfig mConfig;
+    @VisibleForTesting protected ZenModeConfig mConfig;
     private AudioManagerInternal mAudioManager;
     protected PackageManager mPm;
     private long mSuppressedEffects;
@@ -125,12 +126,6 @@
         mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
 
         mDefaultConfig = new ZenModeConfig();
-        mDefaultRuleWeeknightsName = mContext.getResources()
-                .getString(R.string.zen_mode_default_weeknights_name);
-        mDefaultRuleWeekendsName = mContext.getResources()
-                .getString(R.string.zen_mode_default_weekends_name);
-        mDefaultRuleEventsName = mContext.getResources()
-                .getString(R.string.zen_mode_default_events_name);
         setDefaultZenRules(mContext);
         mConfig = mDefaultConfig;
         mConfigs.put(UserHandle.USER_SYSTEM, mConfig);
@@ -435,6 +430,7 @@
     }
 
     private void appendDefaultRules (ZenModeConfig config) {
+        getDefaultRuleNames();
         appendDefaultScheduleRules(config);
         appendDefaultEventRules(config);
     }
@@ -595,8 +591,9 @@
             pw.println(config);
             return;
         }
-        pw.printf("allow(calls=%b,callsFrom=%s,repeatCallers=%b,messages=%b,messagesFrom=%s,"
+        pw.printf("allow(alarms=%b,media=%bcalls=%b,callsFrom=%s,repeatCallers=%b,messages=%b,messagesFrom=%s,"
                 + "events=%b,reminders=%b,whenScreenOff=%b,whenScreenOn=%b)\n",
+                config.allowAlarms, config.allowMediaSystemOther,
                 config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom),
                 config.allowRepeatCallers, config.allowMessages,
                 ZenModeConfig.sourceToString(config.allowMessagesFrom),
@@ -813,7 +810,18 @@
         }
     }
 
-    private void applyRestrictions() {
+    private void getDefaultRuleNames() {
+        // on locale-change, these values differ
+        mDefaultRuleWeeknightsName = mContext.getResources()
+                .getString(R.string.zen_mode_default_weeknights_name);
+        mDefaultRuleWeekendsName = mContext.getResources()
+                .getString(R.string.zen_mode_default_weekends_name);
+        mDefaultRuleEventsName = mContext.getResources()
+                .getString(R.string.zen_mode_default_events_name);
+    }
+
+    @VisibleForTesting
+    protected void applyRestrictions() {
         final boolean zen = mZenMode != Global.ZEN_MODE_OFF;
 
         // notification restrictions
@@ -822,6 +830,10 @@
         // call restrictions
         final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers
                 || (mSuppressedEffects & SUPPRESSED_EFFECT_CALLS) != 0;
+        // alarm restrictions
+        final boolean muteAlarms = zen && !mConfig.allowAlarms;
+        // alarm restrictions
+        final boolean muteMediaAndSystemSounds = zen && !mConfig.allowMediaSystemOther;
         // total silence restrictions
         final boolean muteEverything = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
 
@@ -833,13 +845,18 @@
                 applyRestrictions(muteNotifications || muteEverything, usage);
             } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_CALL) {
                 applyRestrictions(muteCalls || muteEverything, usage);
+            } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_ALARM) {
+                applyRestrictions(muteAlarms || muteEverything, usage);
+            } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_MEDIA_SYSTEM_OTHER) {
+                applyRestrictions(muteMediaAndSystemSounds || muteEverything, usage);
             } else {
                 applyRestrictions(muteEverything, usage);
             }
         }
     }
 
-    private void applyRestrictions(boolean mute, int usage) {
+    @VisibleForTesting
+    protected void applyRestrictions(boolean mute, int usage) {
         final String[] exceptionPackages = null; // none (for now)
         mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, usage,
                 mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
@@ -916,6 +933,7 @@
         weeknights.days = ZenModeConfig.WEEKNIGHT_DAYS;
         weeknights.startHour = 22;
         weeknights.endHour = 7;
+        weeknights.exitAtAlarm = true;
         final ZenRule rule1 = new ZenRule();
         rule1.enabled = false;
         rule1.name = mDefaultRuleWeeknightsName;
@@ -931,6 +949,7 @@
         weekends.startHour = 23;
         weekends.startMinute = 30;
         weekends.endHour = 10;
+        weekends.exitAtAlarm = true;
         final ZenRule rule2 = new ZenRule();
         rule2.enabled = false;
         rule2.name = mDefaultRuleWeekendsName;
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 4a5ce12..b06b583 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -30,12 +30,10 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ILauncherApps;
 import android.content.pm.IOnAppsChangedListener;
-import android.content.pm.IPackageManager;
 import android.content.pm.LauncherApps.ShortcutQuery;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ShortcutInfo;
@@ -64,7 +62,6 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
@@ -89,10 +86,14 @@
     static class BroadcastCookie {
         public final UserHandle user;
         public final String packageName;
+        public final int callingUid;
+        public final int callingPid;
 
-        BroadcastCookie(UserHandle userHandle, String packageName) {
+        BroadcastCookie(UserHandle userHandle, String packageName, int callingPid, int callingUid) {
             this.user = userHandle;
             this.packageName = packageName;
+            this.callingUid = callingUid;
+            this.callingPid = callingPid;
         }
     }
 
@@ -127,6 +128,11 @@
             return getCallingUid();
         }
 
+        @VisibleForTesting
+        int injectBinderCallingPid() {
+            return getCallingPid();
+        }
+
         final int injectCallingUserId() {
             return UserHandle.getUserId(injectBinderCallingUid());
         }
@@ -166,7 +172,7 @@
                 }
                 mListeners.unregister(listener);
                 mListeners.register(listener, new BroadcastCookie(UserHandle.of(getCallingUserId()),
-                        callingPackage));
+                        callingPackage, injectBinderCallingPid(), injectBinderCallingUid()));
             }
         }
 
@@ -438,7 +444,7 @@
         private void ensureShortcutPermission(@NonNull String callingPackage) {
             verifyCallingPackage(callingPackage);
             if (!mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(),
-                    callingPackage)) {
+                    callingPackage, injectBinderCallingPid(), injectBinderCallingUid())) {
                 throw new SecurityException("Caller can't access shortcut information");
             }
         }
@@ -461,7 +467,8 @@
             return new ParceledListSlice<>((List<ShortcutInfo>)
                     mShortcutServiceInternal.getShortcuts(getCallingUserId(),
                             callingPackage, changedSince, packageName, shortcutIds,
-                            componentName, flags, targetUser.getIdentifier()));
+                            componentName, flags, targetUser.getIdentifier(),
+                            injectBinderCallingPid(), injectBinderCallingUid()));
         }
 
         @Override
@@ -514,7 +521,7 @@
         public boolean hasShortcutHostPermission(String callingPackage) {
             verifyCallingPackage(callingPackage);
             return mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(),
-                    callingPackage);
+                    callingPackage, injectBinderCallingPid(), injectBinderCallingUid());
         }
 
         @Override
@@ -536,7 +543,8 @@
             }
 
             final Intent[] intents = mShortcutServiceInternal.createShortcutIntents(
-                    getCallingUserId(), callingPackage, packageName, shortcutId, targetUserId);
+                    getCallingUserId(), callingPackage, packageName, shortcutId, targetUserId,
+                    injectBinderCallingPid(), injectBinderCallingUid());
             if (intents == null || intents.length == 0) {
                 return false;
             }
@@ -901,7 +909,8 @@
 
                         // Make sure the caller has the permission.
                         if (!mShortcutServiceInternal.hasShortcutHostPermission(
-                                launcherUserId, cookie.packageName)) {
+                                launcherUserId, cookie.packageName,
+                                cookie.callingPid, cookie.callingUid)) {
                             continue;
                         }
                         // Each launcher has a different set of pinned shortcuts, so we need to do a
@@ -914,8 +923,8 @@
                                         /* changedSince= */ 0, packageName, /* shortcutIds=*/ null,
                                         /* component= */ null,
                                         ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY
-                                        | ShortcutQuery.FLAG_GET_ALL_KINDS
-                                        , userId);
+                                        | ShortcutQuery.FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED
+                                        , userId, cookie.callingPid, cookie.callingUid);
                         try {
                             listener.onShortcutChanged(user, packageName,
                                     new ParceledListSlice<>(list));
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 8ebeeae..cf0ffbb 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -236,9 +236,10 @@
      */
     @GuardedBy("mInstallLock")
     private int dexOptPath(PackageParser.Package pkg, String path, String isa,
-            String compilerFilter, boolean profileUpdated, String sharedLibrariesPath,
+            String compilerFilter, boolean profileUpdated, String classLoaderContext,
             int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade) {
-        int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, profileUpdated, downgrade);
+        int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, classLoaderContext,
+                profileUpdated, downgrade);
         if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) {
             return DEX_OPT_SKIPPED;
         }
@@ -251,8 +252,8 @@
         Log.i(TAG, "Running dexopt (dexoptNeeded=" + dexoptNeeded + ") on: " + path
                 + " pkg=" + pkg.applicationInfo.packageName + " isa=" + isa
                 + " dexoptFlags=" + printDexoptFlags(dexoptFlags)
-                + " target-filter=" + compilerFilter + " oatDir=" + oatDir
-                + " sharedLibraries=" + sharedLibrariesPath);
+                + " targetFilter=" + compilerFilter + " oatDir=" + oatDir
+                + " classLoaderContext=" + classLoaderContext);
 
         try {
             long startTime = System.currentTimeMillis();
@@ -261,7 +262,7 @@
             // installd only uses downgrade flag for secondary dex files and ignores it for
             // primary dex files.
             mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags,
-                    compilerFilter, pkg.volumeUuid, sharedLibrariesPath, pkg.applicationInfo.seInfo,
+                    compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo,
                     false /* downgrade*/);
 
             if (packageStats != null) {
@@ -508,11 +509,11 @@
      * configuration (isa, compiler filter, profile).
      */
     private int getDexoptNeeded(String path, String isa, String compilerFilter,
-            boolean newProfile, boolean downgrade) {
+            String classLoaderContext, boolean newProfile, boolean downgrade) {
         int dexoptNeeded;
         try {
-            dexoptNeeded = DexFile.getDexOptNeeded(path, isa, compilerFilter, newProfile,
-                    downgrade);
+            dexoptNeeded = DexFile.getDexOptNeeded(path, isa, compilerFilter, classLoaderContext,
+                    newProfile, downgrade);
         } catch (IOException ioe) {
             Slog.w(TAG, "IOException reading apk: " + path, ioe);
             return DEX_OPT_FAILED;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index d62f093..0e11cc7 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -95,7 +95,6 @@
 import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
 
 import libcore.io.IoUtils;
-import libcore.io.Libcore;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -613,7 +612,7 @@
 
             // TODO: this should delegate to DCS so the system process avoids
             // holding open FDs into containers.
-            final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(),
+            final FileDescriptor targetFd = Os.open(target.getAbsolutePath(),
                     O_CREAT | O_WRONLY, 0644);
             Os.chmod(target.getAbsolutePath(), 0644);
 
@@ -625,7 +624,7 @@
             }
 
             if (offsetBytes > 0) {
-                Libcore.os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
+                Os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
             }
 
             if (PackageInstaller.ENABLE_REVOCABLE_FD) {
@@ -661,7 +660,7 @@
                 throw new IllegalArgumentException("Invalid name: " + name);
             }
             final File target = new File(resolveStageDirLocked(), name);
-            final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(), O_RDONLY, 0);
+            final FileDescriptor targetFd = Os.open(target.getAbsolutePath(), O_RDONLY, 0);
             return new ParcelFileDescriptor(targetFd);
         } catch (ErrnoException e) {
             throw e.rethrowAsIOException();
@@ -1127,15 +1126,8 @@
 
                         mResolvedInstructionSets.add(archSubDir.getName());
                         List<File> oatFiles = Arrays.asList(archSubDir.listFiles());
-
-                        // Only add compiled files associated with the base.
-                        // Once b/62269291 is resolved, we can add all compiled files again.
-                        for (File oatFile : oatFiles) {
-                            if (oatFile.getName().equals("base.art")
-                                    || oatFile.getName().equals("base.odex")
-                                    || oatFile.getName().equals("base.vdex")) {
-                                mResolvedInheritedFiles.add(oatFile);
-                            }
+                        if (!oatFiles.isEmpty()) {
+                            mResolvedInheritedFiles.addAll(oatFiles);
                         }
                     }
                 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d7329db..391deb7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3261,23 +3261,6 @@
             return null;
         }
 
-        // If we have a profile for a compressed APK, copy it to the reference location.
-        // Since the package is the stub one, remove the stub suffix to get the normal package and
-        // APK name.
-        File profileFile = new File(getPrebuildProfilePath(pkg).replace(STUB_SUFFIX, ""));
-        if (profileFile.exists()) {
-            try {
-                // We could also do this lazily before calling dexopt in
-                // PackageDexOptimizer to prevent this happening on first boot. The issue
-                // is that we don't have a good way to say "do this only once".
-                if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
-                        pkg.applicationInfo.uid, pkg.packageName)) {
-                    Log.e(TAG, "decompressPackage failed to copy system profile!");
-                }
-            } catch (Exception e) {
-                Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath() + " ", e);
-            }
-        }
         return dstCodePath;
     }
 
@@ -6917,6 +6900,13 @@
                     && info.activityInfo.splitName != null
                     && !ArrayUtils.contains(info.activityInfo.applicationInfo.splitNames,
                             info.activityInfo.splitName)) {
+                if (mInstantAppInstallerInfo == null) {
+                    if (DEBUG_INSTALL) {
+                        Slog.v(TAG, "No installer - not adding it to the ResolveInfo list");
+                    }
+                    resolveInfos.remove(i);
+                    continue;
+                }
                 // requested activity is defined in a split that hasn't been installed yet.
                 // add the installer to the resolve list
                 if (DEBUG_INSTALL) {
@@ -6930,14 +6920,22 @@
                         installFailureActivity,
                         info.activityInfo.applicationInfo.versionCode,
                         null /*failureIntent*/);
-                // make sure this resolver is the default
-                installerInfo.isDefault = true;
                 installerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
                         | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
                 // add a non-generic filter
                 installerInfo.filter = new IntentFilter();
-                // load resources from the correct package
+
+                // This resolve info may appear in the chooser UI, so let us make it
+                // look as the one it replaces as far as the user is concerned which
+                // requires loading the correct label and icon for the resolve info.
                 installerInfo.resolvePackageName = info.getComponentInfo().packageName;
+                installerInfo.labelRes = info.resolveLabelResId();
+                installerInfo.icon = info.resolveIconResId();
+
+                // propagate priority/preferred order/default
+                installerInfo.priority = info.priority;
+                installerInfo.preferredOrder = info.preferredOrder;
+                installerInfo.isDefault = info.isDefault;
                 resolveInfos.set(i, installerInfo);
                 continue;
             }
@@ -9114,10 +9112,30 @@
                         // package and APK names.
                         String systemProfilePath =
                                 getPrebuildProfilePath(disabledPs.pkg).replace(STUB_SUFFIX, "");
-                        File systemProfile = new File(systemProfilePath);
-                        // Use the profile for compilation if there exists one for the same package
-                        // in the system partition.
-                        useProfileForDexopt = systemProfile.exists();
+                        profileFile = new File(systemProfilePath);
+                        // If we have a profile for a compressed APK, copy it to the reference
+                        // location.
+                        // Note that copying the profile here will cause it to override the
+                        // reference profile every OTA even though the existing reference profile
+                        // may have more data. We can't copy during decompression since the
+                        // directories are not set up at that point.
+                        if (profileFile.exists()) {
+                            try {
+                                // We could also do this lazily before calling dexopt in
+                                // PackageDexOptimizer to prevent this happening on first boot. The
+                                // issue is that we don't have a good way to say "do this only
+                                // once".
+                                if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
+                                        pkg.applicationInfo.uid, pkg.packageName)) {
+                                    Log.e(TAG, "Failed to copy system profile for stub package!");
+                                } else {
+                                    useProfileForDexopt = true;
+                                }
+                            } catch (Exception e) {
+                                Log.e(TAG, "Failed to copy profile " +
+                                        profileFile.getAbsolutePath() + " ", e);
+                            }
+                        }
                     }
                 }
             }
@@ -12425,7 +12443,8 @@
                             .getPrivAppDenyPermissions(pkg.packageName);
                     final boolean permissionViolation =
                             deniedPermissions == null || !deniedPermissions.contains(perm);
-                    if (permissionViolation) {
+                    if (permissionViolation
+                            && RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) {
                         if (mPrivappPermissionsViolations == null) {
                             mPrivappPermissionsViolations = new ArraySet<>();
                         }
@@ -21857,11 +21876,7 @@
         synchronized (mAvailableFeatures) {
             final int count = mAvailableFeatures.size();
             for (int i = 0; i < count; i++) {
-                final FeatureInfo feat = mAvailableFeatures.valueAt(i);
-                final long featureToken = proto.start(PackageServiceDumpProto.FEATURES);
-                proto.write(PackageServiceDumpProto.FeatureProto.NAME, feat.name);
-                proto.write(PackageServiceDumpProto.FeatureProto.VERSION, feat.version);
-                proto.end(featureToken);
+                mAvailableFeatures.valueAt(i).writeToProto(proto, PackageServiceDumpProto.FEATURES);
             }
         }
     }
@@ -21893,7 +21908,7 @@
     }
 
     private void dumpDexoptStateLPr(PrintWriter pw, String packageName) {
-        final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ", 120);
+        final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
         ipw.println();
         ipw.println("Dexopt state:");
         ipw.increaseIndent();
@@ -21920,7 +21935,7 @@
     }
 
     private void dumpCompilerStatsLPr(PrintWriter pw, String packageName) {
-        final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ", 120);
+        final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
         ipw.println();
         ipw.println("Compiler stats:");
         ipw.increaseIndent();
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 8f7971e..67e06dd 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -35,6 +35,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.system.ErrnoException;
+import android.system.Os;
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
@@ -232,7 +233,7 @@
      */
     public static String realpath(File path) throws IOException {
         try {
-            return Libcore.os.realpath(path.getAbsolutePath());
+            return Os.realpath(path.getAbsolutePath());
         } catch (ErrnoException ee) {
             throw ee.rethrowAsIOException();
         }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 56595c9..191b43a 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4929,11 +4929,7 @@
     void dumpSharedUsersProto(ProtoOutputStream proto) {
         final int count = mSharedUsers.size();
         for (int i = 0; i < count; i++) {
-            final SharedUserSetting su = mSharedUsers.valueAt(i);
-            final long sharedUserToken = proto.start(PackageServiceDumpProto.SHARED_USERS);
-            proto.write(PackageServiceDumpProto.SharedUserProto.USER_ID, su.userId);
-            proto.write(PackageServiceDumpProto.SharedUserProto.NAME, su.name);
-            proto.end(sharedUserToken);
+            mSharedUsers.valueAt(i).writeToProto(proto, PackageServiceDumpProto.SHARED_USERS);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index a0dadae..877da14 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -18,7 +18,9 @@
 
 import android.annotation.Nullable;
 import android.content.pm.PackageParser;
+import android.service.pm.PackageServiceDumpProto;
 import android.util.ArraySet;
+import android.util.proto.ProtoOutputStream;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -53,6 +55,13 @@
                 + name + "/" + userId + "}";
     }
 
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        long token = proto.start(fieldId);
+        proto.write(PackageServiceDumpProto.SharedUserProto.USER_ID, userId);
+        proto.write(PackageServiceDumpProto.SharedUserProto.NAME, name);
+        proto.end(token);
+    }
+
     void removePackage(PackageSetting packageSetting) {
         if (packages.remove(packageSetting)) {
             // recalculate the pkgFlags for this shared user if needed
diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java
index f922ad1..cedf476 100644
--- a/services/core/java/com/android/server/pm/ShortcutLauncher.java
+++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java
@@ -83,11 +83,16 @@
         return mOwnerUserId;
     }
 
+    @Override
+    protected boolean canRestoreAnyVersion() {
+        // Launcher's pinned shortcuts can be restored to an older version.
+        return true;
+    }
+
     /**
      * Called when the new package can't receive the backup, due to signature or version mismatch.
      */
-    @Override
-    protected void onRestoreBlocked() {
+    private void onRestoreBlocked() {
         final ArrayList<PackageWithUser> pinnedPackages =
                 new ArrayList<>(mPinnedShortcuts.keySet());
         mPinnedShortcuts.clear();
@@ -101,15 +106,21 @@
     }
 
     @Override
-    protected void onRestored() {
-        // Nothing to do.
+    protected void onRestored(int restoreBlockReason) {
+        // For launcher, possible reasons here are DISABLED_REASON_SIGNATURE_MISMATCH or
+        // DISABLED_REASON_BACKUP_NOT_SUPPORTED.
+        // DISABLED_REASON_VERSION_LOWER will NOT happen because we don't check version
+        // code for launchers.
+        if (restoreBlockReason != ShortcutInfo.DISABLED_REASON_NOT_DISABLED) {
+            onRestoreBlocked();
+        }
     }
 
     /**
      * Pin the given shortcuts, replacing the current pinned ones.
      */
     public void pinShortcuts(@UserIdInt int packageUserId,
-            @NonNull String packageName, @NonNull List<String> ids) {
+            @NonNull String packageName, @NonNull List<String> ids, boolean forPinRequest) {
         final ShortcutPackage packageShortcuts =
                 mShortcutUser.getPackageShortcutsIfExists(packageName);
         if (packageShortcuts == null) {
@@ -124,8 +135,12 @@
         } else {
             final ArraySet<String> prevSet = mPinnedShortcuts.get(pu);
 
-            // Pin shortcuts.  Make sure only pin the ones that were visible to the caller.
-            // i.e. a non-dynamic, pinned shortcut by *other launchers* shouldn't be pinned here.
+            // Actually pin shortcuts.
+            // This logic here is to make sure a launcher cannot pin a shortcut that is floating
+            // (i.e. not dynamic nor manifest but is pinned) and pinned by another launcher.
+            // In this case, technically the shortcut doesn't exist to this launcher, so it can't
+            // pin it.
+            // (Maybe unnecessarily strict...)
 
             final ArraySet<String> newSet = new ArraySet<>();
 
@@ -135,8 +150,10 @@
                 if (si == null) {
                     continue;
                 }
-                if (si.isDynamic() || si.isManifestShortcut()
-                        || (prevSet != null && prevSet.contains(id))) {
+                if (si.isDynamic()
+                        || si.isManifestShortcut()
+                        || (prevSet != null && prevSet.contains(id))
+                        || forPinRequest) {
                     newSet.add(id);
                 }
             }
@@ -155,7 +172,7 @@
     }
 
     /**
-     * Return true if the given shortcut is pinned by this launcher.
+     * Return true if the given shortcut is pinned by this launcher.<code></code>
      */
     public boolean hasPinned(ShortcutInfo shortcut) {
         final ArraySet<String> pinned =
@@ -164,10 +181,10 @@
     }
 
     /**
-     * Additionally pin a shortcut. c.f. {@link #pinShortcuts(int, String, List)}
+     * Additionally pin a shortcut. c.f. {@link #pinShortcuts(int, String, List, boolean)}
      */
     public void addPinnedShortcut(@NonNull String packageName, @UserIdInt int packageUserId,
-            String id) {
+            String id, boolean forPinRequest) {
         final ArraySet<String> pinnedSet = getPinnedShortcutIds(packageName, packageUserId);
         final ArrayList<String> pinnedList;
         if (pinnedSet != null) {
@@ -178,21 +195,21 @@
         }
         pinnedList.add(id);
 
-        pinShortcuts(packageUserId, packageName, pinnedList);
+        pinShortcuts(packageUserId, packageName, pinnedList, forPinRequest);
     }
 
     boolean cleanUpPackage(String packageName, @UserIdInt int packageUserId) {
         return mPinnedShortcuts.remove(PackageWithUser.of(packageUserId, packageName)) != null;
     }
 
-    public void ensureVersionInfo() {
+    public void ensurePackageInfo() {
         final PackageInfo pi = mShortcutUser.mService.getPackageInfoWithSignatures(
                 getPackageName(), getPackageUserId());
         if (pi == null) {
             Slog.w(TAG, "Package not found: " + getPackageName());
             return;
         }
-        getPackageInfo().updateVersionInfo(pi);
+        getPackageInfo().updateFromPackageInfo(pi);
     }
 
     /**
@@ -201,6 +218,10 @@
     @Override
     public void saveToXml(XmlSerializer out, boolean forBackup)
             throws IOException {
+        if (forBackup && !getPackageInfo().isBackupAllowed()) {
+            // If an launcher app doesn't support backup&restore, then nothing to do.
+            return;
+        }
         final int size = mPinnedShortcuts.size();
         if (size == 0) {
             return; // Nothing to write.
@@ -209,7 +230,7 @@
         out.startTag(null, TAG_ROOT);
         ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, getPackageName());
         ShortcutService.writeAttr(out, ATTR_LAUNCHER_USER_ID, getPackageUserId());
-        getPackageInfo().saveToXml(out);
+        getPackageInfo().saveToXml(out, forBackup);
 
         for (int i = 0; i < size; i++) {
             final PackageWithUser pu = mPinnedShortcuts.keyAt(i);
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 6fc1e73..a3585bc 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -84,6 +84,7 @@
     private static final String ATTR_DISABLED_MESSAGE = "dmessage";
     private static final String ATTR_DISABLED_MESSAGE_RES_ID = "dmessageid";
     private static final String ATTR_DISABLED_MESSAGE_RES_NAME = "dmessagename";
+    private static final String ATTR_DISABLED_REASON = "disabled-reason";
     private static final String ATTR_INTENT_LEGACY = "intent";
     private static final String ATTR_INTENT_NO_EXTRA = "intent-base";
     private static final String ATTR_RANK = "rank";
@@ -156,13 +157,25 @@
     }
 
     @Override
-    protected void onRestoreBlocked() {
-        // Can't restore due to version/signature mismatch.  Remove all shortcuts.
-        mShortcuts.clear();
+    protected boolean canRestoreAnyVersion() {
+        return false;
     }
 
     @Override
-    protected void onRestored() {
+    protected void onRestored(int restoreBlockReason) {
+        // Shortcuts have been restored.
+        // - Unshadow all shortcuts.
+        // - Set disabled reason.
+        // - Disable if needed.
+        for (int i = mShortcuts.size() - 1; i >= 0; i--) {
+            ShortcutInfo si = mShortcuts.valueAt(i);
+            si.clearFlags(ShortcutInfo.FLAG_SHADOW);
+
+            si.setDisabledReason(restoreBlockReason);
+            if (restoreBlockReason != ShortcutInfo.DISABLED_REASON_NOT_DISABLED) {
+                si.addFlags(ShortcutInfo.FLAG_DISABLED);
+            }
+        }
         // Because some launchers may not have been restored (e.g. allowBackup=false),
         // we need to re-calculate the pinned shortcuts.
         refreshPinnedFlags();
@@ -176,31 +189,47 @@
         return mShortcuts.get(id);
     }
 
-    private void ensureNotImmutable(@Nullable ShortcutInfo shortcut) {
-        if (shortcut != null && shortcut.isImmutable()) {
+    public boolean isShortcutExistsAndInvisibleToPublisher(String id) {
+        ShortcutInfo si = findShortcutById(id);
+        return si != null && !si.isVisibleToPublisher();
+    }
+
+    public boolean isShortcutExistsAndVisibleToPublisher(String id) {
+        ShortcutInfo si = findShortcutById(id);
+        return si != null && si.isVisibleToPublisher();
+    }
+
+    private void ensureNotImmutable(@Nullable ShortcutInfo shortcut, boolean ignoreInvisible) {
+        if (shortcut != null && shortcut.isImmutable()
+                && (!ignoreInvisible || shortcut.isVisibleToPublisher())) {
             throw new IllegalArgumentException(
                     "Manifest shortcut ID=" + shortcut.getId()
                             + " may not be manipulated via APIs");
         }
     }
 
-    public void ensureNotImmutable(@NonNull String id) {
-        ensureNotImmutable(mShortcuts.get(id));
+    public void ensureNotImmutable(@NonNull String id, boolean ignoreInvisible) {
+        ensureNotImmutable(mShortcuts.get(id), ignoreInvisible);
     }
 
-    public void ensureImmutableShortcutsNotIncludedWithIds(@NonNull List<String> shortcutIds) {
+    public void ensureImmutableShortcutsNotIncludedWithIds(@NonNull List<String> shortcutIds,
+            boolean ignoreInvisible) {
         for (int i = shortcutIds.size() - 1; i >= 0; i--) {
-            ensureNotImmutable(shortcutIds.get(i));
+            ensureNotImmutable(shortcutIds.get(i), ignoreInvisible);
         }
     }
 
-    public void ensureImmutableShortcutsNotIncluded(@NonNull List<ShortcutInfo> shortcuts) {
+    public void ensureImmutableShortcutsNotIncluded(@NonNull List<ShortcutInfo> shortcuts,
+            boolean ignoreInvisible) {
         for (int i = shortcuts.size() - 1; i >= 0; i--) {
-            ensureNotImmutable(shortcuts.get(i).getId());
+            ensureNotImmutable(shortcuts.get(i).getId(), ignoreInvisible);
         }
     }
 
-    private ShortcutInfo deleteShortcutInner(@NonNull String id) {
+    /**
+     * Delete a shortcut by ID. This will *always* remove it even if it's immutable or invisible.
+     */
+    private ShortcutInfo forceDeleteShortcutInner(@NonNull String id) {
         final ShortcutInfo shortcut = mShortcuts.remove(id);
         if (shortcut != null) {
             mShortcutUser.mService.removeIconLocked(shortcut);
@@ -210,10 +239,14 @@
         return shortcut;
     }
 
-    private void addShortcutInner(@NonNull ShortcutInfo newShortcut) {
+    /**
+     * Force replace a shortcut. If there's already a shortcut with the same ID, it'll be removed,
+     * even if it's invisible.
+     */
+    private void forceReplaceShortcutInner(@NonNull ShortcutInfo newShortcut) {
         final ShortcutService s = mShortcutUser.mService;
 
-        deleteShortcutInner(newShortcut.getId());
+        forceDeleteShortcutInner(newShortcut.getId());
 
         // Extract Icon and update the icon res ID and the bitmap path.
         s.saveIconAndFixUpShortcutLocked(newShortcut);
@@ -222,11 +255,12 @@
     }
 
     /**
-     * Add a shortcut, or update one with the same ID, with taking over existing flags.
+     * Add a shortcut. If there's already a one with the same ID, it'll be removed, even if it's
+     * invisible.
      *
      * It checks the max number of dynamic shortcuts.
      */
-    public void addOrUpdateDynamicShortcut(@NonNull ShortcutInfo newShortcut) {
+    public void addOrReplaceDynamicShortcut(@NonNull ShortcutInfo newShortcut) {
 
         Preconditions.checkArgument(newShortcut.isEnabled(),
                 "add/setDynamicShortcuts() cannot publish disabled shortcuts");
@@ -242,7 +276,7 @@
         } else {
             // It's an update case.
             // Make sure the target is updatable. (i.e. should be mutable.)
-            oldShortcut.ensureUpdatableWith(newShortcut);
+            oldShortcut.ensureUpdatableWith(newShortcut, /*isUpdating=*/ false);
 
             wasPinned = oldShortcut.isPinned();
         }
@@ -252,7 +286,7 @@
             newShortcut.addFlags(ShortcutInfo.FLAG_PINNED);
         }
 
-        addShortcutInner(newShortcut);
+        forceReplaceShortcutInner(newShortcut);
     }
 
     /**
@@ -273,7 +307,7 @@
         }
         if (removeList != null) {
             for (int i = removeList.size() - 1; i >= 0; i--) {
-                deleteShortcutInner(removeList.get(i));
+                forceDeleteShortcutInner(removeList.get(i));
             }
         }
     }
@@ -281,13 +315,13 @@
     /**
      * Remove all dynamic shortcuts.
      */
-    public void deleteAllDynamicShortcuts() {
+    public void deleteAllDynamicShortcuts(boolean ignoreInvisible) {
         final long now = mShortcutUser.mService.injectCurrentTimeMillis();
 
         boolean changed = false;
         for (int i = mShortcuts.size() - 1; i >= 0; i--) {
             final ShortcutInfo si = mShortcuts.valueAt(i);
-            if (si.isDynamic()) {
+            if (si.isDynamic() && (!ignoreInvisible || si.isVisibleToPublisher())) {
                 changed = true;
 
                 si.setTimestamp(now);
@@ -307,9 +341,10 @@
      * @return true if it's actually removed because it wasn't pinned, or false if it's still
      * pinned.
      */
-    public boolean deleteDynamicWithId(@NonNull String shortcutId) {
+    public boolean deleteDynamicWithId(@NonNull String shortcutId, boolean ignoreInvisible) {
         final ShortcutInfo removed = deleteOrDisableWithId(
-                shortcutId, /* disable =*/ false, /* overrideImmutable=*/ false);
+                shortcutId, /* disable =*/ false, /* overrideImmutable=*/ false, ignoreInvisible,
+                ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
         return removed == null;
     }
 
@@ -320,9 +355,11 @@
      * @return true if it's actually removed because it wasn't pinned, or false if it's still
      * pinned.
      */
-    private boolean disableDynamicWithId(@NonNull String shortcutId) {
+    private boolean disableDynamicWithId(@NonNull String shortcutId, boolean ignoreInvisible,
+            int disabledReason) {
         final ShortcutInfo disabled = deleteOrDisableWithId(
-                shortcutId, /* disable =*/ true, /* overrideImmutable=*/ false);
+                shortcutId, /* disable =*/ true, /* overrideImmutable=*/ false, ignoreInvisible,
+                disabledReason);
         return disabled == null;
     }
 
@@ -331,9 +368,10 @@
      * is pinned, it'll remain as a pinned shortcut but will be disabled.
      */
     public void disableWithId(@NonNull String shortcutId, String disabledMessage,
-            int disabledMessageResId, boolean overrideImmutable) {
+            int disabledMessageResId, boolean overrideImmutable, boolean ignoreInvisible,
+            int disabledReason) {
         final ShortcutInfo disabled = deleteOrDisableWithId(shortcutId, /* disable =*/ true,
-                overrideImmutable);
+                overrideImmutable, ignoreInvisible, disabledReason);
 
         if (disabled != null) {
             if (disabledMessage != null) {
@@ -348,14 +386,18 @@
 
     @Nullable
     private ShortcutInfo deleteOrDisableWithId(@NonNull String shortcutId, boolean disable,
-            boolean overrideImmutable) {
+            boolean overrideImmutable, boolean ignoreInvisible, int disabledReason) {
+        Preconditions.checkState(
+                (disable == (disabledReason != ShortcutInfo.DISABLED_REASON_NOT_DISABLED)),
+                "disable and disabledReason disagree: " + disable + " vs " + disabledReason);
         final ShortcutInfo oldShortcut = mShortcuts.get(shortcutId);
 
-        if (oldShortcut == null || !oldShortcut.isEnabled()) {
+        if (oldShortcut == null || !oldShortcut.isEnabled()
+                && (ignoreInvisible && !oldShortcut.isVisibleToPublisher())) {
             return null; // Doesn't exist or already disabled.
         }
         if (!overrideImmutable) {
-            ensureNotImmutable(oldShortcut);
+            ensureNotImmutable(oldShortcut, /*ignoreInvisible=*/ true);
         }
         if (oldShortcut.isPinned()) {
 
@@ -363,6 +405,10 @@
             oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST);
             if (disable) {
                 oldShortcut.addFlags(ShortcutInfo.FLAG_DISABLED);
+                // Do not overwrite the disabled reason if one is alreay set.
+                if (oldShortcut.getDisabledReason() == ShortcutInfo.DISABLED_REASON_NOT_DISABLED) {
+                    oldShortcut.setDisabledReason(disabledReason);
+                }
             }
             oldShortcut.setTimestamp(mShortcutUser.mService.injectCurrentTimeMillis());
 
@@ -373,7 +419,7 @@
 
             return oldShortcut;
         } else {
-            deleteShortcutInner(shortcutId);
+            forceDeleteShortcutInner(shortcutId);
             return null;
         }
     }
@@ -381,11 +427,25 @@
     public void enableWithId(@NonNull String shortcutId) {
         final ShortcutInfo shortcut = mShortcuts.get(shortcutId);
         if (shortcut != null) {
-            ensureNotImmutable(shortcut);
+            ensureNotImmutable(shortcut, /*ignoreInvisible=*/ true);
             shortcut.clearFlags(ShortcutInfo.FLAG_DISABLED);
+            shortcut.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
         }
     }
 
+    public void updateInvisibleShortcutForPinRequestWith(@NonNull ShortcutInfo shortcut) {
+        final ShortcutInfo source = mShortcuts.get(shortcut.getId());
+        Preconditions.checkNotNull(source);
+
+        mShortcutUser.mService.validateShortcutForPinRequest(shortcut);
+
+        shortcut.addFlags(ShortcutInfo.FLAG_PINNED);
+
+        forceReplaceShortcutInner(shortcut);
+
+        adjustRanks();
+    }
+
     /**
      * Called after a launcher updates the pinned set.  For each shortcut in this package,
      * set FLAG_PINNED if any launcher has pinned it.  Otherwise, clear it.
@@ -510,7 +570,7 @@
      */
     public void findAll(@NonNull List<ShortcutInfo> result,
             @Nullable Predicate<ShortcutInfo> query, int cloneFlag) {
-        findAll(result, query, cloneFlag, null, 0);
+        findAll(result, query, cloneFlag, null, 0, /*getPinnedByAnyLauncher=*/ false);
     }
 
     /**
@@ -522,7 +582,7 @@
      */
     public void findAll(@NonNull List<ShortcutInfo> result,
             @Nullable Predicate<ShortcutInfo> query, int cloneFlag,
-            @Nullable String callingLauncher, int launcherUserId) {
+            @Nullable String callingLauncher, int launcherUserId, boolean getPinnedByAnyLauncher) {
         if (getPackageInfo().isShadow()) {
             // Restored and the app not installed yet, so don't return any.
             return;
@@ -544,9 +604,11 @@
             final boolean isPinnedByCaller = (callingLauncher == null)
                     || ((pinnedByCallerSet != null) && pinnedByCallerSet.contains(si.getId()));
 
-            if (si.isFloating()) {
-                if (!isPinnedByCaller) {
-                    continue;
+            if (!getPinnedByAnyLauncher) {
+                if (si.isFloating()) {
+                    if (!isPinnedByCaller) {
+                        continue;
+                    }
                 }
             }
             final ShortcutInfo clone = si.clone(cloneFlag);
@@ -612,7 +674,8 @@
             }
             checked.add(activity);
 
-            if (!s.injectIsActivityEnabledAndExported(activity, getOwnerUserId())) {
+            if ((activity != null)
+                    && !s.injectIsActivityEnabledAndExported(activity, getOwnerUserId())) {
                 return false;
             }
         }
@@ -693,7 +756,27 @@
                     getPackageInfo().getVersionCode(), pi.versionCode));
         }
 
-        getPackageInfo().updateVersionInfo(pi);
+        getPackageInfo().updateFromPackageInfo(pi);
+        final int newVersionCode = getPackageInfo().getVersionCode();
+
+        // See if there are any shortcuts that were prevented restoring because the app was of a
+        // lower version, and re-enable them.
+        for (int i = mShortcuts.size() - 1; i >= 0; i--) {
+            final ShortcutInfo si = mShortcuts.valueAt(i);
+            if (si.getDisabledReason() != ShortcutInfo.DISABLED_REASON_VERSION_LOWER) {
+                continue;
+            }
+            if (getPackageInfo().getBackupSourceVersionCode() > newVersionCode) {
+                if (ShortcutService.DEBUG) {
+                    Slog.d(TAG, String.format("Shortcut %s require version %s, still not restored.",
+                            si.getId(), getPackageInfo().getBackupSourceVersionCode()));
+                }
+                continue;
+            }
+            Slog.i(TAG, String.format("Restoring shortcut: %s", si.getId()));
+            si.clearFlags(ShortcutInfo.FLAG_DISABLED);
+            si.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
+        }
 
         // For existing shortcuts, update timestamps if they have any resources.
         // Also check if shortcuts' activities are still main activities.  Otherwise, disable them.
@@ -713,7 +796,8 @@
                         Slog.w(TAG, String.format(
                                 "%s is no longer main activity. Disabling shorcut %s.",
                                 getPackageName(), si.getId()));
-                        if (disableDynamicWithId(si.getId())) {
+                        if (disableDynamicWithId(si.getId(), /*ignoreInvisible*/ false,
+                                ShortcutInfo.DISABLED_REASON_APP_CHANGED)) {
                             continue; // Actually removed.
                         }
                         // Still pinned, so fall-through and possibly update the resources.
@@ -809,7 +893,7 @@
 
                 // Note even if enabled=false, we still need to update all fields, so do it
                 // regardless.
-                addShortcutInner(newShortcut); // This will clean up the old one too.
+                forceReplaceShortcutInner(newShortcut); // This will clean up the old one too.
 
                 if (!newDisabled && toDisableList != null) {
                     // Still alive, don't remove.
@@ -831,7 +915,8 @@
                 final String id = toDisableList.valueAt(i);
 
                 disableWithId(id, /* disable message =*/ null, /* disable message resid */ 0,
-                        /* overrideImmutable=*/ true);
+                        /* overrideImmutable=*/ true, /*ignoreInvisible=*/ false,
+                        ShortcutInfo.DISABLED_REASON_APP_CHANGED);
             }
             removeOrphans();
         }
@@ -869,7 +954,7 @@
                     service.wtf("Found manifest shortcuts in excess list.");
                     continue;
                 }
-                deleteDynamicWithId(shortcut.getId());
+                deleteDynamicWithId(shortcut.getId(), /*ignoreInvisible=*/ true);
             }
         }
 
@@ -1075,7 +1160,7 @@
         if (ret != 0) {
             return ret;
         }
-        // If they're stil tie, just sort by their IDs.
+        // If they're still tie, just sort by their IDs.
         // This may happen with updateShortcuts() -- see
         // the testUpdateShortcuts_noManifestShortcuts() test.
         return a.getId().compareTo(b.getId());
@@ -1257,25 +1342,34 @@
         ShortcutService.writeAttr(out, ATTR_NAME, getPackageName());
         ShortcutService.writeAttr(out, ATTR_CALL_COUNT, mApiCallCount);
         ShortcutService.writeAttr(out, ATTR_LAST_RESET, mLastResetTime);
-        getPackageInfo().saveToXml(out);
+        getPackageInfo().saveToXml(out, forBackup);
 
         for (int j = 0; j < size; j++) {
-            saveShortcut(out, mShortcuts.valueAt(j), forBackup);
+            saveShortcut(out, mShortcuts.valueAt(j), forBackup,
+                    getPackageInfo().isBackupAllowed());
         }
 
         out.endTag(null, TAG_ROOT);
     }
 
-    private void saveShortcut(XmlSerializer out, ShortcutInfo si, boolean forBackup)
+    private void saveShortcut(XmlSerializer out, ShortcutInfo si, boolean forBackup,
+            boolean appSupportsBackup)
             throws IOException, XmlPullParserException {
 
         final ShortcutService s = mShortcutUser.mService;
 
         if (forBackup) {
             if (!(si.isPinned() && si.isEnabled())) {
-                return; // We only backup pinned shortcuts that are enabled.
+                // We only backup pinned shortcuts that are enabled.
+                // Note, this means, shortcuts that are restored but are blocked restore, e.g. due
+                // to a lower version code, will not be ported to a new device.
+                return;
             }
         }
+        final boolean shouldBackupDetails =
+                !forBackup // It's not backup
+                || appSupportsBackup; // Or, it's a backup and app supports backup.
+
         // Note: at this point no shortcuts should have bitmaps pending save, but if they do,
         // just remove the bitmap.
         if (si.isIconPendingSave()) {
@@ -1292,20 +1386,31 @@
         ShortcutService.writeAttr(out, ATTR_TEXT, si.getText());
         ShortcutService.writeAttr(out, ATTR_TEXT_RES_ID, si.getTextResId());
         ShortcutService.writeAttr(out, ATTR_TEXT_RES_NAME, si.getTextResName());
-        ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE, si.getDisabledMessage());
-        ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE_RES_ID,
-                si.getDisabledMessageResourceId());
-        ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE_RES_NAME,
-                si.getDisabledMessageResName());
+        if (shouldBackupDetails) {
+            ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE, si.getDisabledMessage());
+            ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE_RES_ID,
+                    si.getDisabledMessageResourceId());
+            ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE_RES_NAME,
+                    si.getDisabledMessageResName());
+        }
+        ShortcutService.writeAttr(out, ATTR_DISABLED_REASON, si.getDisabledReason());
         ShortcutService.writeAttr(out, ATTR_TIMESTAMP,
                 si.getLastChangedTimestamp());
         if (forBackup) {
             // Don't write icon information.  Also drop the dynamic flag.
-            ShortcutService.writeAttr(out, ATTR_FLAGS,
-                    si.getFlags() &
-                            ~(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_HAS_ICON_RES
+
+            int flags = si.getFlags() &
+                    ~(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_HAS_ICON_RES
                             | ShortcutInfo.FLAG_ICON_FILE_PENDING_SAVE
-                            | ShortcutInfo.FLAG_DYNAMIC));
+                            | ShortcutInfo.FLAG_DYNAMIC);
+            ShortcutService.writeAttr(out, ATTR_FLAGS, flags);
+
+            // Set the publisher version code at every backup.
+            final int packageVersionCode = getPackageInfo().getVersionCode();
+            if (packageVersionCode == 0) {
+                s.wtf("Package version code should be available at this point.");
+                // However, 0 is a valid version code, so we just go ahead with it...
+            }
         } else {
             // When writing for backup, ranks shouldn't be saved, since shortcuts won't be restored
             // as dynamic.
@@ -1317,26 +1422,28 @@
             ShortcutService.writeAttr(out, ATTR_BITMAP_PATH, si.getBitmapPath());
         }
 
-        {
-            final Set<String> cat = si.getCategories();
-            if (cat != null && cat.size() > 0) {
-                out.startTag(null, TAG_CATEGORIES);
-                XmlUtils.writeStringArrayXml(cat.toArray(new String[cat.size()]),
-                        NAME_CATEGORIES, out);
-                out.endTag(null, TAG_CATEGORIES);
+        if (shouldBackupDetails) {
+            {
+                final Set<String> cat = si.getCategories();
+                if (cat != null && cat.size() > 0) {
+                    out.startTag(null, TAG_CATEGORIES);
+                    XmlUtils.writeStringArrayXml(cat.toArray(new String[cat.size()]),
+                            NAME_CATEGORIES, out);
+                    out.endTag(null, TAG_CATEGORIES);
+                }
             }
-        }
-        final Intent[] intentsNoExtras = si.getIntentsNoExtras();
-        final PersistableBundle[] intentsExtras = si.getIntentPersistableExtrases();
-        final int numIntents = intentsNoExtras.length;
-        for (int i = 0; i < numIntents; i++) {
-            out.startTag(null, TAG_INTENT);
-            ShortcutService.writeAttr(out, ATTR_INTENT_NO_EXTRA, intentsNoExtras[i]);
-            ShortcutService.writeTagExtra(out, TAG_EXTRAS, intentsExtras[i]);
-            out.endTag(null, TAG_INTENT);
-        }
+            final Intent[] intentsNoExtras = si.getIntentsNoExtras();
+            final PersistableBundle[] intentsExtras = si.getIntentPersistableExtrases();
+            final int numIntents = intentsNoExtras.length;
+            for (int i = 0; i < numIntents; i++) {
+                out.startTag(null, TAG_INTENT);
+                ShortcutService.writeAttr(out, ATTR_INTENT_NO_EXTRA, intentsNoExtras[i]);
+                ShortcutService.writeTagExtra(out, TAG_EXTRAS, intentsExtras[i]);
+                out.endTag(null, TAG_INTENT);
+            }
 
-        ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras());
+            ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras());
+        }
 
         out.endTag(null, TAG_SHORTCUT);
     }
@@ -1356,6 +1463,7 @@
         ret.mLastResetTime =
                 ShortcutService.parseLongAttribute(parser, ATTR_LAST_RESET);
 
+
         final int outerDepth = parser.getDepth();
         int type;
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -1369,10 +1477,11 @@
                 switch (tag) {
                     case ShortcutPackageInfo.TAG_ROOT:
                         ret.getPackageInfo().loadFromXml(parser, fromBackup);
+
                         continue;
                     case TAG_SHORTCUT:
                         final ShortcutInfo si = parseShortcut(parser, packageName,
-                                shortcutUser.getUserId());
+                                shortcutUser.getUserId(), fromBackup);
 
                         // Don't use addShortcut(), we don't need to save the icon.
                         ret.mShortcuts.put(si.getId(), si);
@@ -1385,7 +1494,8 @@
     }
 
     private static ShortcutInfo parseShortcut(XmlPullParser parser, String packageName,
-            @UserIdInt int userId) throws IOException, XmlPullParserException {
+            @UserIdInt int userId, boolean fromBackup)
+            throws IOException, XmlPullParserException {
         String id;
         ComponentName activityComponent;
         // Icon icon;
@@ -1398,6 +1508,7 @@
         String disabledMessage;
         int disabledMessageResId;
         String disabledMessageResName;
+        int disabledReason;
         Intent intentLegacy;
         PersistableBundle intentPersistableExtrasLegacy = null;
         ArrayList<Intent> intents = new ArrayList<>();
@@ -1408,6 +1519,7 @@
         int iconResId;
         String iconResName;
         String bitmapPath;
+        int backupVersionCode;
         ArraySet<String> categories = null;
 
         id = ShortcutService.parseStringAttribute(parser, ATTR_ID);
@@ -1424,6 +1536,7 @@
                 ATTR_DISABLED_MESSAGE_RES_ID);
         disabledMessageResName = ShortcutService.parseStringAttribute(parser,
                 ATTR_DISABLED_MESSAGE_RES_NAME);
+        disabledReason = ShortcutService.parseIntAttribute(parser, ATTR_DISABLED_REASON);
         intentLegacy = ShortcutService.parseIntentAttributeNoDefault(parser, ATTR_INTENT_LEGACY);
         rank = (int) ShortcutService.parseLongAttribute(parser, ATTR_RANK);
         lastChangedTimestamp = ShortcutService.parseLongAttribute(parser, ATTR_TIMESTAMP);
@@ -1480,6 +1593,19 @@
             intents.add(intentLegacy);
         }
 
+
+        if ((disabledReason == ShortcutInfo.DISABLED_REASON_NOT_DISABLED)
+                && ((flags & ShortcutInfo.FLAG_DISABLED) != 0)) {
+            // We didn't used to have the disabled reason, so if a shortcut is disabled
+            // and has no reason, we assume it was disabled by publisher.
+            disabledReason = ShortcutInfo.DISABLED_REASON_BY_APP;
+        }
+
+        // All restored shortcuts are initially "shadow".
+        if (fromBackup) {
+            flags |= ShortcutInfo.FLAG_SHADOW;
+        }
+
         return new ShortcutInfo(
                 userId, id, packageName, activityComponent, /* icon =*/ null,
                 title, titleResId, titleResName, text, textResId, textResName,
@@ -1487,7 +1613,7 @@
                 categories,
                 intents.toArray(new Intent[intents.size()]),
                 rank, extras, lastChangedTimestamp, flags,
-                iconResId, iconResName, bitmapPath);
+                iconResId, iconResName, bitmapPath, disabledReason);
     }
 
     private static Intent parseIntent(XmlPullParser parser)
@@ -1602,6 +1728,20 @@
                 Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
                         + " has both resource and bitmap icons");
             }
+            if (si.isEnabled()
+                    != (si.getDisabledReason() == ShortcutInfo.DISABLED_REASON_NOT_DISABLED)) {
+                failed = true;
+                Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
+                        + " isEnabled() and getDisabledReason() disagree: "
+                        + si.isEnabled() + " vs " + si.getDisabledReason());
+            }
+            if ((si.getDisabledReason() == ShortcutInfo.DISABLED_REASON_VERSION_LOWER)
+                    && (getPackageInfo().getBackupSourceVersionCode()
+                    == ShortcutInfo.VERSION_CODE_UNKNOWN)) {
+                failed = true;
+                Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
+                        + " RESTORED_VERSION_LOWER with no backup source version code.");
+            }
             if (s.isDummyMainActivity(si.getActivity())) {
                 failed = true;
                 Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
index e5a2f5a..3a9bbc8 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
@@ -18,6 +18,7 @@
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
 import android.content.pm.PackageInfo;
+import android.content.pm.ShortcutInfo;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -45,32 +46,45 @@
     static final String TAG_ROOT = "package-info";
     private static final String ATTR_VERSION = "version";
     private static final String ATTR_LAST_UPDATE_TIME = "last_udpate_time";
+    private static final String ATTR_BACKUP_SOURCE_VERSION = "bk_src_version";
+    private static final String ATTR_BACKUP_ALLOWED = "allow-backup";
+    private static final String ATTR_BACKUP_SOURCE_BACKUP_ALLOWED = "bk_src_backup-allowed";
     private static final String ATTR_SHADOW = "shadow";
 
     private static final String TAG_SIGNATURE = "signature";
     private static final String ATTR_SIGNATURE_HASH = "hash";
 
-    private static final int VERSION_UNKNOWN = -1;
-
     /**
      * When true, this package information was restored from the previous device, and the app hasn't
      * been installed yet.
      */
     private boolean mIsShadow;
-    private int mVersionCode = VERSION_UNKNOWN;
+    private int mVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN;
+    private int mBackupSourceVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN;
     private long mLastUpdateTime;
     private ArrayList<byte[]> mSigHashes;
 
+    // mBackupAllowed didn't used to be parsisted, so we don't restore it from a file.
+    // mBackupAllowed will always start with false, and will have been updated before making a
+    // backup next time, which works file.
+    // We just don't want to print an uninitialzied mBackupAlldowed value on dumpsys, so
+    // we use this boolean to control dumpsys.
+    private boolean mBackupAllowedInitialized;
+    private boolean mBackupAllowed;
+    private boolean mBackupSourceBackupAllowed;
+
     private ShortcutPackageInfo(int versionCode, long lastUpdateTime,
             ArrayList<byte[]> sigHashes, boolean isShadow) {
         mVersionCode = versionCode;
         mLastUpdateTime = lastUpdateTime;
         mIsShadow = isShadow;
         mSigHashes = sigHashes;
+        mBackupAllowed = false; // By default, we assume false.
+        mBackupSourceBackupAllowed = false;
     }
 
     public static ShortcutPackageInfo newEmpty() {
-        return new ShortcutPackageInfo(VERSION_UNKNOWN, /* last update time =*/ 0,
+        return new ShortcutPackageInfo(ShortcutInfo.VERSION_CODE_UNKNOWN, /* last update time =*/ 0,
                 new ArrayList<>(0), /* isShadow */ false);
     }
 
@@ -86,15 +100,33 @@
         return mVersionCode;
     }
 
+    public int getBackupSourceVersionCode() {
+        return mBackupSourceVersionCode;
+    }
+
+    @VisibleForTesting
+    public boolean isBackupSourceBackupAllowed() {
+        return mBackupSourceBackupAllowed;
+    }
+
     public long getLastUpdateTime() {
         return mLastUpdateTime;
     }
 
-    /** Set {@link #mVersionCode} and {@link #mLastUpdateTime} from a {@link PackageInfo}. */
-    public void updateVersionInfo(@NonNull PackageInfo pi) {
+    public boolean isBackupAllowed() {
+        return mBackupAllowed;
+    }
+
+    /**
+     * Set {@link #mVersionCode}, {@link #mLastUpdateTime} and {@link #mBackupAllowed}
+     * from a {@link PackageInfo}.
+     */
+    public void updateFromPackageInfo(@NonNull PackageInfo pi) {
         if (pi != null) {
             mVersionCode = pi.versionCode;
             mLastUpdateTime = pi.lastUpdateTime;
+            mBackupAllowed = ShortcutService.shouldBackupApp(pi);
+            mBackupAllowedInitialized = true;
         }
     }
 
@@ -102,23 +134,24 @@
         return mSigHashes.size() > 0;
     }
 
-    public boolean canRestoreTo(ShortcutService s, PackageInfo target) {
-        if (!s.shouldBackupApp(target)) {
-            // "allowBackup" was true when backed up, but now false.
-            Slog.w(TAG, "Can't restore: package no longer allows backup");
-            return false;
+    //@DisabledReason
+    public int canRestoreTo(ShortcutService s, PackageInfo currentPackage, boolean anyVersionOkay) {
+        if (!BackupUtils.signaturesMatch(mSigHashes, currentPackage)) {
+            Slog.w(TAG, "Can't restore: Package signature mismatch");
+            return ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH;
         }
-        if (target.versionCode < mVersionCode) {
+        if (!ShortcutService.shouldBackupApp(currentPackage) || !mBackupSourceBackupAllowed) {
+            // "allowBackup" was true when backed up, but now false.
+            Slog.w(TAG, "Can't restore: package didn't or doesn't allow backup");
+            return ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED;
+        }
+        if (!anyVersionOkay && (currentPackage.versionCode < mBackupSourceVersionCode)) {
             Slog.w(TAG, String.format(
                     "Can't restore: package current version %d < backed up version %d",
-                    target.versionCode, mVersionCode));
-            return false;
+                    currentPackage.versionCode, mBackupSourceVersionCode));
+            return ShortcutInfo.DISABLED_REASON_VERSION_LOWER;
         }
-        if (!BackupUtils.signaturesMatch(mSigHashes, target)) {
-            Slog.w(TAG, "Can't restore: Package signature mismatch");
-            return false;
-        }
-        return true;
+        return ShortcutInfo.DISABLED_REASON_NOT_DISABLED;
     }
 
     @VisibleForTesting
@@ -132,6 +165,8 @@
         final ShortcutPackageInfo ret = new ShortcutPackageInfo(pi.versionCode, pi.lastUpdateTime,
                 BackupUtils.hashSignatureArray(pi.signatures), /* shadow=*/ false);
 
+        ret.mBackupSourceBackupAllowed = s.shouldBackupApp(pi);
+        ret.mBackupSourceVersionCode = pi.versionCode;
         return ret;
     }
 
@@ -151,13 +186,19 @@
         mSigHashes = BackupUtils.hashSignatureArray(pi.signatures);
     }
 
-    public void saveToXml(XmlSerializer out) throws IOException {
+    public void saveToXml(XmlSerializer out, boolean forBackup) throws IOException {
 
         out.startTag(null, TAG_ROOT);
 
         ShortcutService.writeAttr(out, ATTR_VERSION, mVersionCode);
         ShortcutService.writeAttr(out, ATTR_LAST_UPDATE_TIME, mLastUpdateTime);
         ShortcutService.writeAttr(out, ATTR_SHADOW, mIsShadow);
+        ShortcutService.writeAttr(out, ATTR_BACKUP_ALLOWED, mBackupAllowed);
+
+        ShortcutService.writeAttr(out, ATTR_BACKUP_SOURCE_VERSION, mBackupSourceVersionCode);
+        ShortcutService.writeAttr(out,
+                ATTR_BACKUP_SOURCE_BACKUP_ALLOWED, mBackupSourceBackupAllowed);
+
 
         for (int i = 0; i < mSigHashes.size(); i++) {
             out.startTag(null, TAG_SIGNATURE);
@@ -171,7 +212,9 @@
     public void loadFromXml(XmlPullParser parser, boolean fromBackup)
             throws IOException, XmlPullParserException {
 
-        final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION);
+        // Don't use the version code from the backup file.
+        final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION,
+                ShortcutInfo.VERSION_CODE_UNKNOWN);
 
         final long lastUpdateTime = ShortcutService.parseLongAttribute(
                 parser, ATTR_LAST_UPDATE_TIME);
@@ -180,6 +223,20 @@
         final boolean shadow =
                 fromBackup || ShortcutService.parseBooleanAttribute(parser, ATTR_SHADOW);
 
+        // We didn't used to save these attributes, and all backed up shortcuts were from
+        // apps that support backups, so the default values take this fact into consideration.
+        final int backupSourceVersion = ShortcutService.parseIntAttribute(parser,
+                ATTR_BACKUP_SOURCE_VERSION, ShortcutInfo.VERSION_CODE_UNKNOWN);
+
+        // Note the only time these "true" default value is used is when restoring from an old
+        // build that didn't save ATTR_BACKUP_ALLOWED, and that means all the data included in
+        // a backup file were from apps that support backup, so we can just use "true" as the
+        // default.
+        final boolean backupAllowed = ShortcutService.parseBooleanAttribute(
+                parser, ATTR_BACKUP_ALLOWED, true);
+        final boolean backupSourceBackupAllowed = ShortcutService.parseBooleanAttribute(
+                parser, ATTR_BACKUP_SOURCE_BACKUP_ALLOWED, true);
+
         final ArrayList<byte[]> hashes = new ArrayList<>();
 
         final int outerDepth = parser.getDepth();
@@ -207,11 +264,28 @@
             ShortcutService.warnForInvalidTag(depth, tag);
         }
 
-        // Successfully loaded; replace the feilds.
-        mVersionCode = versionCode;
+        // Successfully loaded; replace the fields.
+        if (fromBackup) {
+            mVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN;
+            mBackupSourceVersionCode = versionCode;
+            mBackupSourceBackupAllowed = backupAllowed;
+        } else {
+            mVersionCode = versionCode;
+            mBackupSourceVersionCode = backupSourceVersion;
+            mBackupSourceBackupAllowed = backupSourceBackupAllowed;
+        }
         mLastUpdateTime = lastUpdateTime;
         mIsShadow = shadow;
         mSigHashes = hashes;
+
+        // Note we don't restore it from the file because it didn't used to be saved.
+        // We always start by assuming backup is disabled for the current package,
+        // and this field will have been updated before we actually create a backup, at the same
+        // time when we update the version code.
+        // Until then, the value of mBackupAllowed shouldn't matter, but we don't want to print
+        // a false flag on dumpsys, so set mBackupAllowedInitialized to false.
+        mBackupAllowed = false;
+        mBackupAllowedInitialized = false;
     }
 
     public void dump(PrintWriter pw, String prefix) {
@@ -223,6 +297,7 @@
         pw.print(prefix);
         pw.print("  IsShadow: ");
         pw.print(mIsShadow);
+        pw.print(mIsShadow ? " (not installed)" : " (installed)");
         pw.println();
 
         pw.print(prefix);
@@ -230,6 +305,25 @@
         pw.print(mVersionCode);
         pw.println();
 
+        if (mBackupAllowedInitialized) {
+            pw.print(prefix);
+            pw.print("  Backup Allowed: ");
+            pw.print(mBackupAllowed);
+            pw.println();
+        }
+
+        if (mBackupSourceVersionCode != ShortcutInfo.VERSION_CODE_UNKNOWN) {
+            pw.print(prefix);
+            pw.print("  Backup source version: ");
+            pw.print(mBackupSourceVersionCode);
+            pw.println();
+
+            pw.print(prefix);
+            pw.print("  Backup source backup allowed: ");
+            pw.print(mBackupSourceBackupAllowed);
+            pw.println();
+        }
+
         pw.print(prefix);
         pw.print("  Last package update time: ");
         pw.print(mLastUpdateTime);
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
index e59d69f..689099c 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -17,6 +17,7 @@
 
 import android.annotation.NonNull;
 import android.content.pm.PackageInfo;
+import android.content.pm.ShortcutInfo;
 import android.util.Slog;
 
 import com.android.internal.util.Preconditions;
@@ -101,51 +102,42 @@
         final ShortcutService s = mShortcutUser.mService;
         if (!s.isPackageInstalled(mPackageName, mPackageUserId)) {
             if (ShortcutService.DEBUG) {
-                Slog.d(TAG, String.format("Package still not installed: %s user=%d",
+                Slog.d(TAG, String.format("Package still not installed: %s/u%d",
                         mPackageName, mPackageUserId));
             }
             return; // Not installed, no need to restore yet.
         }
-        boolean blockRestore = false;
-        if (!mPackageInfo.hasSignatures()) {
-            s.wtf("Attempted to restore package " + mPackageName + ", user=" + mPackageUserId
-                    + " but signatures not found in the restore data.");
-            blockRestore = true;
-        }
-        if (!blockRestore) {
-            final PackageInfo pi = s.getPackageInfoWithSignatures(mPackageName, mPackageUserId);
-            if (!mPackageInfo.canRestoreTo(s, pi)) {
-                // Package is now installed, but can't restore.  Let the subclass do the cleanup.
-                blockRestore = true;
-            }
-        }
-        if (blockRestore) {
-            onRestoreBlocked();
-        } else {
-            if (ShortcutService.DEBUG) {
-                Slog.d(TAG, String.format("Restored package: %s/%d on user %d", mPackageName,
-                        mPackageUserId, getOwnerUserId()));
-            }
+        int restoreBlockReason;
+        int currentVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN;
 
-            onRestored();
+        if (!mPackageInfo.hasSignatures()) {
+            s.wtf("Attempted to restore package " + mPackageName + "/u" + mPackageUserId
+                    + " but signatures not found in the restore data.");
+            restoreBlockReason = ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH;
+        } else {
+            final PackageInfo pi = s.getPackageInfoWithSignatures(mPackageName, mPackageUserId);
+            currentVersionCode = pi.versionCode;
+            restoreBlockReason = mPackageInfo.canRestoreTo(s, pi, canRestoreAnyVersion());
         }
 
+        if (ShortcutService.DEBUG) {
+            Slog.d(TAG, String.format("Restoring package: %s/u%d (version=%d) %s for u%d",
+                    mPackageName, mPackageUserId, currentVersionCode,
+                    ShortcutInfo.getDisabledReasonDebugString(restoreBlockReason),
+                    getOwnerUserId()));
+        }
+
+        onRestored(restoreBlockReason);
+
         // Either way, it's no longer a shadow.
         mPackageInfo.setShadow(false);
 
         s.scheduleSaveUser(mPackageUserId);
     }
 
-    /**
-     * Called when the new package can't be restored because it has a lower version number
-     * or different signatures.
-     */
-    protected abstract void onRestoreBlocked();
+    protected abstract boolean canRestoreAnyVersion();
 
-    /**
-     * Called when the new package is successfully restored.
-     */
-    protected abstract void onRestored();
+    protected abstract void onRestored(int restoreBlockReason);
 
     public abstract void saveToXml(@NonNull XmlSerializer out, boolean forBackup)
             throws IOException, XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/ShortcutParser.java b/services/core/java/com/android/server/pm/ShortcutParser.java
index 3cf4200..866c46c 100644
--- a/services/core/java/com/android/server/pm/ShortcutParser.java
+++ b/services/core/java/com/android/server/pm/ShortcutParser.java
@@ -337,6 +337,9 @@
                 (enabled ? ShortcutInfo.FLAG_MANIFEST : ShortcutInfo.FLAG_DISABLED)
                 | ShortcutInfo.FLAG_IMMUTABLE
                 | ((iconResId != 0) ? ShortcutInfo.FLAG_HAS_ICON_RES : 0);
+        final int disabledReason =
+                enabled ? ShortcutInfo.DISABLED_REASON_NOT_DISABLED
+                        : ShortcutInfo.DISABLED_REASON_BY_APP;
 
         // Note we don't need to set resource names here yet.  They'll be set when they're about
         // to be published.
@@ -363,6 +366,7 @@
                 flags,
                 iconResId,
                 null, // icon res name
-                null); // bitmap path
+                null, // bitmap path
+                disabledReason);
     }
 }
diff --git a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
index 8a8128d..3e44de9 100644
--- a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
+++ b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
@@ -300,10 +300,12 @@
 
         final ShortcutInfo existing = ps.findShortcutById(inShortcut.getId());
         final boolean existsAlready = existing != null;
+        final boolean existingIsVisible = existsAlready && existing.isVisibleToPublisher();
 
         if (DEBUG) {
             Slog.d(TAG, "requestPinnedShortcut: package=" + inShortcut.getPackage()
                     + " existsAlready=" + existsAlready
+                    + " existingIsVisible=" + existingIsVisible
                     + " shortcut=" + inShortcut.toInsecureString());
         }
 
@@ -378,7 +380,6 @@
         // manifest shortcut.)
         Preconditions.checkArgument(shortcutInfo.isEnabled(),
                 "Shortcut ID=" + shortcutInfo + " already exists but disabled.");
-
     }
 
     private boolean startRequestConfirmActivity(ComponentName activity, int launcherUserId,
@@ -463,7 +464,7 @@
             launcher.attemptToRestoreIfNeededAndSave();
             if (launcher.hasPinned(original)) {
                 if (DEBUG) {
-                    Slog.d(TAG, "Shortcut " + original + " already pinned.");
+                    Slog.d(TAG, "Shortcut " + original + " already pinned.");                       // This too.
                 }
                 return true;
             }
@@ -497,7 +498,7 @@
                 if (original.getActivity() == null) {
                     original.setActivity(mService.getDummyMainActivity(appPackageName));
                 }
-                ps.addOrUpdateDynamicShortcut(original);
+                ps.addOrReplaceDynamicShortcut(original);
             }
 
             // Pin the shortcut.
@@ -505,13 +506,14 @@
                 Slog.d(TAG, "Pinning " + shortcutId);
             }
 
-            launcher.addPinnedShortcut(appPackageName, appUserId, shortcutId);
+            launcher.addPinnedShortcut(appPackageName, appUserId, shortcutId,
+                    /*forPinRequest=*/ true);
 
             if (current == null) {
                 if (DEBUG) {
                     Slog.d(TAG, "Removing " + shortcutId + " as dynamic");
                 }
-                ps.deleteDynamicWithId(shortcutId);
+                ps.deleteDynamicWithId(shortcutId, /*ignoreInvisible=*/ false);
             }
 
             ps.adjustRanks(); // Shouldn't be needed, but just in case.
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 27560c5f..1c002aa 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -553,6 +553,9 @@
 
         public Lifecycle(Context context) {
             super(context);
+            if (DEBUG) {
+                Binder.LOG_RUNTIME_EXCEPTION = true;
+            }
             mService = new ShortcutService(context);
         }
 
@@ -738,6 +741,10 @@
         return parseLongAttribute(parser, attribute) == 1;
     }
 
+    static boolean parseBooleanAttribute(XmlPullParser parser, String attribute, boolean def) {
+        return parseLongAttribute(parser, attribute, (def ? 1 : 0)) == 1;
+    }
+
     static int parseIntAttribute(XmlPullParser parser, String attribute) {
         return (int) parseLongAttribute(parser, attribute);
     }
@@ -835,6 +842,8 @@
     static void writeAttr(XmlSerializer out, String name, boolean value) throws IOException {
         if (value) {
             writeAttr(out, name, "1");
+        } else {
+            writeAttr(out, name, "0");
         }
     }
 
@@ -1689,7 +1698,7 @@
 
             final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
 
-            ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
+            ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true);
 
             fillInDefaultActivity(newShortcuts);
 
@@ -1709,12 +1718,12 @@
             }
 
             // First, remove all un-pinned; dynamic shortcuts
-            ps.deleteAllDynamicShortcuts();
+            ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true);
 
             // Then, add/update all.  We need to make sure to take over "pinned" flag.
             for (int i = 0; i < size; i++) {
                 final ShortcutInfo newShortcut = newShortcuts.get(i);
-                ps.addOrUpdateDynamicShortcut(newShortcut);
+                ps.addOrReplaceDynamicShortcut(newShortcut);
             }
 
             // Lastly, adjust the ranks.
@@ -1740,7 +1749,7 @@
 
             final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
 
-            ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
+            ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true);
 
             // For update, don't fill in the default activity.  Having null activity means
             // "don't update the activity" here.
@@ -1761,7 +1770,9 @@
                 fixUpIncomingShortcutInfo(source, /* forUpdate= */ true);
 
                 final ShortcutInfo target = ps.findShortcutById(source.getId());
-                if (target == null) {
+
+                // Invisible shortcuts can't be updated.
+                if (target == null || !target.isVisibleToPublisher()) {
                     continue;
                 }
 
@@ -1808,7 +1819,7 @@
     }
 
     @Override
-    public boolean addDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList,
+    public boolean  addDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList,
             @UserIdInt int userId) {
         verifyCaller(packageName, userId);
 
@@ -1820,7 +1831,7 @@
 
             final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
 
-            ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
+            ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true);
 
             fillInDefaultActivity(newShortcuts);
 
@@ -1845,7 +1856,7 @@
                 newShortcut.setRankChanged();
 
                 // Add it.
-                ps.addOrUpdateDynamicShortcut(newShortcut);
+                ps.addOrReplaceDynamicShortcut(newShortcut);
             }
 
             // Lastly, adjust the ranks.
@@ -1901,6 +1912,22 @@
             Preconditions.checkState(isUidForegroundLocked(injectBinderCallingUid()),
                     "Calling application must have a foreground activity or a foreground service");
 
+            // If it's a pin shortcut request, and there's already a shortcut with the same ID
+            // that's not visible to the caller (i.e. restore-blocked; meaning it's pinned by
+            // someone already), then we just replace the existing one with this new one,
+            // and then proceed the rest of the process.
+            if (shortcut != null) {
+                final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(
+                        packageName, userId);
+                final String id = shortcut.getId();
+                if (ps.isShortcutExistsAndInvisibleToPublisher(id)) {
+
+                    ps.updateInvisibleShortcutForPinRequestWith(shortcut);
+
+                    packageShortcutsChanged(packageName, userId);
+                }
+            }
+
             // Send request to the launcher, if supported.
             ret = mShortcutRequestPinProcessor.requestPinItemLocked(shortcut, appWidget, extras,
                     userId, resultIntent);
@@ -1922,15 +1949,21 @@
 
             final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
 
-            ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds);
+            ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds,
+                    /*ignoreInvisible=*/ true);
 
             final String disabledMessageString =
                     (disabledMessage == null) ? null : disabledMessage.toString();
 
             for (int i = shortcutIds.size() - 1; i >= 0; i--) {
-                ps.disableWithId(Preconditions.checkStringNotEmpty((String) shortcutIds.get(i)),
+                final String id = Preconditions.checkStringNotEmpty((String) shortcutIds.get(i));
+                if (!ps.isShortcutExistsAndVisibleToPublisher(id)) {
+                    continue;
+                }
+                ps.disableWithId(id,
                         disabledMessageString, disabledMessageResId,
-                        /* overrideImmutable=*/ false);
+                        /* overrideImmutable=*/ false, /*ignoreInvisible=*/ true,
+                        ShortcutInfo.DISABLED_REASON_BY_APP);
             }
 
             // We may have removed dynamic shortcuts which may have left a gap, so adjust the ranks.
@@ -1951,10 +1984,15 @@
 
             final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
 
-            ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds);
+            ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds,
+                    /*ignoreInvisible=*/ true);
 
             for (int i = shortcutIds.size() - 1; i >= 0; i--) {
-                ps.enableWithId((String) shortcutIds.get(i));
+                final String id = Preconditions.checkStringNotEmpty((String) shortcutIds.get(i));
+                if (!ps.isShortcutExistsAndVisibleToPublisher(id)) {
+                    continue;
+                }
+                ps.enableWithId(id);
             }
         }
         packageShortcutsChanged(packageName, userId);
@@ -1973,11 +2011,15 @@
 
             final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
 
-            ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds);
+            ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds,
+                    /*ignoreInvisible=*/ true);
 
             for (int i = shortcutIds.size() - 1; i >= 0; i--) {
-                ps.deleteDynamicWithId(
-                        Preconditions.checkStringNotEmpty((String) shortcutIds.get(i)));
+                final String id = Preconditions.checkStringNotEmpty((String) shortcutIds.get(i));
+                if (!ps.isShortcutExistsAndVisibleToPublisher(id)) {
+                    continue;
+                }
+                ps.deleteDynamicWithId(id, /*ignoreInvisible=*/ true);
             }
 
             // We may have removed dynamic shortcuts which may have left a gap, so adjust the ranks.
@@ -1996,7 +2038,7 @@
             throwIfUserLockedL(userId);
 
             final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
-            ps.deleteAllDynamicShortcuts();
+            ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true);
         }
         packageShortcutsChanged(packageName, userId);
 
@@ -2013,7 +2055,7 @@
 
             return getShortcutsWithQueryLocked(
                     packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
-                    ShortcutInfo::isDynamic);
+                    ShortcutInfo::isDynamicVisible);
         }
     }
 
@@ -2027,7 +2069,7 @@
 
             return getShortcutsWithQueryLocked(
                     packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
-                    ShortcutInfo::isManifestShortcut);
+                    ShortcutInfo::isManifestVisible);
         }
     }
 
@@ -2041,7 +2083,7 @@
 
             return getShortcutsWithQueryLocked(
                     packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
-                    ShortcutInfo::isPinned);
+                    ShortcutInfo::isPinnedVisible);
         }
     }
 
@@ -2190,7 +2232,11 @@
     }
 
     // We override this method in unit tests to do a simpler check.
-    boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId) {
+    boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId,
+            int callingPid, int callingUid) {
+        if (injectCheckAccessShortcutsPermission(callingPid, callingUid)) {
+            return true;
+        }
         final long start = injectElapsedRealtime();
         try {
             return hasShortcutHostPermissionInner(callingPackage, userId);
@@ -2199,6 +2245,14 @@
         }
     }
 
+    /**
+     * Returns true if the caller has the "ACCESS_SHORTCUTS" permission.
+     */
+    boolean injectCheckAccessShortcutsPermission(int callingPid, int callingUid) {
+        return mContext.checkPermission(android.Manifest.permission.ACCESS_SHORTCUTS,
+                callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
+    }
+
     // This method is extracted so we can directly call this method from unit tests,
     // even when hasShortcutPermission() is overridden.
     @VisibleForTesting
@@ -2379,7 +2433,7 @@
                 @NonNull String callingPackage, long changedSince,
                 @Nullable String packageName, @Nullable List<String> shortcutIds,
                 @Nullable ComponentName componentName,
-                int queryFlags, int userId) {
+                int queryFlags, int userId, int callingPid, int callingUid) {
             final ArrayList<ShortcutInfo> ret = new ArrayList<>();
 
             final boolean cloneKeyFieldOnly =
@@ -2400,13 +2454,15 @@
                 if (packageName != null) {
                     getShortcutsInnerLocked(launcherUserId,
                             callingPackage, packageName, shortcutIds, changedSince,
-                            componentName, queryFlags, userId, ret, cloneFlag);
+                            componentName, queryFlags, userId, ret, cloneFlag,
+                            callingPid, callingUid);
                 } else {
                     final List<String> shortcutIdsF = shortcutIds;
                     getUserShortcutsLocked(userId).forAllPackages(p -> {
                         getShortcutsInnerLocked(launcherUserId,
                                 callingPackage, p.getPackageName(), shortcutIdsF, changedSince,
-                                componentName, queryFlags, userId, ret, cloneFlag);
+                                componentName, queryFlags, userId, ret, cloneFlag,
+                                callingPid, callingUid);
                     });
                 }
             }
@@ -2416,7 +2472,8 @@
         private void getShortcutsInnerLocked(int launcherUserId, @NonNull String callingPackage,
                 @Nullable String packageName, @Nullable List<String> shortcutIds, long changedSince,
                 @Nullable ComponentName componentName, int queryFlags,
-                int userId, ArrayList<ShortcutInfo> ret, int cloneFlag) {
+                int userId, ArrayList<ShortcutInfo> ret, int cloneFlag,
+                int callingPid, int callingUid) {
             final ArraySet<String> ids = shortcutIds == null ? null
                     : new ArraySet<>(shortcutIds);
 
@@ -2425,6 +2482,13 @@
             if (p == null) {
                 return; // No need to instantiate ShortcutPackage.
             }
+            final boolean matchDynamic = (queryFlags & ShortcutQuery.FLAG_MATCH_DYNAMIC) != 0;
+            final boolean matchPinned = (queryFlags & ShortcutQuery.FLAG_MATCH_PINNED) != 0;
+            final boolean matchManifest = (queryFlags & ShortcutQuery.FLAG_MATCH_MANIFEST) != 0;
+
+            final boolean getPinnedByAnyLauncher =
+                    ((queryFlags & ShortcutQuery.FLAG_MATCH_ALL_PINNED) != 0)
+                    && injectCheckAccessShortcutsPermission(callingPid, callingUid);
 
             p.findAll(ret,
                     (ShortcutInfo si) -> {
@@ -2440,20 +2504,17 @@
                                 return false;
                             }
                         }
-                        if (((queryFlags & ShortcutQuery.FLAG_GET_DYNAMIC) != 0)
-                                && si.isDynamic()) {
+                        if (matchDynamic && si.isDynamic()) {
                             return true;
                         }
-                        if (((queryFlags & ShortcutQuery.FLAG_GET_PINNED) != 0)
-                                && si.isPinned()) {
+                        if ((matchPinned && si.isPinned()) || getPinnedByAnyLauncher) {
                             return true;
                         }
-                        if (((queryFlags & ShortcutQuery.FLAG_GET_MANIFEST) != 0)
-                                && si.isManifestShortcut()) {
+                        if (matchManifest && si.isDeclaredInManifest()) {
                             return true;
                         }
                         return false;
-                    }, cloneFlag, callingPackage, launcherUserId);
+                    }, cloneFlag, callingPackage, launcherUserId, getPinnedByAnyLauncher);
         }
 
         @Override
@@ -2470,14 +2531,16 @@
                         .attemptToRestoreIfNeededAndSave();
 
                 final ShortcutInfo si = getShortcutInfoLocked(
-                        launcherUserId, callingPackage, packageName, shortcutId, userId);
+                        launcherUserId, callingPackage, packageName, shortcutId, userId,
+                        /*getPinnedByAnyLauncher=*/ false);
                 return si != null && si.isPinned();
             }
         }
 
         private ShortcutInfo getShortcutInfoLocked(
                 int launcherUserId, @NonNull String callingPackage,
-                @NonNull String packageName, @NonNull String shortcutId, int userId) {
+                @NonNull String packageName, @NonNull String shortcutId, int userId,
+                boolean getPinnedByAnyLauncher) {
             Preconditions.checkStringNotEmpty(packageName, "packageName");
             Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");
 
@@ -2493,7 +2556,7 @@
             final ArrayList<ShortcutInfo> list = new ArrayList<>(1);
             p.findAll(list,
                     (ShortcutInfo si) -> shortcutId.equals(si.getId()),
-                    /* clone flags=*/ 0, callingPackage, launcherUserId);
+                    /* clone flags=*/ 0, callingPackage, launcherUserId, getPinnedByAnyLauncher);
             return list.size() == 0 ? null : list.get(0);
         }
 
@@ -2513,7 +2576,7 @@
                         getLauncherShortcutsLocked(callingPackage, userId, launcherUserId);
                 launcher.attemptToRestoreIfNeededAndSave();
 
-                launcher.pinShortcuts(userId, packageName, shortcutIds);
+                launcher.pinShortcuts(userId, packageName, shortcutIds, /*forPinRequest=*/ false);
             }
             packageShortcutsChanged(packageName, userId);
 
@@ -2523,7 +2586,8 @@
         @Override
         public Intent[] createShortcutIntents(int launcherUserId,
                 @NonNull String callingPackage,
-                @NonNull String packageName, @NonNull String shortcutId, int userId) {
+                @NonNull String packageName, @NonNull String shortcutId, int userId,
+                int callingPid, int callingUid) {
             // Calling permission must be checked by LauncherAppsImpl.
             Preconditions.checkStringNotEmpty(packageName, "packageName can't be empty");
             Preconditions.checkStringNotEmpty(shortcutId, "shortcutId can't be empty");
@@ -2535,9 +2599,13 @@
                 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
                         .attemptToRestoreIfNeededAndSave();
 
+                final boolean getPinnedByAnyLauncher =
+                        injectCheckAccessShortcutsPermission(callingPid, callingUid);
+
                 // Make sure the shortcut is actually visible to the launcher.
                 final ShortcutInfo si = getShortcutInfoLocked(
-                        launcherUserId, callingPackage, packageName, shortcutId, userId);
+                        launcherUserId, callingPackage, packageName, shortcutId, userId,
+                        getPinnedByAnyLauncher);
                 // "si == null" should suffice here, but check the flags too just to make sure.
                 if (si == null || !si.isEnabled() || !si.isAlive()) {
                     Log.e(TAG, "Shortcut " + shortcutId + " does not exist or disabled");
@@ -2623,8 +2691,9 @@
 
         @Override
         public boolean hasShortcutHostPermission(int launcherUserId,
-                @NonNull String callingPackage) {
-            return ShortcutService.this.hasShortcutHostPermission(callingPackage, launcherUserId);
+                @NonNull String callingPackage, int callingPid, int callingUid) {
+            return ShortcutService.this.hasShortcutHostPermission(callingPackage, launcherUserId,
+                    callingPid, callingUid);
         }
 
         @Override
@@ -3343,7 +3412,7 @@
         return isApplicationFlagSet(packageName, userId, ApplicationInfo.FLAG_ALLOW_BACKUP);
     }
 
-    boolean shouldBackupApp(PackageInfo pi) {
+    static boolean shouldBackupApp(PackageInfo pi) {
         return (pi.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0;
     }
 
@@ -3371,7 +3440,7 @@
             // Set the version code for the launchers.
             // We shouldn't do this for publisher packages, because we don't want to update the
             // version code without rescanning the manifest.
-            user.forAllLaunchers(launcher -> launcher.ensureVersionInfo());
+            user.forAllLaunchers(launcher -> launcher.ensurePackageInfo());
 
             // Save to the filesystem.
             scheduleSaveUser(userId);
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 55e6d28a..48eccd0 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -364,9 +364,6 @@
     private void saveShortcutPackageItem(XmlSerializer out,
             ShortcutPackageItem spi, boolean forBackup) throws IOException, XmlPullParserException {
         if (forBackup) {
-            if (!mService.shouldBackupApp(spi.getPackageName(), spi.getPackageUserId())) {
-                return; // Don't save.
-            }
             if (spi.getPackageUserId() != spi.getOwnerUserId()) {
                 return; // Don't save cross-user information.
             }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 062aa33..d2d857c 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -417,8 +417,8 @@
                 bp = new BasePermission(info.name, tree.getSourcePackageName(),
                         BasePermission.TYPE_DYNAMIC);
             } else if (bp.isDynamic()) {
-                throw new SecurityException(
-                        "Not allowed to modify non-dynamic permission "
+                // TODO: switch this back to SecurityException
+                Slog.wtf(TAG, "Not allowed to modify non-dynamic permission "
                         + info.name);
             }
             changed = bp.addToTree(fixedLevel, info, tree);
@@ -444,8 +444,8 @@
                 return;
             }
             if (bp.isDynamic()) {
-                throw new SecurityException(
-                        "Not allowed to modify non-dynamic permission "
+                // TODO: switch this back to SecurityException
+                Slog.wtf(TAG, "Not allowed to modify non-dynamic permission "
                         + permName);
             }
             mSettings.removePermissionLocked(permName);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index d8e8fd3..6520dc9 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -553,7 +553,6 @@
 
     int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
     int mUserRotation = Surface.ROTATION_0;
-    boolean mAccelerometerDefault;
 
     boolean mSupportAutoRotation;
     int mAllowAllRotations = -1;
@@ -708,7 +707,6 @@
     Intent mVrHeadsetHomeIntent;
     boolean mSearchKeyShortcutPending;
     boolean mConsumeSearchKeyUp;
-    boolean mAssistKeyLongPressed;
     boolean mPendingMetaAction;
     boolean mPendingCapsLockToggle;
     int mMetaState;
@@ -839,6 +837,8 @@
     private static final int MSG_DISPATCH_BACK_KEY_TO_AUTOFILL = 24;
     private static final int MSG_SYSTEM_KEY_PRESS = 25;
     private static final int MSG_HANDLE_ALL_APPS = 26;
+    private static final int MSG_LAUNCH_ASSIST = 27;
+    private static final int MSG_LAUNCH_ASSIST_LONG_PRESS = 28;
 
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
@@ -880,8 +880,16 @@
                 case MSG_HIDE_BOOT_MESSAGE:
                     handleHideBootMessage();
                     break;
+                case MSG_LAUNCH_ASSIST:
+                    final int deviceId = msg.arg1;
+                    final String hint = (String) msg.obj;
+                    launchAssistAction(hint, deviceId);
+                    break;
+                case MSG_LAUNCH_ASSIST_LONG_PRESS:
+                    launchAssistLongPressAction();
+                    break;
                 case MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK:
-                    launchVoiceAssistWithWakeLock(msg.arg1 != 0);
+                    launchVoiceAssistWithWakeLock();
                     break;
                 case MSG_POWER_DELAYED_PRESS:
                     powerPress((Long)msg.obj, msg.arg1 != 0, msg.arg2);
@@ -911,7 +919,7 @@
                     disposeInputConsumer((InputConsumer) msg.obj);
                     break;
                 case MSG_BACK_DELAYED_PRESS:
-                    backMultiPressAction((Long) msg.obj, msg.arg1);
+                    backMultiPressAction(msg.arg1);
                     finishBackKeyPress();
                     break;
                 case MSG_ACCESSIBILITY_SHORTCUT:
@@ -1415,7 +1423,7 @@
         }
     }
 
-    private void backMultiPressAction(long eventTime, int count) {
+    private void backMultiPressAction(int count) {
         if (count >= PANIC_PRESS_BACK_COUNT) {
             switch (mPanicPressOnBackBehavior) {
                 case PANIC_PRESS_BACK_NOTHING:
@@ -1584,7 +1592,7 @@
         }
     }
 
-    private void sleepPress(long eventTime) {
+    private void sleepPress() {
         if (mShortPressOnSleepBehavior == SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME) {
             launchHomeFromHotKey(false /* awakenDreams */, true /*respectKeyguard*/);
         }
@@ -1646,11 +1654,23 @@
                 mScreenshotChordVolumeDownKeyConsumed = true;
                 mA11yShortcutChordVolumeUpKeyConsumed = true;
                 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_ACCESSIBILITY_SHORTCUT),
-                        ViewConfiguration.get(mContext).getAccessibilityShortcutKeyTimeout());
+                        getAccessibilityShortcutTimeout());
             }
         }
     }
 
+    private long getAccessibilityShortcutTimeout() {
+        ViewConfiguration config = ViewConfiguration.get(mContext);
+        try {
+            return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, mCurrentUserId) == 0
+                    ? config.getAccessibilityShortcutKeyTimeout()
+                    : config.getAccessibilityShortcutKeyTimeoutAfterConfirmation();
+        } catch (Settings.SettingNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     private long getScreenshotChordLongPressDelay() {
         if (mKeyguardDelegate.isShowing()) {
             // Double the time it takes to take a screenshot from the keyguard
@@ -3542,44 +3562,11 @@
                 toggleKeyboardShortcutsMenu(event.getDeviceId());
             }
         } else if (keyCode == KeyEvent.KEYCODE_ASSIST) {
-            if (down) {
-                if (repeatCount == 0) {
-                    mAssistKeyLongPressed = false;
-                } else if (repeatCount == 1) {
-                    mAssistKeyLongPressed = true;
-                    if (!keyguardOn) {
-                         launchAssistLongPressAction();
-                    }
-                }
-            } else {
-                if (mAssistKeyLongPressed) {
-                    mAssistKeyLongPressed = false;
-                } else {
-                    if (!keyguardOn) {
-                        launchAssistAction(null, event.getDeviceId());
-                    }
-                }
-            }
+            Slog.wtf(TAG, "KEYCODE_ASSIST should be handled in interceptKeyBeforeQueueing");
             return -1;
         } else if (keyCode == KeyEvent.KEYCODE_VOICE_ASSIST) {
-            if (!down) {
-                Intent voiceIntent;
-                if (!keyguardOn) {
-                    voiceIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
-                } else {
-                    IDeviceIdleController dic = IDeviceIdleController.Stub.asInterface(
-                            ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
-                    if (dic != null) {
-                        try {
-                            dic.exitIdle("voice-search");
-                        } catch (RemoteException e) {
-                        }
-                    }
-                    voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
-                    voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, true);
-                }
-                startActivityAsUser(voiceIntent, UserHandle.CURRENT_OR_SELF);
-            }
+            Slog.wtf(TAG, "KEYCODE_VOICE_ASSIST should be handled in interceptKeyBeforeQueueing");
+            return -1;
         } else if (keyCode == KeyEvent.KEYCODE_SYSRQ) {
             if (down && repeatCount == 0) {
                 mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN);
@@ -3891,8 +3878,7 @@
                 mAccessibilityTvScheduled = true;
                 Message msg = Message.obtain(mHandler, MSG_ACCESSIBILITY_TV);
                 msg.setAsynchronous(true);
-                mHandler.sendMessageDelayed(msg,
-                        ViewConfiguration.get(mContext).getAccessibilityShortcutKeyTimeout());
+                mHandler.sendMessageDelayed(msg, getAccessibilityShortcutTimeout());
             }
         } else if (mAccessibilityTvScheduled) {
             mHandler.removeMessages(MSG_ACCESSIBILITY_TV);
@@ -6200,7 +6186,7 @@
                     useHapticFeedback = false; // suppress feedback if already non-interactive
                 }
                 if (down) {
-                    sleepPress(event.getEventTime());
+                    sleepPress();
                 } else {
                     sleepRelease(event.getEventTime());
                 }
@@ -6271,18 +6257,30 @@
                 }
                 break;
             }
-            case KeyEvent.KEYCODE_VOICE_ASSIST: {
-                // Only do this if we would otherwise not pass it to the user. In that case,
-                // interceptKeyBeforeDispatching would apply a similar but different policy in
-                // order to invoke voice assist actions. Note that we need to make a copy of the
-                // key event here because the original key event will be recycled when we return.
-                if ((result & ACTION_PASS_TO_USER) == 0 && !down) {
-                    mBroadcastWakeLock.acquire();
-                    Message msg = mHandler.obtainMessage(MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK,
-                            keyguardActive ? 1 : 0, 0);
+            case KeyEvent.KEYCODE_ASSIST: {
+                final boolean longPressed = event.getRepeatCount() > 0;
+                if (down && longPressed) {
+                    Message msg = mHandler.obtainMessage(MSG_LAUNCH_ASSIST_LONG_PRESS);
                     msg.setAsynchronous(true);
                     msg.sendToTarget();
                 }
+                if (!down && !longPressed) {
+                    Message msg = mHandler.obtainMessage(MSG_LAUNCH_ASSIST, event.getDeviceId(),
+                            0 /* unused */, null /* hint */);
+                    msg.setAsynchronous(true);
+                    msg.sendToTarget();
+                }
+                result &= ~ACTION_PASS_TO_USER;
+                break;
+            }
+            case KeyEvent.KEYCODE_VOICE_ASSIST: {
+                if (!down) {
+                    mBroadcastWakeLock.acquire();
+                    Message msg = mHandler.obtainMessage(MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK);
+                    msg.setAsynchronous(true);
+                    msg.sendToTarget();
+                }
+                result &= ~ACTION_PASS_TO_USER;
                 break;
             }
             case KeyEvent.KEYCODE_WINDOW: {
@@ -6551,18 +6549,22 @@
         }
     }
 
-    void launchVoiceAssistWithWakeLock(boolean keyguardActive) {
-        IDeviceIdleController dic = IDeviceIdleController.Stub.asInterface(
-                ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
-        if (dic != null) {
-            try {
-                dic.exitIdle("voice-search");
-            } catch (RemoteException e) {
+    void launchVoiceAssistWithWakeLock() {
+        final Intent voiceIntent;
+        if (!keyguardOn()) {
+            voiceIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
+        } else {
+            IDeviceIdleController dic = IDeviceIdleController.Stub.asInterface(
+                    ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
+            if (dic != null) {
+                try {
+                    dic.exitIdle("voice-search");
+                } catch (RemoteException e) {
+                }
             }
+            voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
+            voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, true);
         }
-        Intent voiceIntent =
-            new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
-        voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, keyguardActive);
         startActivityAsUser(voiceIntent, UserHandle.CURRENT_OR_SELF);
         mBroadcastWakeLock.release();
     }
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 6a5ecfaa..ca3dd05 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -64,6 +64,7 @@
     private final PendingIntent mAnomalyAlarmIntent;
     private final PendingIntent mPollingAlarmIntent;
     private final BroadcastReceiver mAppUpdateReceiver;
+    private final BroadcastReceiver mUserUpdateReceiver;
 
     public StatsCompanionService(Context context) {
         super();
@@ -75,6 +76,26 @@
         mPollingAlarmIntent = PendingIntent.getBroadcast(mContext, 0,
                 new Intent(mContext, PollingAlarmReceiver.class), 0);
         mAppUpdateReceiver = new AppUpdateReceiver();
+        mUserUpdateReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                synchronized (sStatsdLock) {
+                    sStatsd = fetchStatsdService();
+                    if (sStatsd == null) {
+                        Slog.w(TAG, "Could not access statsd");
+                        return;
+                    }
+                    try {
+                        // Pull the latest state of UID->app name, version mapping.
+                        // Needed since the new user basically has a version of every app.
+                        informAllUidsLocked(context);
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
+                        forgetEverything();
+                    }
+                }
+            }
+        };
         Slog.w(TAG, "Registered receiver for ACTION_PACKAGE_REPLACE AND ADDED.");
     }
 
@@ -121,6 +142,14 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             Slog.i(TAG, "StatsCompanionService noticed an app was updated.");
+            /**
+             * App updates actually consist of REMOVE, ADD, and then REPLACE broadcasts. To avoid
+             * waste, we ignore the REMOVE and ADD broadcasts that contain the replacing flag.
+             */
+            if (!intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED) &&
+                intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                return; // Keep only replacing or normal add and remove.
+            }
             synchronized (sStatsdLock) {
                 if (sStatsd == null) {
                     Slog.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
@@ -370,6 +399,14 @@
                 filter.addDataScheme("package");
                 mContext.registerReceiverAsUser(mAppUpdateReceiver, UserHandle.ALL, filter, null,
                     null);
+
+                // Setup receiver for user initialize (which happens once for a new user) and
+                // if a user is removed.
+                filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE);
+                filter.addAction(Intent.ACTION_USER_REMOVED);
+                mContext.registerReceiverAsUser(mUserUpdateReceiver, UserHandle.ALL,
+                    filter, null, null);
+
                 // Pull the latest state of UID->app name, version mapping when statsd starts.
                 informAllUidsLocked(mContext);
             } catch (RemoteException e) {
@@ -391,6 +428,7 @@
         synchronized (sStatsdLock) {
             sStatsd = null;
             mContext.unregisterReceiver(mAppUpdateReceiver);
+            mContext.unregisterReceiver(mUserUpdateReceiver);
             cancelAnomalyAlarm();
             cancelPollingAlarms();
         }
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index 5365e27..2ef7f25 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -295,13 +295,11 @@
     void updateThumbnailLayer() {
         if (thumbnail != null) {
             final int layer = mAppToken.getHighestAnimLayer();
-            if (layer != mThumbnailLayer) {
-                if (DEBUG_LAYERS) Slog.v(TAG,
-                        "Setting thumbnail layer " + mAppToken + ": layer=" + layer);
-                thumbnail.setLayer(layer + WindowManagerService.WINDOW_LAYER_MULTIPLIER
-                        - WindowManagerService.LAYER_OFFSET_THUMBNAIL);
-                mThumbnailLayer = layer;
-            }
+            if (DEBUG_LAYERS) Slog.v(TAG,
+                    "Setting thumbnail layer " + mAppToken + ": layer=" + layer);
+            thumbnail.setLayer(layer + WindowManagerService.WINDOW_LAYER_MULTIPLIER
+                    - WindowManagerService.LAYER_OFFSET_THUMBNAIL);
+            mThumbnailLayer = layer;
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 1b463c7..5d03493 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1310,8 +1310,7 @@
 
                 // Notify the pinned stack upon all windows drawn. If there was an animation in
                 // progress then this signal will resume that animation.
-                final TaskStack pinnedStack =
-                        mDisplayContent.getStack(WINDOWING_MODE_PINNED);
+                final TaskStack pinnedStack = mDisplayContent.getPinnedStack();
                 if (pinnedStack != null) {
                     pinnedStack.onAllWindowsDrawn();
                 }
diff --git a/services/core/java/com/android/server/wm/BlackFrame.java b/services/core/java/com/android/server/wm/BlackFrame.java
index 5c29a0a..d206554 100644
--- a/services/core/java/com/android/server/wm/BlackFrame.java
+++ b/services/core/java/com/android/server/wm/BlackFrame.java
@@ -18,7 +18,6 @@
 
 import static android.graphics.PixelFormat.OPAQUE;
 import static android.view.SurfaceControl.FX_SURFACE_DIM;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -51,14 +50,8 @@
             int w = r-l;
             int h = b-t;
 
-            if (DEBUG_SURFACE_TRACE) {
-                surface = new WindowSurfaceController.SurfaceTrace(session, "BlackSurface("
-                        + l + ", " + t + ")",
-                        w, h, OPAQUE, FX_SURFACE_DIM | SurfaceControl.HIDDEN);
-            } else {
-                surface = new SurfaceControl(session, "BlackSurface",
-                        w, h, OPAQUE, FX_SURFACE_DIM | SurfaceControl.HIDDEN);
-            }
+            surface = new SurfaceControl(session, "BlackSurface",
+                    w, h, OPAQUE, FX_SURFACE_DIM | SurfaceControl.HIDDEN);
 
             surface.setAlpha(1);
             surface.setLayerStack(layerStack);
diff --git a/services/core/java/com/android/server/wm/CircularDisplayMask.java b/services/core/java/com/android/server/wm/CircularDisplayMask.java
index ae41541..85f468b 100644
--- a/services/core/java/com/android/server/wm/CircularDisplayMask.java
+++ b/services/core/java/com/android/server/wm/CircularDisplayMask.java
@@ -17,7 +17,6 @@
 package com.android.server.wm;
 
 
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
@@ -67,14 +66,9 @@
 
         SurfaceControl ctrl = null;
         try {
-            if (DEBUG_SURFACE_TRACE) {
-                ctrl = new WindowSurfaceController.SurfaceTrace(session, "CircularDisplayMask",
-                        mScreenSize.x, mScreenSize.y, PixelFormat.TRANSLUCENT,
-                        SurfaceControl.HIDDEN);
-            } else {
-                ctrl = new SurfaceControl(session, "CircularDisplayMask", mScreenSize.x,
-                        mScreenSize.y, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
-            }
+            ctrl = new SurfaceControl(session, "CircularDisplayMask", mScreenSize.x,
+                    mScreenSize.y, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
+
             ctrl.setLayerStack(display.getLayerStack());
             ctrl.setLayer(zOrder);
             ctrl.setPosition(0, 0);
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 5bfea98..a4ab3ba 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -28,6 +28,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.app.WindowConfiguration.activityTypeToString;
+import static android.app.WindowConfiguration.windowingModeToString;
 import static com.android.server.wm.proto.ConfigurationContainerProto.FULL_CONFIGURATION;
 import static com.android.server.wm.proto.ConfigurationContainerProto.MERGED_OVERRIDE_CONFIGURATION;
 import static com.android.server.wm.proto.ConfigurationContainerProto.OVERRIDE_CONFIGURATION;
@@ -37,6 +38,7 @@
 import android.content.res.Configuration;
 import android.util.proto.ProtoOutputStream;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 
 /**
@@ -342,6 +344,26 @@
         protoOutputStream.end(token);
     }
 
+    /**
+     * Dumps the names of this container children in the input print writer indenting each
+     * level with the input prefix.
+     */
+    public void dumpChildrenNames(PrintWriter pw, String prefix) {
+        final String childPrefix = prefix + " ";
+        pw.println(getName()
+                + " type=" + activityTypeToString(getActivityType())
+                + " mode=" + windowingModeToString(getWindowingMode()));
+        for (int i = getChildCount() - 1; i >= 0; --i) {
+            final E cc = getChildAt(i);
+            pw.print(childPrefix + "#" + i + " ");
+            cc.dumpChildrenNames(pw, childPrefix);
+        }
+    }
+
+    String getName() {
+        return toString();
+    }
+
     abstract protected int getChildCount();
 
     abstract protected E getChildAt(int index);
diff --git a/services/core/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java
index 708973d..48181d3 100644
--- a/services/core/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -17,7 +17,6 @@
 package com.android.server.wm;
 
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DIM_LAYER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -105,16 +104,10 @@
     private void constructSurface(WindowManagerService service) {
         service.openSurfaceTransaction();
         try {
-            if (DEBUG_SURFACE_TRACE) {
-                mDimSurface = new WindowSurfaceController.SurfaceTrace(service.mFxSession,
-                    "DimSurface",
+            mDimSurface = new SurfaceControl(service.mFxSession, mName,
                     16, 16, PixelFormat.OPAQUE,
                     SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN);
-            } else {
-                mDimSurface = new SurfaceControl(service.mFxSession, mName,
-                    16, 16, PixelFormat.OPAQUE,
-                    SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN);
-            }
+
             if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG,
                     "  DIM " + mDimSurface + ": CREATE");
             mDimSurface.setLayerStack(mDisplayId);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 05afd55..03fdc96 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -116,7 +117,6 @@
 
 import android.annotation.CallSuper;
 import android.annotation.NonNull;
-import android.app.ActivityManager.StackId;
 import android.content.pm.PackageManager;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
@@ -296,10 +296,6 @@
     /** Window tokens that are in the process of exiting, but still on screen for animations. */
     final ArrayList<WindowToken> mExitingTokens = new ArrayList<>();
 
-    /** A special TaskStack with id==HOME_STACK_ID that moves to the bottom whenever any TaskStack
-     * (except a future lockscreen TaskStack) moves to the top. */
-    private TaskStack mHomeStack = null;
-
     /** Detect user tapping outside of current focused task bounds .*/
     TaskTapPointerEventListener mTapDetector;
 
@@ -979,7 +975,7 @@
 
             // In the presence of the PINNED stack or System Alert
             // windows we unfortunately can not seamlessly rotate.
-            if (getStack(WINDOWING_MODE_PINNED) != null) {
+            if (hasPinnedStack()) {
                 mayRotateSeamlessly = false;
             }
             for (int i = 0; i < mService.mSessions.size(); i++) {
@@ -1450,20 +1446,31 @@
     }
 
     TaskStack getHomeStack() {
-        if (mHomeStack == null && mDisplayId == DEFAULT_DISPLAY) {
-            Slog.e(TAG_WM, "getHomeStack: Returning null from this=" + this);
-        }
-        return mHomeStack;
+        return mTaskStackContainers.getHomeStack();
     }
 
-    TaskStack getStackById(int stackId) {
-        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
-            final TaskStack stack = mTaskStackContainers.get(i);
-            if (stack.mStackId == stackId) {
-                return stack;
-            }
-        }
-        return null;
+    /**
+     * @return The primary split-screen stack, but only if it is visible, and {@code null} otherwise.
+     */
+    TaskStack getSplitScreenPrimaryStackStack() {
+        TaskStack stack = mTaskStackContainers.getSplitScreenPrimaryStackStack();
+        return (stack != null && stack.isVisible()) ? stack : null;
+    }
+
+    /**
+     * Like {@link #getSplitScreenPrimaryStackStack}, but also returns the stack if it's currently
+     * not visible.
+     */
+    TaskStack getSplitScreenPrimaryStackStackIgnoringVisibility() {
+        return mTaskStackContainers.getSplitScreenPrimaryStackStack();
+    }
+
+    TaskStack getPinnedStack() {
+        return mTaskStackContainers.getPinnedStack();
+    }
+
+    private boolean hasPinnedStack() {
+        return mTaskStackContainers.getPinnedStack() != null;
     }
 
     /**
@@ -1479,29 +1486,16 @@
      * activity type. Null is no compatible stack on the display.
      */
     TaskStack getStack(int windowingMode, int activityType) {
-        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
-            final TaskStack stack = mTaskStackContainers.get(i);
-            if (stack.isCompatible(windowingMode, activityType)) {
-                return stack;
-            }
-        }
-        return null;
+        return mTaskStackContainers.getStack(windowingMode, activityType);
     }
 
     @VisibleForTesting
-    int getStackCount() {
-        return mTaskStackContainers.size();
+    TaskStack getTopStack() {
+        return mTaskStackContainers.getTopStack();
     }
 
-    @VisibleForTesting
-    int getStackPosition(int windowingMode, int activityType) {
-        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
-            final TaskStack stack = mTaskStackContainers.get(i);
-            if (stack.isCompatible(windowingMode, activityType)) {
-                return i;
-            }
-        }
-        return -1;
+    void onStackWindowingModeChanged(TaskStack stack) {
+        mTaskStackContainers.onStackWindowingModeChanged(stack);
     }
 
     @Override
@@ -1522,8 +1516,8 @@
      * bounds were updated.
      */
     void updateStackBoundsAfterConfigChange(@NonNull List<Integer> changedStackList) {
-        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
-            final TaskStack stack = mTaskStackContainers.get(i);
+        for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
+            final TaskStack stack = mTaskStackContainers.getChildAt(i);
             if (stack.updateBoundsAfterConfigChange()) {
                 changedStackList.add(stack.mStackId);
             }
@@ -1532,7 +1526,7 @@
         // If there was no pinned stack, we still need to notify the controller of the display info
         // update as a result of the config change.  We do this here to consolidate the flow between
         // changes when there is and is not a stack.
-        if (getStack(WINDOWING_MODE_PINNED) == null) {
+        if (!hasPinnedStack()) {
             mPinnedStackControllerLocked.onDisplayInfoChanged();
         }
     }
@@ -1631,8 +1625,8 @@
         mDisplay.getDisplayInfo(mDisplayInfo);
         mDisplay.getMetrics(mDisplayMetrics);
 
-        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
-            mTaskStackContainers.get(i).updateDisplayInfo(null);
+        for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
+            mTaskStackContainers.getChildAt(i).updateDisplayInfo(null);
         }
     }
 
@@ -1753,24 +1747,12 @@
         out.set(mContentRect);
     }
 
-    TaskStack addStackToDisplay(int stackId, boolean onTop, StackWindowController controller) {
+    TaskStack createStack(int stackId, boolean onTop, StackWindowController controller) {
         if (DEBUG_STACK) Slog.d(TAG_WM, "Create new stackId=" + stackId + " on displayId="
                 + mDisplayId);
 
-        TaskStack stack = getStackById(stackId);
-        if (stack != null) {
-            // It's already attached to the display...clear mDeferRemoval, set controller, and move
-            // stack to appropriate z-order on display as needed.
-            stack.mDeferRemoval = false;
-            stack.setController(controller);
-            // We're not moving the display to front when we're adding stacks, only when
-            // requested to change the position of stack explicitly.
-            mTaskStackContainers.positionChildAt(onTop ? POSITION_TOP : POSITION_BOTTOM, stack,
-                    false /* includingParents */);
-        } else {
-            stack = new TaskStack(mService, stackId, controller);
-            mTaskStackContainers.addStackToDisplay(stack, onTop);
-        }
+        final TaskStack stack = new TaskStack(mService, stackId, controller);
+        mTaskStackContainers.addStackToDisplay(stack, onTop);
 
         if (stack.inSplitScreenPrimaryWindowingMode()) {
             mDividerControllerLocked.notifyDockedStackExistsChanged(true);
@@ -1789,7 +1771,7 @@
                     + " to its current displayId=" + mDisplayId);
         }
 
-        prevDc.mTaskStackContainers.removeStackFromDisplay(stack);
+        prevDc.mTaskStackContainers.removeChild(stack);
         mTaskStackContainers.addStackToDisplay(stack, onTop);
     }
 
@@ -1823,8 +1805,8 @@
     }
 
     int taskIdFromPoint(int x, int y) {
-        for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
-            final TaskStack stack = mTaskStackContainers.get(stackNdx);
+        for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+            final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
             final int taskId = stack.taskIdFromPoint(x, y);
             if (taskId != -1) {
                 return taskId;
@@ -1840,8 +1822,8 @@
     Task findTaskForResizePoint(int x, int y) {
         final int delta = dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
         mTmpTaskForResizePointSearchResult.reset();
-        for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
-            final TaskStack stack = mTaskStackContainers.get(stackNdx);
+        for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+            final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
             if (!stack.getWindowConfiguration().canResizeTask()) {
                 return null;
             }
@@ -1863,8 +1845,8 @@
             mTouchExcludeRegion.set(mBaseDisplayRect);
             final int delta = dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
             mTmpRect2.setEmpty();
-            for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
-                final TaskStack stack = mTaskStackContainers.get(stackNdx);
+            for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
                 stack.setTouchExcludeRegion(
                         focusedTask, delta, mTouchExcludeRegion, mContentRect, mTmpRect2);
             }
@@ -1895,7 +1877,7 @@
             mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
         }
         // TODO(multi-display): Support docked stacks on secondary displays.
-        if (mDisplayId == DEFAULT_DISPLAY && getDockedStackLocked() != null) {
+        if (mDisplayId == DEFAULT_DISPLAY && getSplitScreenPrimaryStackStack() != null) {
             mDividerControllerLocked.getTouchRegion(mTmpRect);
             mTmpRegion.set(mTmpRect);
             mTouchExcludeRegion.op(mTmpRegion, Op.UNION);
@@ -1912,8 +1894,8 @@
     }
 
     private void resetAnimationBackgroundAnimator() {
-        for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
-            mTaskStackContainers.get(stackNdx).resetAnimationBackgroundAnimator();
+        for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+            mTaskStackContainers.getChildAt(stackNdx).resetAnimationBackgroundAnimator();
         }
     }
 
@@ -1984,8 +1966,8 @@
             float dividerAnimationTarget) {
         boolean updated = false;
 
-        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
-            final TaskStack stack = mTaskStackContainers.get(i);
+        for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
+            final TaskStack stack = mTaskStackContainers.getChildAt(i);
             if (stack == null || !stack.isAdjustedForIme()) {
                 continue;
             }
@@ -2013,8 +1995,8 @@
 
     boolean clearImeAdjustAnimation() {
         boolean changed = false;
-        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
-            final TaskStack stack = mTaskStackContainers.get(i);
+        for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
+            final TaskStack stack = mTaskStackContainers.getChildAt(i);
             if (stack != null && stack.isAdjustedForIme()) {
                 stack.resetAdjustedForIme(true /* adjustBoundsNow */);
                 changed  = true;
@@ -2024,8 +2006,8 @@
     }
 
     void beginImeAdjustAnimation() {
-        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
-            final TaskStack stack = mTaskStackContainers.get(i);
+        for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
+            final TaskStack stack = mTaskStackContainers.getChildAt(i);
             if (stack.isVisible() && stack.isAdjustedForIme()) {
                 stack.beginImeAdjustAnimation();
             }
@@ -2054,8 +2036,8 @@
         // - If IME is not visible, divider is not moved and is normal width.
 
         if (imeVisible && dockVisible && (imeOnTop || imeOnBottom) && !dockMinimized) {
-            for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
-                final TaskStack stack = mTaskStackContainers.get(i);
+            for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
+                final TaskStack stack = mTaskStackContainers.getChildAt(i);
                 final boolean isDockedOnBottom = stack.getDockSide() == DOCKED_BOTTOM;
                 if (stack.isVisible() && (imeOnBottom || isDockedOnBottom)
                         && stack.inSplitScreenWindowingMode()) {
@@ -2067,8 +2049,8 @@
             mDividerControllerLocked.setAdjustedForIme(
                     imeOnBottom /*ime*/, true /*divider*/, true /*animate*/, imeWin, imeHeight);
         } else {
-            for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
-                final TaskStack stack = mTaskStackContainers.get(i);
+            for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
+                final TaskStack stack = mTaskStackContainers.getChildAt(i);
                 stack.resetAdjustedForIme(!dockVisible);
             }
             mDividerControllerLocked.setAdjustedForIme(
@@ -2099,8 +2081,8 @@
     }
 
     void prepareFreezingTaskBounds() {
-        for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
-            final TaskStack stack = mTaskStackContainers.get(stackNdx);
+        for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+            final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
             stack.prepareFreezingTaskBounds();
         }
     }
@@ -2159,22 +2141,22 @@
         final long token = proto.start(fieldId);
         super.writeToProto(proto, WINDOW_CONTAINER);
         proto.write(ID, mDisplayId);
-        for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
-            final TaskStack stack = mTaskStackContainers.get(stackNdx);
+        for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+            final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
             stack.writeToProto(proto, STACKS);
         }
         mDividerControllerLocked.writeToProto(proto, DOCKED_STACK_DIVIDER_CONTROLLER);
         mPinnedStackControllerLocked.writeToProto(proto, PINNED_STACK_CONTROLLER);
-        for (int i = mAboveAppWindowsContainers.size() - 1; i >= 0; --i) {
-            final WindowToken windowToken = mAboveAppWindowsContainers.get(i);
+        for (int i = mAboveAppWindowsContainers.getChildCount() - 1; i >= 0; --i) {
+            final WindowToken windowToken = mAboveAppWindowsContainers.getChildAt(i);
             windowToken.writeToProto(proto, ABOVE_APP_WINDOWS);
         }
-        for (int i = mBelowAppWindowsContainers.size() - 1; i >= 0; --i) {
-            final WindowToken windowToken = mBelowAppWindowsContainers.get(i);
+        for (int i = mBelowAppWindowsContainers.getChildCount() - 1; i >= 0; --i) {
+            final WindowToken windowToken = mBelowAppWindowsContainers.getChildAt(i);
             windowToken.writeToProto(proto, BELOW_APP_WINDOWS);
         }
-        for (int i = mImeWindowsContainers.size() - 1; i >= 0; --i) {
-            final WindowToken windowToken = mImeWindowsContainers.get(i);
+        for (int i = mImeWindowsContainers.getChildCount() - 1; i >= 0; --i) {
+            final WindowToken windowToken = mImeWindowsContainers.getChildAt(i);
             windowToken.writeToProto(proto, IME_WINDOWS);
         }
         proto.write(DPI, mBaseDisplayDensity);
@@ -2220,8 +2202,8 @@
 
         pw.println();
         pw.println(prefix + "Application tokens in top down Z order:");
-        for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
-            final TaskStack stack = mTaskStackContainers.get(stackNdx);
+        for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+            final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
             stack.dump(prefix + "  ", pw);
         }
 
@@ -2240,6 +2222,22 @@
         pw.println();
         mDimLayerController.dump(prefix, pw);
         pw.println();
+
+        // Dump stack references
+        final TaskStack homeStack = getHomeStack();
+        if (homeStack != null) {
+            pw.println(prefix + "homeStack=" + homeStack.getName());
+        }
+        final TaskStack pinnedStack = getPinnedStack();
+        if (pinnedStack != null) {
+            pw.println(prefix + "pinnedStack=" + pinnedStack.getName());
+        }
+        final TaskStack splitScreenPrimaryStack = getSplitScreenPrimaryStackStack();
+        if (splitScreenPrimaryStack != null) {
+            pw.println(prefix + "splitScreenPrimaryStack=" + splitScreenPrimaryStack.getName());
+        }
+
+        pw.println();
         mDividerControllerLocked.dump(prefix, pw);
         pw.println();
         mPinnedStackControllerLocked.dump(prefix, pw);
@@ -2265,22 +2263,6 @@
         return stack != null && stack.isVisible();
     }
 
-    /**
-     * @return The docked stack, but only if it is visible, and {@code null} otherwise.
-     */
-    TaskStack getDockedStackLocked() {
-        final TaskStack stack = getStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
-        return (stack != null && stack.isVisible()) ? stack : null;
-    }
-
-    /**
-     * Like {@link #getDockedStackLocked}, but also returns the docked stack if it's currently not
-     * visible.
-     */
-    TaskStack getDockedStackIgnoringVisibility() {
-        return getStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
-    }
-
     /** Find the visible, touch-deliverable window under the given point */
     WindowState getTouchableWinAtPointLocked(float xf, float yf) {
         final int x = (int) xf;
@@ -3357,14 +3339,6 @@
      */
     static class DisplayChildWindowContainer<E extends WindowContainer> extends WindowContainer<E> {
 
-        int size() {
-            return mChildren.size();
-        }
-
-        E get(int index) {
-            return mChildren.get(index);
-        }
-
         @Override
         boolean fillsParent() {
             return true;
@@ -3382,25 +3356,108 @@
      */
     private final class TaskStackContainers extends DisplayChildWindowContainer<TaskStack> {
 
+        // Cached reference to some special stacks we tend to get a lot so we don't need to loop
+        // through the list to find them.
+        private TaskStack mHomeStack = null;
+        private TaskStack mPinnedStack = null;
+        private TaskStack mSplitScreenPrimaryStack = null;
+
+        /**
+         * Returns the topmost stack on the display that is compatible with the input windowing mode
+         * and activity type. Null is no compatible stack on the display.
+         */
+        TaskStack getStack(int windowingMode, int activityType) {
+            if (activityType == ACTIVITY_TYPE_HOME) {
+                return mHomeStack;
+            }
+            if (windowingMode == WINDOWING_MODE_PINNED) {
+                return mPinnedStack;
+            } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+                return mSplitScreenPrimaryStack;
+            }
+            for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
+                final TaskStack stack = mTaskStackContainers.getChildAt(i);
+                if (stack.isCompatible(windowingMode, activityType)) {
+                    return stack;
+                }
+            }
+            return null;
+        }
+
+        @VisibleForTesting
+        TaskStack getTopStack() {
+            return mTaskStackContainers.getChildCount() > 0
+                    ? mTaskStackContainers.getChildAt(mTaskStackContainers.getChildCount() - 1) : null;
+        }
+
+        TaskStack getHomeStack() {
+            if (mHomeStack == null && mDisplayId == DEFAULT_DISPLAY) {
+                Slog.e(TAG_WM, "getHomeStack: Returning null from this=" + this);
+            }
+            return mHomeStack;
+        }
+
+        TaskStack getPinnedStack() {
+            return mPinnedStack;
+        }
+
+        TaskStack getSplitScreenPrimaryStackStack() {
+            return mSplitScreenPrimaryStack;
+        }
+
         /**
          * Adds the stack to this container.
-         * @see WindowManagerService#addStackToDisplay(int, int, boolean)
+         * @see DisplayContent#createStack(int, boolean, StackWindowController)
          */
         void addStackToDisplay(TaskStack stack, boolean onTop) {
-            if (stack.isActivityTypeHome()) {
-                if (mHomeStack != null) {
-                    throw new IllegalArgumentException("attachStack: HOME_STACK_ID (0) not first.");
-                }
-                mHomeStack = stack;
-            }
+            addStackReferenceIfNeeded(stack);
             addChild(stack, onTop);
             stack.onDisplayChanged(DisplayContent.this);
         }
 
-        /** Removes the stack from its container and prepare for changing the parent. */
-        void removeStackFromDisplay(TaskStack stack) {
-            removeChild(stack);
-            stack.onRemovedFromDisplay();
+        void onStackWindowingModeChanged(TaskStack stack) {
+            removeStackReferenceIfNeeded(stack);
+            addStackReferenceIfNeeded(stack);
+            if (stack == mPinnedStack && getTopStack() != stack) {
+                // Looks like this stack changed windowing mode to pinned. Move it to the top.
+                positionChildAt(POSITION_TOP, stack, false /* includingParents */);
+            }
+        }
+
+        private void addStackReferenceIfNeeded(TaskStack stack) {
+            if (stack.isActivityTypeHome()) {
+                if (mHomeStack != null) {
+                    throw new IllegalArgumentException("addStackReferenceIfNeeded: home stack="
+                            + mHomeStack + " already exist on display=" + this + " stack=" + stack);
+                }
+                mHomeStack = stack;
+            }
+            final int windowingMode = stack.getWindowingMode();
+            if (windowingMode == WINDOWING_MODE_PINNED) {
+                if (mPinnedStack != null) {
+                    throw new IllegalArgumentException("addStackReferenceIfNeeded: pinned stack="
+                            + mPinnedStack + " already exist on display=" + this
+                            + " stack=" + stack);
+                }
+                mPinnedStack = stack;
+            } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+                if (mSplitScreenPrimaryStack != null) {
+                    throw new IllegalArgumentException("addStackReferenceIfNeeded:"
+                            + " split-screen-primary" + " stack=" + mSplitScreenPrimaryStack
+                            + " already exist on display=" + this + " stack=" + stack);
+                }
+                mSplitScreenPrimaryStack = stack;
+            }
+        }
+
+        private void removeStackReferenceIfNeeded(TaskStack stack) {
+            if (stack == mHomeStack) {
+                mHomeStack = null;
+            } else if (stack == mPinnedStack) {
+                mPinnedStack = null;
+            } else if (stack == mSplitScreenPrimaryStack) {
+                mSplitScreenPrimaryStack = null;
+            }
         }
 
         private void addChild(TaskStack stack, boolean toTop) {
@@ -3410,6 +3467,11 @@
             setLayoutNeeded();
         }
 
+        @Override
+        protected void removeChild(TaskStack stack) {
+            super.removeChild(stack);
+            removeStackReferenceIfNeeded(stack);
+        }
 
         @Override
         boolean isOnTop() {
@@ -3452,8 +3514,7 @@
                     : requestedPosition >= topChildPosition;
             int targetPosition = requestedPosition;
 
-            if (toTop && stack.getWindowingMode() != WINDOWING_MODE_PINNED
-                    && getStack(WINDOWING_MODE_PINNED) != null) {
+            if (toTop && stack.getWindowingMode() != WINDOWING_MODE_PINNED && hasPinnedStack()) {
                 // The pinned stack is always the top most stack (always-on-top) when it is present.
                 TaskStack topStack = mChildren.get(topChildPosition);
                 if (topStack.getWindowingMode() != WINDOWING_MODE_PINNED) {
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 629af66..52526e2 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
@@ -320,7 +319,7 @@
         if (mWindow == null) {
             return;
         }
-        TaskStack stack = mDisplayContent.getDockedStackIgnoringVisibility();
+        TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackStackIgnoringVisibility();
 
         // If the stack is invisible, we policy force hide it in WindowAnimator.shouldForceHide
         final boolean visible = stack != null;
@@ -360,7 +359,7 @@
     }
 
     void positionDockedStackedDivider(Rect frame) {
-        TaskStack stack = mDisplayContent.getDockedStackLocked();
+        TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackStack();
         if (stack == null) {
             // Unfortunately we might end up with still having a divider, even though the underlying
             // stack was already removed. This is because we are on AM thread and the removal of the
@@ -457,7 +456,7 @@
         long animDuration = 0;
         if (animate) {
             final TaskStack stack =
-                    mDisplayContent.getStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+                    mDisplayContent.getSplitScreenPrimaryStackStackIgnoringVisibility();
             final long transitionDuration = isAnimationMaximizing()
                     ? mService.mAppTransition.getLastClipRevealTransitionDuration()
                     : DEFAULT_APP_TRANSITION_DURATION;
@@ -511,7 +510,8 @@
     void registerDockedStackListener(IDockedStackListener listener) {
         mDockedStackListeners.register(listener);
         notifyDockedDividerVisibilityChanged(wasVisible());
-        notifyDockedStackExistsChanged(mDisplayContent.getDockedStackIgnoringVisibility() != null);
+        notifyDockedStackExistsChanged(
+                mDisplayContent.getSplitScreenPrimaryStackStackIgnoringVisibility() != null);
         notifyDockedStackMinimizedChanged(mMinimizedDock, false /* animate */,
                 isHomeStackResizable());
         notifyAdjustedForImeChanged(mAdjustedForIme, 0 /* animDuration */);
@@ -530,7 +530,7 @@
         final TaskStack stack = targetWindowingMode != WINDOWING_MODE_UNDEFINED
                 ? mDisplayContent.getStack(targetWindowingMode)
                 : null;
-        final TaskStack dockedStack = mDisplayContent.getDockedStackLocked();
+        final TaskStack dockedStack = mDisplayContent.getSplitScreenPrimaryStackStack();
         boolean visibleAndValid = visible && stack != null && dockedStack != null;
         if (visibleAndValid) {
             stack.getDimBounds(mTmpRect);
@@ -598,7 +598,7 @@
     }
 
     private void checkMinimizeChanged(boolean animate) {
-        if (mDisplayContent.getDockedStackIgnoringVisibility() == null) {
+        if (mDisplayContent.getSplitScreenPrimaryStackStackIgnoringVisibility() == null) {
             return;
         }
         final TaskStack homeStack = mDisplayContent.getHomeStack();
@@ -760,7 +760,7 @@
     }
 
     private boolean setMinimizedDockedStack(boolean minimized) {
-        final TaskStack stack = mDisplayContent.getDockedStackIgnoringVisibility();
+        final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackStackIgnoringVisibility();
         notifyDockedStackMinimizedChanged(minimized, false /* animate */, isHomeStackResizable());
         return stack != null && stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f);
     }
@@ -811,8 +811,7 @@
     }
 
     private boolean animateForMinimizedDockedStack(long now) {
-        final TaskStack stack =
-                mDisplayContent.getStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+        final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackStackIgnoringVisibility();
         if (!mAnimationStarted) {
             mAnimationStarted = true;
             mAnimationStartTime = now;
diff --git a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
index 3186d3d..19bd8e9 100644
--- a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
+++ b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
@@ -17,7 +17,6 @@
 package com.android.server.wm;
 
 
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
@@ -57,14 +56,8 @@
 
         SurfaceControl ctrl = null;
         try {
-            if (DEBUG_SURFACE_TRACE) {
-                ctrl = new WindowSurfaceController.SurfaceTrace(session, "EmulatorDisplayOverlay",
-                        mScreenSize.x, mScreenSize.y, PixelFormat.TRANSLUCENT,
-                        SurfaceControl.HIDDEN);
-            } else {
-                ctrl = new SurfaceControl(session, "EmulatorDisplayOverlay", mScreenSize.x,
-                        mScreenSize.y, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
-            }
+            ctrl = new SurfaceControl(session, "EmulatorDisplayOverlay", mScreenSize.x,
+                    mScreenSize.y, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
             ctrl.setLayerStack(display.getLayerStack());
             ctrl.setLayer(zOrder);
             ctrl.setPosition(0, 0);
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index ef31598..365366a 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -417,8 +417,7 @@
                             false /* useCurrentMinEdgeSize */);
                 }
                 final Rect animatingBounds = mTmpAnimatingBoundsRect;
-                final TaskStack pinnedStack =
-                        mDisplayContent.getStack(WINDOWING_MODE_PINNED);
+                final TaskStack pinnedStack = mDisplayContent.getPinnedStack();
                 if (pinnedStack != null) {
                     pinnedStack.getAnimationOrCurrentBounds(animatingBounds);
                 } else {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 7832f5de..fd57470 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -411,17 +411,6 @@
         }
     }
 
-    TaskStack getStackById(int stackId) {
-        for (int i = mChildren.size() - 1; i >= 0; i--) {
-            final DisplayContent dc = mChildren.get(i);
-            final TaskStack stack = dc.getStackById(stackId);
-            if (stack != null) {
-                return stack;
-            }
-        }
-        return null;
-    }
-
     TaskStack getStack(int windowingMode, int activityType) {
         for (int i = mChildren.size() - 1; i >= 0; i--) {
             final DisplayContent dc = mChildren.get(i);
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index d5b6d24..8e99be8 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
@@ -24,7 +23,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
 import static com.android.server.wm.WindowStateAnimator.WINDOW_FREEZE_LAYER;
-import static com.android.server.wm.WindowSurfaceController.SurfaceTrace;
 import static com.android.server.wm.proto.ScreenRotationAnimationProto.ANIMATION_RUNNING;
 import static com.android.server.wm.proto.ScreenRotationAnimationProto.STARTED;
 
@@ -276,17 +274,10 @@
                     flags |= SurfaceControl.SECURE;
                 }
 
-                if (DEBUG_SURFACE_TRACE) {
-                    mSurfaceControl = new SurfaceTrace(session, "ScreenshotSurface",
-                            mWidth, mHeight,
-                            PixelFormat.OPAQUE, flags);
-                    Slog.w(TAG, "ScreenRotationAnimation ctor: displayOffset="
-                            + mOriginalDisplayRect.toShortString());
-                } else {
-                    mSurfaceControl = new SurfaceControl(session, "ScreenshotSurface",
-                            mWidth, mHeight,
-                            PixelFormat.OPAQUE, flags);
-                }
+                mSurfaceControl = new SurfaceControl(session, "ScreenshotSurface",
+                        mWidth, mHeight,
+                        PixelFormat.OPAQUE, flags);
+
                 // capture a screenshot into the surface we just created
                 Surface sur = new Surface();
                 sur.copyFrom(mSurfaceControl);
diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java
index c0e5fd4..1fda832 100644
--- a/services/core/java/com/android/server/wm/StackWindowController.java
+++ b/services/core/java/com/android/server/wm/StackWindowController.java
@@ -43,7 +43,7 @@
 public class StackWindowController
         extends WindowContainerController<TaskStack, StackWindowListener> {
 
-    final int mStackId;
+    private final int mStackId;
 
     private final H mHandler;
 
@@ -72,7 +72,7 @@
                         + " to unknown displayId=" + displayId);
             }
 
-            dc.addStackToDisplay(stackId, onTop, this);
+            dc.createStack(stackId, onTop, this);
             getRawBounds(outBounds);
         }
     }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 6c6934f..891d637a 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -419,7 +419,7 @@
         return mFillsParent
                 || !inSplitScreenSecondaryWindowingMode()
                 || displayContent == null
-                || displayContent.getDockedStackIgnoringVisibility() != null;
+                || displayContent.getSplitScreenPrimaryStackStackIgnoringVisibility() != null;
     }
 
     /** Original bounds of the task if applicable, otherwise fullscreen rect. */
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index bff24f6..54ef065 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -294,7 +294,9 @@
         decorPainter.drawDecors(c, null /* statusBarExcludeFrame */);
         node.end(c);
         final Bitmap hwBitmap = ThreadedRenderer.createHardwareBitmap(node, width, height);
-
+        if (hwBitmap == null) {
+            return null;
+        }
         return new TaskSnapshot(hwBitmap.createGraphicBufferHandle(),
                 topChild.getConfiguration().orientation, mainWindow.mStableInsets,
                 ActivityManager.isLowRamDeviceStatic() /* reduced */, 1.0f /* scale */);
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 3780d19..d170b6f 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -294,7 +294,7 @@
         if (mFillsParent
                 || !inSplitScreenSecondaryWindowingMode()
                 || mDisplayContent == null
-                || mDisplayContent.getDockedStackLocked() != null) {
+                || mDisplayContent.getSplitScreenPrimaryStackStack() != null) {
             return true;
         }
         return false;
@@ -673,6 +673,16 @@
         }
     }
 
+    @Override
+    public void onConfigurationChanged(Configuration newParentConfig) {
+        final int prevWindowingMode = getWindowingMode();
+        super.onConfigurationChanged(newParentConfig);
+        if (mDisplayContent != null && prevWindowingMode != getWindowingMode()) {
+            mDisplayContent.onStackWindowingModeChanged(this);
+        }
+    }
+
+    @Override
     void onDisplayChanged(DisplayContent dc) {
         if (mDisplayContent != null) {
             throw new IllegalStateException("onDisplayChanged: Already attached");
@@ -683,7 +693,7 @@
                 "animation background stackId=" + mStackId);
 
         Rect bounds = null;
-        final TaskStack dockedStack = dc.getDockedStackIgnoringVisibility();
+        final TaskStack dockedStack = dc.getSplitScreenPrimaryStackStackIgnoringVisibility();
         if (inSplitScreenPrimaryWindowingMode()
                 || (dockedStack != null && inSplitScreenSecondaryWindowingMode()
                         && !dockedStack.fillsParent())) {
@@ -762,7 +772,8 @@
             return;
         }
 
-        final TaskStack dockedStack = mDisplayContent.getDockedStackIgnoringVisibility();
+        final TaskStack dockedStack =
+                mDisplayContent.getSplitScreenPrimaryStackStackIgnoringVisibility();
         if (dockedStack == null) {
             // Not sure why you are calling this method when there is no docked stack...
             throw new IllegalStateException(
@@ -889,17 +900,12 @@
     }
 
     @Override
-    void removeImmediately() {
-        super.removeImmediately();
+    void onParentSet() {
+        if (getParent() != null || mDisplayContent == null) {
+            return;
+        }
 
-        onRemovedFromDisplay();
-    }
-
-    /**
-     * Removes the stack it from its current parent, so it can be either destroyed completely or
-     * re-parented.
-     */
-    void onRemovedFromDisplay() {
+        // Looks like the stack was removed from the display. Go ahead and clean things up.
         mDisplayContent.mDimLayerController.removeDimLayerUser(this);
         EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
 
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 40923c8..563eb9c 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -73,12 +73,12 @@
 
 
     @Override
-    final protected int getChildCount() {
+    protected int getChildCount() {
         return mChildren.size();
     }
 
     @Override
-    final protected E getChildAt(int index) {
+    protected E getChildAt(int index) {
         return mChildren.get(index);
     }
 
@@ -674,20 +674,6 @@
     }
 
     /**
-     * Dumps the names of this container children in the input print writer indenting each
-     * level with the input prefix.
-     */
-    void dumpChildrenNames(StringBuilder out, String prefix) {
-        final String childPrefix = prefix + " ";
-        out.append(getName() + "\n");
-        for (int i = mChildren.size() - 1; i >= 0; --i) {
-            final WindowContainer wc = mChildren.get(i);
-            out.append(childPrefix + "#" + i + " ");
-            wc.dumpChildrenNames(out, childPrefix);
-        }
-    }
-
-    /**
      * Write to a protocol buffer output stream. Protocol buffer message definition is at
      * {@link com.android.server.wm.proto.WindowContainerProto}.
      *
@@ -704,10 +690,6 @@
         protoOutputStream.end(token);
     }
 
-    String getName() {
-        return toString();
-    }
-
     private ForAllWindowsConsumerWrapper obtainConsumerWrapper(Consumer<WindowState> consumer) {
         ForAllWindowsConsumerWrapper wrapper = mConsumerWrapperPool.acquire();
         if (wrapper == null) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index 6d5673e..9d9805a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -60,7 +60,6 @@
     static final boolean DEBUG_SCREENSHOT = false;
     static final boolean DEBUG_BOOT = false;
     static final boolean DEBUG_LAYOUT_REPEATS = false;
-    static final boolean DEBUG_SURFACE_TRACE = false;
     static final boolean DEBUG_WINDOW_TRACE = false;
     static final boolean DEBUG_TASK_MOVEMENT = false;
     static final boolean DEBUG_TASK_POSITIONING = false;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 4279d2e..f0da474 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3391,7 +3391,8 @@
 
             // Notify whether the docked stack exists for the current user
             final DisplayContent displayContent = getDefaultDisplayContentLocked();
-            final TaskStack stack = displayContent.getDockedStackIgnoringVisibility();
+            final TaskStack stack =
+                    displayContent.getSplitScreenPrimaryStackStackIgnoringVisibility();
             displayContent.mDividerControllerLocked.notifyDockedStackExistsChanged(
                     stack != null && stack.hasTaskForUser(newUserId));
 
@@ -6898,11 +6899,6 @@
                     dumpSessionsLocked(pw, true);
                 }
                 return;
-            } else if ("surfaces".equals(cmd)) {
-                synchronized(mWindowMap) {
-                    WindowSurfaceController.SurfaceTrace.dumpAllSurfaces(pw, null);
-                }
-                return;
             } else if ("displays".equals(cmd) || "d".equals(cmd)) {
                 synchronized(mWindowMap) {
                     mRoot.dumpDisplayContents(pw);
@@ -6925,9 +6921,7 @@
                 return;
             } else if ("containers".equals(cmd)) {
                 synchronized(mWindowMap) {
-                    StringBuilder output = new StringBuilder();
-                    mRoot.dumpChildrenNames(output, " ");
-                    pw.println(output.toString());
+                    mRoot.dumpChildrenNames(pw, " ");
                     pw.println(" ");
                     mRoot.forAllWindows(w -> {pw.println(w);}, true /* traverseTopToBottom */);
                 }
@@ -6967,10 +6961,6 @@
             if (dumpAll) {
                 pw.println("-------------------------------------------------------------------------------");
             }
-            WindowSurfaceController.SurfaceTrace.dumpAllSurfaces(pw, dumpAll ?
-                    "-------------------------------------------------------------------------------"
-                    : null);
-            pw.println();
             if (dumpAll) {
                 pw.println("-------------------------------------------------------------------------------");
             }
@@ -7132,7 +7122,7 @@
     public int getDockedStackSide() {
         synchronized (mWindowMap) {
             final TaskStack dockedStack = getDefaultDisplayContentLocked()
-                    .getDockedStackIgnoringVisibility();
+                    .getSplitScreenPrimaryStackStackIgnoringVisibility();
             return dockedStack == null ? DOCKED_INVALID : dockedStack.getDockSide();
         }
     }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4cb2a9d..e171528 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -80,7 +80,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -1206,7 +1205,7 @@
             // application when it has finished drawing.
             if (getOrientationChanging() || dragResizingChanged
                     || isResizedWhileNotDragResizing()) {
-                if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION || DEBUG_RESIZE) {
+                if (DEBUG_ANIM || DEBUG_ORIENTATION || DEBUG_RESIZE) {
                     Slog.v(TAG_WM, "Orientation or resize start waiting for draw"
                             + ", mDrawState=DRAW_PENDING in " + this
                             + ", surfaceController " + winAnimator.mSurfaceController);
@@ -2361,7 +2360,8 @@
                             // just in case they have the divider at an unstable position. Better
                             // also reset drag resizing state, because the owner can't do it
                             // anymore.
-                            final TaskStack stack = dc.getDockedStackIgnoringVisibility();
+                            final TaskStack stack =
+                                    dc.getSplitScreenPrimaryStackStackIgnoringVisibility();
                             if (stack != null) {
                                 stack.resetDockedStackToMiddle();
                             }
@@ -3679,7 +3679,7 @@
 
         // Force the show in the next prepareSurfaceLocked() call.
         mWinAnimator.mLastAlpha = -1;
-        if (DEBUG_SURFACE_TRACE || DEBUG_ANIM) Slog.v(TAG,
+        if (DEBUG_ANIM) Slog.v(TAG,
                 "performShowLocked: mDrawState=HAS_DRAWN in " + this);
         mWinAnimator.mDrawState = HAS_DRAWN;
         mService.scheduleAnimationLocked();
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index f544321..5266903 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -31,7 +31,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_CROP;
@@ -509,7 +508,7 @@
         boolean layoutNeeded = false;
 
         if (mDrawState == DRAW_PENDING) {
-            if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION)
+            if (DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION)
                 Slog.v(TAG, "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING " + mWin + " in "
                         + mSurfaceController);
             if (DEBUG_STARTING_WINDOW && startingWindow) {
@@ -532,7 +531,7 @@
         if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {
             return false;
         }
-        if (DEBUG_SURFACE_TRACE || DEBUG_ANIM) {
+        if (DEBUG_ANIM) {
             Slog.i(TAG, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW " + mSurfaceController);
         }
         mDrawState = READY_TO_SHOW;
@@ -1033,7 +1032,7 @@
                 //Slog.i(TAG_WM, "Not applying alpha transform");
             }
 
-            if ((DEBUG_SURFACE_TRACE || WindowManagerService.localLOGV)
+            if ((DEBUG_ANIM || WindowManagerService.localLOGV)
                     && (mShownAlpha == 1.0 || mShownAlpha == 0.0)) Slog.v(
                     TAG, "computeShownFrameLocked: Animating " + this + " mAlpha=" + mAlpha
                     + " self=" + (selfTransformation ? mTransformation.getAlpha() : "null")
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 2e1e3f7..d56df55 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -22,7 +22,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -565,262 +564,4 @@
     public String toString() {
         return mSurfaceControl.toString();
     }
-
-    static class SurfaceTrace extends SurfaceControl {
-        private final static String SURFACE_TAG = TAG_WITH_CLASS_NAME ? "SurfaceTrace" : TAG_WM;
-        private final static boolean LOG_SURFACE_TRACE = DEBUG_SURFACE_TRACE;
-        final static ArrayList<SurfaceTrace> sSurfaces = new ArrayList<SurfaceTrace>();
-
-        private float mSurfaceTraceAlpha = 0;
-        private int mLayer;
-        private final PointF mPosition = new PointF();
-        private final Point mSize = new Point();
-        private final Rect mWindowCrop = new Rect();
-        private final Rect mFinalCrop = new Rect();
-        private boolean mShown = false;
-        private int mLayerStack;
-        private boolean mIsOpaque;
-        private float mDsdx, mDtdx, mDsdy, mDtdy;
-        private final String mName;
-
-        public SurfaceTrace(SurfaceSession s, String name, int w, int h, int format, int flags,
-                        int windowType, int ownerUid)
-                    throws OutOfResourcesException {
-            super(s, name, w, h, format, flags, windowType, ownerUid);
-            mName = name != null ? name : "Not named";
-            mSize.set(w, h);
-            if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "ctor: " + this + ". Called by "
-                    + Debug.getCallers(3));
-            synchronized (sSurfaces) {
-                sSurfaces.add(0, this);
-            }
-        }
-
-        public SurfaceTrace(SurfaceSession s,
-                        String name, int w, int h, int format, int flags) {
-            super(s, name, w, h, format, flags);
-            mName = name != null ? name : "Not named";
-            mSize.set(w, h);
-            if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "ctor: " + this + ". Called by "
-                    + Debug.getCallers(3));
-            synchronized (sSurfaces) {
-                sSurfaces.add(0, this);
-            }
-        }
-
-        @Override
-        public void setAlpha(float alpha) {
-            if (mSurfaceTraceAlpha != alpha) {
-                if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setAlpha(" + alpha + "): OLD:" + this +
-                        ". Called by " + Debug.getCallers(3));
-                mSurfaceTraceAlpha = alpha;
-            }
-            super.setAlpha(alpha);
-        }
-
-        @Override
-        public void setLayer(int zorder) {
-            if (zorder != mLayer) {
-                if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setLayer(" + zorder + "): OLD:" + this
-                        + ". Called by " + Debug.getCallers(3));
-                mLayer = zorder;
-            }
-            super.setLayer(zorder);
-
-            synchronized (sSurfaces) {
-                sSurfaces.remove(this);
-                int i;
-                for (i = sSurfaces.size() - 1; i >= 0; i--) {
-                    SurfaceTrace s = sSurfaces.get(i);
-                    if (s.mLayer < zorder) {
-                        break;
-                    }
-                }
-                sSurfaces.add(i + 1, this);
-            }
-        }
-
-        @Override
-        public void setPosition(float x, float y) {
-            if (x != mPosition.x || y != mPosition.y) {
-                if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setPosition(" + x + "," + y + "): OLD:"
-                        + this + ". Called by " + Debug.getCallers(3));
-                mPosition.set(x, y);
-            }
-            super.setPosition(x, y);
-        }
-
-        @Override
-        public void setGeometryAppliesWithResize() {
-            if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setGeometryAppliesWithResize(): OLD: "
-                    + this + ". Called by" + Debug.getCallers(3));
-            super.setGeometryAppliesWithResize();
-        }
-
-        @Override
-        public void setSize(int w, int h) {
-            if (w != mSize.x || h != mSize.y) {
-                if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setSize(" + w + "," + h + "): OLD:"
-                        + this + ". Called by " + Debug.getCallers(3));
-                mSize.set(w, h);
-            }
-            super.setSize(w, h);
-        }
-
-        @Override
-        public void setWindowCrop(Rect crop) {
-            if (crop != null) {
-                if (!crop.equals(mWindowCrop)) {
-                    if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setWindowCrop("
-                            + crop.toShortString() + "): OLD:" + this + ". Called by "
-                            + Debug.getCallers(3));
-                    mWindowCrop.set(crop);
-                }
-            }
-            super.setWindowCrop(crop);
-        }
-
-        @Override
-        public void setFinalCrop(Rect crop) {
-            if (crop != null) {
-                if (!crop.equals(mFinalCrop)) {
-                    if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setFinalCrop("
-                            + crop.toShortString() + "): OLD:" + this + ". Called by "
-                            + Debug.getCallers(3));
-                    mFinalCrop.set(crop);
-                }
-            }
-            super.setFinalCrop(crop);
-        }
-
-        @Override
-        public void setLayerStack(int layerStack) {
-            if (layerStack != mLayerStack) {
-                if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setLayerStack(" + layerStack + "): OLD:"
-                        + this + ". Called by " + Debug.getCallers(3));
-                mLayerStack = layerStack;
-            }
-            super.setLayerStack(layerStack);
-        }
-
-        @Override
-        public void setOpaque(boolean isOpaque) {
-            if (isOpaque != mIsOpaque) {
-                if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setOpaque(" + isOpaque + "): OLD:"
-                        + this + ". Called by " + Debug.getCallers(3));
-                mIsOpaque = isOpaque;
-            }
-            super.setOpaque(isOpaque);
-        }
-
-        @Override
-        public void setSecure(boolean isSecure) {
-            super.setSecure(isSecure);
-        }
-
-        @Override
-        public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
-            if (dsdx != mDsdx || dtdx != mDtdx || dsdy != mDsdy || dtdy != mDtdy) {
-                if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setMatrix(" + dsdx + "," + dtdx + ","
-                        + dsdy + "," + dtdy + "): OLD:" + this + ". Called by "
-                        + Debug.getCallers(3));
-                mDsdx = dsdx;
-                mDtdx = dtdx;
-                mDsdy = dsdy;
-                mDtdy = dtdy;
-            }
-            super.setMatrix(dsdx, dtdx, dsdy, dtdy);
-        }
-
-        @Override
-        public void hide() {
-            if (mShown) {
-                if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "hide: OLD:" + this + ". Called by "
-                        + Debug.getCallers(3));
-                mShown = false;
-            }
-            super.hide();
-        }
-
-        @Override
-        public void show() {
-            if (!mShown) {
-                if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "show: OLD:" + this + ". Called by "
-                        + Debug.getCallers(3));
-                mShown = true;
-            }
-            super.show();
-        }
-
-        @Override
-        public void destroy() {
-            super.destroy();
-            if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "destroy: " + this + ". Called by "
-                    + Debug.getCallers(3));
-            synchronized (sSurfaces) {
-                sSurfaces.remove(this);
-            }
-        }
-
-        @Override
-        public void release() {
-            super.release();
-            if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "release: " + this + ". Called by "
-                    + Debug.getCallers(3));
-            synchronized (sSurfaces) {
-                sSurfaces.remove(this);
-            }
-        }
-
-        @Override
-        public void setTransparentRegionHint(Region region) {
-            if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setTransparentRegionHint(" + region
-                    + "): OLD: " + this + " . Called by " + Debug.getCallers(3));
-            super.setTransparentRegionHint(region);
-        }
-
-        static void dumpAllSurfaces(PrintWriter pw, String header) {
-            synchronized (sSurfaces) {
-                final int N = sSurfaces.size();
-                if (N <= 0) {
-                    return;
-                }
-                if (header != null) {
-                    pw.println(header);
-                }
-                pw.println("WINDOW MANAGER SURFACES (dumpsys window surfaces)");
-                for (int i = 0; i < N; i++) {
-                    SurfaceTrace s = sSurfaces.get(i);
-                    pw.print("  Surface #"); pw.print(i); pw.print(": #");
-                            pw.print(Integer.toHexString(System.identityHashCode(s)));
-                            pw.print(" "); pw.println(s.mName);
-                    pw.print("    mLayerStack="); pw.print(s.mLayerStack);
-                            pw.print(" mLayer="); pw.println(s.mLayer);
-                    pw.print("    mShown="); pw.print(s.mShown); pw.print(" mAlpha=");
-                            pw.print(s.mSurfaceTraceAlpha); pw.print(" mIsOpaque=");
-                            pw.println(s.mIsOpaque);
-                    pw.print("    mPosition="); pw.print(s.mPosition.x); pw.print(",");
-                            pw.print(s.mPosition.y);
-                            pw.print(" mSize="); pw.print(s.mSize.x); pw.print("x");
-                            pw.println(s.mSize.y);
-                    pw.print("    mCrop="); s.mWindowCrop.printShortString(pw); pw.println();
-                    pw.print("    mFinalCrop="); s.mFinalCrop.printShortString(pw); pw.println();
-                    pw.print("    Transform: ("); pw.print(s.mDsdx); pw.print(", ");
-                            pw.print(s.mDtdx); pw.print(", "); pw.print(s.mDsdy);
-                            pw.print(", "); pw.print(s.mDtdy); pw.println(")");
-                }
-            }
-        }
-
-        @Override
-        public String toString() {
-            return "Surface " + Integer.toHexString(System.identityHashCode(this)) + " "
-                    + mName + " (" + mLayerStack + "): shown=" + mShown + " layer=" + mLayer
-                    + " alpha=" + mSurfaceTraceAlpha + " " + mPosition.x + "," + mPosition.y
-                    + " " + mSize.x + "x" + mSize.y
-                    + " crop=" + mWindowCrop.toShortString()
-                    + " opaque=" + mIsOpaque
-                    + " (" + mDsdx + "," + mDtdx + "," + mDsdy + "," + mDtdy + ")";
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index af1fa2fe..fa33fe8 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -449,6 +449,9 @@
             //       animating?
             wtoken.setVisibility(animLp, false, transit, false, voiceInteraction);
             wtoken.updateReportedVisibilityLocked();
+            // setAllAppWinAnimators so the windows get onExitAnimationDone once the animation is
+            // done.
+            wtoken.setAllAppWinAnimators();
             // Force the allDrawn flag, because we want to start
             // this guy's animations regardless of whether it's
             // gotten drawn.
diff --git a/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
index 5f67ac1..ed79352 100644
--- a/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
+++ b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
@@ -30,6 +30,8 @@
 
 namespace android {
 
+using android::hidl::base::V1_0::IBase;
+using hardware::hidl_death_recipient;
 using hardware::hidl_vec;
 using hardware::thermal::V1_0::CoolingDevice;
 using hardware::thermal::V1_0::CpuUsage;
@@ -58,7 +60,22 @@
 
 jfloat gUndefinedTemperature;
 
-static sp<IThermal> gThermalModule;
+static void getThermalHalLocked();
+static std::mutex gThermalHalMutex;
+static sp<IThermal> gThermalHal = nullptr;
+
+// struct ThermalHalDeathRecipient;
+struct ThermalHalDeathRecipient : virtual public hidl_death_recipient {
+      // hidl_death_recipient interface
+      virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override {
+          std::lock_guard<std::mutex> lock(gThermalHalMutex);
+          ALOGE("ThermalHAL just died");
+          gThermalHal = nullptr;
+          getThermalHalLocked();
+      }
+};
+
+sp<ThermalHalDeathRecipient> gThermalHalDeathRecipient = nullptr;
 
 // ----------------------------------------------------------------------------
 
@@ -66,25 +83,50 @@
     return isnan(temperature) ? gUndefinedTemperature : temperature;
 }
 
-static void nativeInit(JNIEnv* env, jobject obj) {
-    // TODO(b/31632518)
-    if (gThermalModule == nullptr) {
-        gThermalModule = IThermal::getService();
+// The caller must be holding gThermalHalMutex.
+static void getThermalHalLocked() {
+    if (gThermalHal != nullptr) {
+        return;
     }
 
-    if (gThermalModule == nullptr) {
+    gThermalHal = IThermal::getService();
+
+    if (gThermalHal == nullptr) {
         ALOGE("Unable to get Thermal service.");
+    } else {
+        if (gThermalHalDeathRecipient == nullptr) {
+            gThermalHalDeathRecipient = new ThermalHalDeathRecipient();
+        }
+        hardware::Return<bool> linked = gThermalHal->linkToDeath(
+            gThermalHalDeathRecipient, 0x451F /* cookie */);
+        if (!linked.isOk()) {
+            ALOGE("Transaction error in linking to ThermalHAL death: %s",
+            linked.description().c_str());
+            gThermalHal = nullptr;
+        } else if (!linked) {
+            ALOGW("Unable to link to ThermalHal death notifications");
+            gThermalHal = nullptr;
+        } else {
+            ALOGD("Link to death notification successful");
+        }
     }
 }
 
+static void nativeInit(JNIEnv* env, jobject obj) {
+    std::lock_guard<std::mutex> lock(gThermalHalMutex);
+    getThermalHalLocked();
+}
+
 static jfloatArray nativeGetFanSpeeds(JNIEnv *env, jclass /* clazz */) {
-    if (gThermalModule == nullptr) {
+    std::lock_guard<std::mutex> lock(gThermalHalMutex);
+    getThermalHalLocked();
+    if (gThermalHal == nullptr) {
         ALOGE("Couldn't get fan speeds because of HAL error.");
         return env->NewFloatArray(0);
     }
 
     hidl_vec<CoolingDevice> list;
-    Return<void> ret = gThermalModule->getCoolingDevices(
+    Return<void> ret = gThermalHal->getCoolingDevices(
             [&list](ThermalStatus status, hidl_vec<CoolingDevice> devices) {
                 if (status.code == ThermalStatusCode::SUCCESS) {
                     list = std::move(devices);
@@ -109,12 +151,14 @@
 
 static jfloatArray nativeGetDeviceTemperatures(JNIEnv *env, jclass /* clazz */, int type,
                                                int source) {
-    if (gThermalModule == nullptr) {
+    std::lock_guard<std::mutex> lock(gThermalHalMutex);
+    getThermalHalLocked();
+    if (gThermalHal == nullptr) {
         ALOGE("Couldn't get device temperatures because of HAL error.");
         return env->NewFloatArray(0);
     }
     hidl_vec<Temperature> list;
-    Return<void> ret = gThermalModule->getTemperatures(
+    Return<void> ret = gThermalHal->getTemperatures(
             [&list](ThermalStatus status, hidl_vec<Temperature> temperatures) {
                 if (status.code == ThermalStatusCode::SUCCESS) {
                     list = std::move(temperatures);
@@ -154,12 +198,14 @@
 }
 
 static jobjectArray nativeGetCpuUsages(JNIEnv *env, jclass /* clazz */) {
-    if (gThermalModule == nullptr || !gCpuUsageInfoClassInfo.initMethod) {
+    std::lock_guard<std::mutex> lock(gThermalHalMutex);
+    getThermalHalLocked();
+    if (gThermalHal == nullptr || !gCpuUsageInfoClassInfo.initMethod) {
         ALOGE("Couldn't get CPU usages because of HAL error.");
         return env->NewObjectArray(0, gCpuUsageInfoClassInfo.clazz, nullptr);
     }
     hidl_vec<CpuUsage> list;
-    Return<void> ret = gThermalModule->getCpuUsages(
+    Return<void> ret = gThermalHal->getCpuUsages(
             [&list](ThermalStatus status, hidl_vec<CpuUsage> cpuUsages) {
                 if (status.code == ThermalStatusCode::SUCCESS) {
                     list = std::move(cpuUsages);
@@ -202,7 +248,6 @@
 };
 
 int register_android_server_HardwarePropertiesManagerService(JNIEnv* env) {
-    gThermalModule = nullptr;
     int res = jniRegisterNativeMethods(env, "com/android/server/HardwarePropertiesManagerService",
                                        gHardwarePropertiesManagerServiceMethods,
                                        NELEM(gHardwarePropertiesManagerServiceMethods));
diff --git a/services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp b/services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp
index 9a17635..3eaf488 100644
--- a/services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp
+++ b/services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp
@@ -103,8 +103,8 @@
     // fd2   A file descriptor bound to the following netlink groups
     //       (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY).
     base::unique_fd
-            fd1(conntrackSocket(NFNLGRP_CONNTRACK_NEW | NFNLGRP_CONNTRACK_DESTROY)),
-            fd2(conntrackSocket(NFNLGRP_CONNTRACK_UPDATE | NFNLGRP_CONNTRACK_DESTROY));
+            fd1(conntrackSocket(NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY)),
+            fd2(conntrackSocket(NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY));
     if (fd1.get() < 0 || fd2.get() < 0) {
         ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno));
         return false;
diff --git a/services/core/jni/com_android_server_location_ContextHubService.cpp b/services/core/jni/com_android_server_location_ContextHubService.cpp
index d90b011..ad372de 100644
--- a/services/core/jni/com_android_server_location_ContextHubService.cpp
+++ b/services/core/jni/com_android_server_location_ContextHubService.cpp
@@ -1162,7 +1162,7 @@
     }
 
     if (result != Result::OK) {
-        ALOGD("Send Message failure - %d", retVal);
+        ALOGD("Send Message failure - %d", result);
         if (msgType == CONTEXT_HUB_LOAD_APP) {
             jint ignored;
             closeLoadTxn(false, &ignored);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ff45070..b78fcdd 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -125,6 +125,7 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Future;
 
+import static android.os.IServiceManager.DUMP_PRIORITY_CRITICAL;
 import static android.view.Display.DEFAULT_DISPLAY;
 
 public final class SystemServer {
@@ -205,7 +206,8 @@
             "com.android.server.autofill.AutofillManagerService";
     private static final String TIME_ZONE_RULES_MANAGER_SERVICE_CLASS =
             "com.android.server.timezone.RulesManagerService$Lifecycle";
-
+    private static final String IOT_SERVICE_CLASS =
+            "com.google.android.things.services.IoTSystemService";
     private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
 
     private static final String UNCRYPT_PACKAGE_FILE = "/cache/recovery/uncrypt_file";
@@ -824,7 +826,8 @@
             wm = WindowManagerService.main(context, inputManager,
                     mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                     !mFirstBoot, mOnlyCore, new PhoneWindowManager());
-            ServiceManager.addService(Context.WINDOW_SERVICE, wm);
+            ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
+                    DUMP_PRIORITY_CRITICAL);
             ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
             traceEnd();
 
@@ -1542,6 +1545,12 @@
             traceEnd();
         }
 
+        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_EMBEDDED)) {
+            traceBeginAndSlog("StartIoTSystemService");
+            mSystemServiceManager.startService(IOT_SERVICE_CLASS);
+            traceEnd();
+        }
+
         // Statsd helper
         traceBeginAndSlog("StartStatsCompanionService");
         mSystemServiceManager.startService(StatsCompanionService.Lifecycle.class);
@@ -1654,6 +1663,25 @@
 
         mSystemServiceManager.setSafeMode(safeMode);
 
+        // Start device specific services
+        traceBeginAndSlog("StartDeviceSpecificServices");
+        final String[] classes = mSystemContext.getResources().getStringArray(
+                R.array.config_deviceSpecificSystemServices);
+        for (final String className : classes) {
+            traceBeginAndSlog("StartDeviceSpecificServices " + className);
+            try {
+                mSystemServiceManager.startService(className);
+            } catch (Throwable e) {
+                reportWtf("starting " + className, e);
+            }
+            traceEnd();
+        }
+        traceEnd();
+
+        traceBeginAndSlog("StartBootPhaseDeviceSpecificServicesReady");
+        mSystemServiceManager.startBootPhase(SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY);
+        traceEnd();
+
         // These are needed to propagate to the runnable below.
         final NetworkManagementService networkManagementF = networkManagement;
         final NetworkStatsService networkStatsF = networkStats;
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 190b3a6..5c2b66f 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -33,7 +33,7 @@
 import android.net.apf.ApfGenerator;
 import android.net.apf.ApfGenerator.IllegalInstructionException;
 import android.net.apf.ApfGenerator.Register;
-import android.net.ip.IpManager;
+import android.net.ip.IpClient;
 import android.net.metrics.ApfProgramEvent;
 import android.net.metrics.ApfStats;
 import android.net.metrics.IpConnectivityLog;
@@ -238,7 +238,7 @@
     private static final int APF_MAX_ETH_TYPE_BLACK_LIST_LEN = 20;
 
     private final ApfCapabilities mApfCapabilities;
-    private final IpManager.Callback mIpManagerCallback;
+    private final IpClient.Callback mIpClientCallback;
     private final NetworkInterface mNetworkInterface;
     private final IpConnectivityLog mMetricsLog;
 
@@ -262,10 +262,10 @@
 
     @VisibleForTesting
     ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface,
-            IpManager.Callback ipManagerCallback, boolean multicastFilter,
+            IpClient.Callback ipClientCallback, boolean multicastFilter,
             boolean ieee802_3Filter, int[] ethTypeBlackList, IpConnectivityLog log) {
         mApfCapabilities = apfCapabilities;
-        mIpManagerCallback = ipManagerCallback;
+        mIpClientCallback = ipClientCallback;
         mNetworkInterface = networkInterface;
         mMulticastFilter = multicastFilter;
         mDrop802_3Frames = ieee802_3Filter;
@@ -275,7 +275,7 @@
 
         mMetricsLog = log;
 
-        // TODO: ApfFilter should not generate programs until IpManager sends provisioning success.
+        // TODO: ApfFilter should not generate programs until IpClient sends provisioning success.
         maybeStartFilter();
     }
 
@@ -1051,7 +1051,7 @@
         if (VDBG) {
             hexDump("Installing filter: ", program, program.length);
         }
-        mIpManagerCallback.installPacketFilter(program);
+        mIpClientCallback.installPacketFilter(program);
         logApfProgramEventLocked(now);
         mLastInstallEvent = new ApfProgramEvent();
         mLastInstallEvent.lifetime = programMinLifetime;
@@ -1161,7 +1161,7 @@
      * filtering using APF programs.
      */
     public static ApfFilter maybeCreate(ApfCapabilities apfCapabilities,
-            NetworkInterface networkInterface, IpManager.Callback ipManagerCallback,
+            NetworkInterface networkInterface, IpClient.Callback ipClientCallback,
             boolean multicastFilter, boolean ieee802_3Filter, int[] ethTypeBlackList) {
         if (apfCapabilities == null || networkInterface == null) return null;
         if (apfCapabilities.apfVersionSupported == 0) return null;
@@ -1178,7 +1178,7 @@
             Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
             return null;
         }
-        return new ApfFilter(apfCapabilities, networkInterface, ipManagerCallback,
+        return new ApfFilter(apfCapabilities, networkInterface, ipClientCallback,
                 multicastFilter, ieee802_3Filter, ethTypeBlackList, new IpConnectivityLog());
     }
 
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
new file mode 100644
index 0000000..2359fab
--- /dev/null
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -0,0 +1,1712 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import com.android.internal.util.MessageUtils;
+import com.android.internal.util.WakeupMessage;
+
+import android.content.Context;
+import android.net.DhcpResults;
+import android.net.INetd;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties.ProvisioningChange;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.ProxyInfo;
+import android.net.RouteInfo;
+import android.net.StaticIpConfiguration;
+import android.net.apf.ApfCapabilities;
+import android.net.apf.ApfFilter;
+import android.net.dhcp.DhcpClient;
+import android.net.metrics.IpConnectivityLog;
+import android.net.metrics.IpManagerEvent;
+import android.net.util.MultinetworkPolicyTracker;
+import android.net.util.NetdService;
+import android.net.util.NetworkConstants;
+import android.net.util.SharedLog;
+import android.os.INetworkManagementService;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.text.TextUtils;
+import android.util.LocalLog;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.R;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.IState;
+import com.android.internal.util.Preconditions;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+import com.android.server.net.NetlinkTracker;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.List;
+import java.util.Set;
+import java.util.StringJoiner;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+
+/**
+ * IpClient
+ *
+ * This class provides the interface to IP-layer provisioning and maintenance
+ * functionality that can be used by transport layers like Wi-Fi, Ethernet,
+ * et cetera.
+ *
+ * [ Lifetime ]
+ * IpClient is designed to be instantiated as soon as the interface name is
+ * known and can be as long-lived as the class containing it (i.e. declaring
+ * it "private final" is okay).
+ *
+ * @hide
+ */
+public class IpClient extends StateMachine {
+    private static final boolean DBG = false;
+
+    // For message logging.
+    private static final Class[] sMessageClasses = { IpClient.class, DhcpClient.class };
+    private static final SparseArray<String> sWhatToString =
+            MessageUtils.findMessageNames(sMessageClasses);
+
+    /**
+     * Callbacks for handling IpClient events.
+     */
+    public static class Callback {
+        // In order to receive onPreDhcpAction(), call #withPreDhcpAction()
+        // when constructing a ProvisioningConfiguration.
+        //
+        // Implementations of onPreDhcpAction() must call
+        // IpClient#completedPreDhcpAction() to indicate that DHCP is clear
+        // to proceed.
+        public void onPreDhcpAction() {}
+        public void onPostDhcpAction() {}
+
+        // This is purely advisory and not an indication of provisioning
+        // success or failure.  This is only here for callers that want to
+        // expose DHCPv4 results to other APIs (e.g., WifiInfo#setInetAddress).
+        // DHCPv4 or static IPv4 configuration failure or success can be
+        // determined by whether or not the passed-in DhcpResults object is
+        // null or not.
+        public void onNewDhcpResults(DhcpResults dhcpResults) {}
+
+        public void onProvisioningSuccess(LinkProperties newLp) {}
+        public void onProvisioningFailure(LinkProperties newLp) {}
+
+        // Invoked on LinkProperties changes.
+        public void onLinkPropertiesChange(LinkProperties newLp) {}
+
+        // Called when the internal IpReachabilityMonitor (if enabled) has
+        // detected the loss of a critical number of required neighbors.
+        public void onReachabilityLost(String logMsg) {}
+
+        // Called when the IpClient state machine terminates.
+        public void onQuit() {}
+
+        // Install an APF program to filter incoming packets.
+        public void installPacketFilter(byte[] filter) {}
+
+        // If multicast filtering cannot be accomplished with APF, this function will be called to
+        // actuate multicast filtering using another means.
+        public void setFallbackMulticastFilter(boolean enabled) {}
+
+        // Enabled/disable Neighbor Discover offload functionality. This is
+        // called, for example, whenever 464xlat is being started or stopped.
+        public void setNeighborDiscoveryOffload(boolean enable) {}
+    }
+
+    // Use a wrapper class to log in order to ensure complete and detailed
+    // logging. This method is lighter weight than annotations/reflection
+    // and has the following benefits:
+    //
+    //     - No invoked method can be forgotten.
+    //       Any new method added to IpClient.Callback must be overridden
+    //       here or it will never be called.
+    //
+    //     - No invoking call site can be forgotten.
+    //       Centralized logging in this way means call sites don't need to
+    //       remember to log, and therefore no call site can be forgotten.
+    //
+    //     - No variation in log format among call sites.
+    //       Encourages logging of any available arguments, and all call sites
+    //       are necessarily logged identically.
+    //
+    // TODO: Find an lighter weight approach.
+    private class LoggingCallbackWrapper extends Callback {
+        private static final String PREFIX = "INVOKE ";
+        private Callback mCallback;
+
+        public LoggingCallbackWrapper(Callback callback) {
+            mCallback = callback;
+        }
+
+        private void log(String msg) {
+            mLog.log(PREFIX + msg);
+        }
+
+        @Override
+        public void onPreDhcpAction() {
+            mCallback.onPreDhcpAction();
+            log("onPreDhcpAction()");
+        }
+        @Override
+        public void onPostDhcpAction() {
+            mCallback.onPostDhcpAction();
+            log("onPostDhcpAction()");
+        }
+        @Override
+        public void onNewDhcpResults(DhcpResults dhcpResults) {
+            mCallback.onNewDhcpResults(dhcpResults);
+            log("onNewDhcpResults({" + dhcpResults + "})");
+        }
+        @Override
+        public void onProvisioningSuccess(LinkProperties newLp) {
+            mCallback.onProvisioningSuccess(newLp);
+            log("onProvisioningSuccess({" + newLp + "})");
+        }
+        @Override
+        public void onProvisioningFailure(LinkProperties newLp) {
+            mCallback.onProvisioningFailure(newLp);
+            log("onProvisioningFailure({" + newLp + "})");
+        }
+        @Override
+        public void onLinkPropertiesChange(LinkProperties newLp) {
+            mCallback.onLinkPropertiesChange(newLp);
+            log("onLinkPropertiesChange({" + newLp + "})");
+        }
+        @Override
+        public void onReachabilityLost(String logMsg) {
+            mCallback.onReachabilityLost(logMsg);
+            log("onReachabilityLost(" + logMsg + ")");
+        }
+        @Override
+        public void onQuit() {
+            mCallback.onQuit();
+            log("onQuit()");
+        }
+        @Override
+        public void installPacketFilter(byte[] filter) {
+            mCallback.installPacketFilter(filter);
+            log("installPacketFilter(byte[" + filter.length + "])");
+        }
+        @Override
+        public void setFallbackMulticastFilter(boolean enabled) {
+            mCallback.setFallbackMulticastFilter(enabled);
+            log("setFallbackMulticastFilter(" + enabled + ")");
+        }
+        @Override
+        public void setNeighborDiscoveryOffload(boolean enable) {
+            mCallback.setNeighborDiscoveryOffload(enable);
+            log("setNeighborDiscoveryOffload(" + enable + ")");
+        }
+    }
+
+    /**
+     * This class encapsulates parameters to be passed to
+     * IpClient#startProvisioning(). A defensive copy is made by IpClient
+     * and the values specified herein are in force until IpClient#stop()
+     * is called.
+     *
+     * Example use:
+     *
+     *     final ProvisioningConfiguration config =
+     *             mIpClient.buildProvisioningConfiguration()
+     *                     .withPreDhcpAction()
+     *                     .withProvisioningTimeoutMs(36 * 1000)
+     *                     .build();
+     *     mIpClient.startProvisioning(config);
+     *     ...
+     *     mIpClient.stop();
+     *
+     * The specified provisioning configuration will only be active until
+     * IpClient#stop() is called. Future calls to IpClient#startProvisioning()
+     * must specify the configuration again.
+     */
+    public static class ProvisioningConfiguration {
+        // TODO: Delete this default timeout once those callers that care are
+        // fixed to pass in their preferred timeout.
+        //
+        // We pick 36 seconds so we can send DHCP requests at
+        //
+        //     t=0, t=2, t=6, t=14, t=30
+        //
+        // allowing for 10% jitter.
+        private static final int DEFAULT_TIMEOUT_MS = 36 * 1000;
+
+        public static class Builder {
+            private ProvisioningConfiguration mConfig = new ProvisioningConfiguration();
+
+            public Builder withoutIPv4() {
+                mConfig.mEnableIPv4 = false;
+                return this;
+            }
+
+            public Builder withoutIPv6() {
+                mConfig.mEnableIPv6 = false;
+                return this;
+            }
+
+            public Builder withoutIpReachabilityMonitor() {
+                mConfig.mUsingIpReachabilityMonitor = false;
+                return this;
+            }
+
+            public Builder withPreDhcpAction() {
+                mConfig.mRequestedPreDhcpActionMs = DEFAULT_TIMEOUT_MS;
+                return this;
+            }
+
+            public Builder withPreDhcpAction(int dhcpActionTimeoutMs) {
+                mConfig.mRequestedPreDhcpActionMs = dhcpActionTimeoutMs;
+                return this;
+            }
+
+            public Builder withInitialConfiguration(InitialConfiguration initialConfig) {
+                mConfig.mInitialConfig = initialConfig;
+                return this;
+            }
+
+            public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
+                mConfig.mStaticIpConfig = staticConfig;
+                return this;
+            }
+
+            public Builder withApfCapabilities(ApfCapabilities apfCapabilities) {
+                mConfig.mApfCapabilities = apfCapabilities;
+                return this;
+            }
+
+            public Builder withProvisioningTimeoutMs(int timeoutMs) {
+                mConfig.mProvisioningTimeoutMs = timeoutMs;
+                return this;
+            }
+
+            public Builder withIPv6AddrGenModeEUI64() {
+                mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_EUI64;
+                return this;
+            }
+
+            public Builder withIPv6AddrGenModeStablePrivacy() {
+                mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
+                return this;
+            }
+
+            public Builder withNetwork(Network network) {
+                mConfig.mNetwork = network;
+                return this;
+            }
+
+            public Builder withDisplayName(String displayName) {
+                mConfig.mDisplayName = displayName;
+                return this;
+            }
+
+            public ProvisioningConfiguration build() {
+                return new ProvisioningConfiguration(mConfig);
+            }
+        }
+
+        /* package */ boolean mEnableIPv4 = true;
+        /* package */ boolean mEnableIPv6 = true;
+        /* package */ boolean mUsingIpReachabilityMonitor = true;
+        /* package */ int mRequestedPreDhcpActionMs;
+        /* package */ InitialConfiguration mInitialConfig;
+        /* package */ StaticIpConfiguration mStaticIpConfig;
+        /* package */ ApfCapabilities mApfCapabilities;
+        /* package */ int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS;
+        /* package */ int mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
+        /* package */ Network mNetwork = null;
+        /* package */ String mDisplayName = null;
+
+        public ProvisioningConfiguration() {} // used by Builder
+
+        public ProvisioningConfiguration(ProvisioningConfiguration other) {
+            mEnableIPv4 = other.mEnableIPv4;
+            mEnableIPv6 = other.mEnableIPv6;
+            mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor;
+            mRequestedPreDhcpActionMs = other.mRequestedPreDhcpActionMs;
+            mInitialConfig = InitialConfiguration.copy(other.mInitialConfig);
+            mStaticIpConfig = other.mStaticIpConfig;
+            mApfCapabilities = other.mApfCapabilities;
+            mProvisioningTimeoutMs = other.mProvisioningTimeoutMs;
+            mIPv6AddrGenMode = other.mIPv6AddrGenMode;
+            mNetwork = other.mNetwork;
+            mDisplayName = other.mDisplayName;
+        }
+
+        @Override
+        public String toString() {
+            return new StringJoiner(", ", getClass().getSimpleName() + "{", "}")
+                    .add("mEnableIPv4: " + mEnableIPv4)
+                    .add("mEnableIPv6: " + mEnableIPv6)
+                    .add("mUsingIpReachabilityMonitor: " + mUsingIpReachabilityMonitor)
+                    .add("mRequestedPreDhcpActionMs: " + mRequestedPreDhcpActionMs)
+                    .add("mInitialConfig: " + mInitialConfig)
+                    .add("mStaticIpConfig: " + mStaticIpConfig)
+                    .add("mApfCapabilities: " + mApfCapabilities)
+                    .add("mProvisioningTimeoutMs: " + mProvisioningTimeoutMs)
+                    .add("mIPv6AddrGenMode: " + mIPv6AddrGenMode)
+                    .add("mNetwork: " + mNetwork)
+                    .add("mDisplayName: " + mDisplayName)
+                    .toString();
+        }
+
+        public boolean isValid() {
+            return (mInitialConfig == null) || mInitialConfig.isValid();
+        }
+    }
+
+    public static class InitialConfiguration {
+        public final Set<LinkAddress> ipAddresses = new HashSet<>();
+        public final Set<IpPrefix> directlyConnectedRoutes = new HashSet<>();
+        public final Set<InetAddress> dnsServers = new HashSet<>();
+        public Inet4Address gateway; // WiFi legacy behavior with static ipv4 config
+
+        public static InitialConfiguration copy(InitialConfiguration config) {
+            if (config == null) {
+                return null;
+            }
+            InitialConfiguration configCopy = new InitialConfiguration();
+            configCopy.ipAddresses.addAll(config.ipAddresses);
+            configCopy.directlyConnectedRoutes.addAll(config.directlyConnectedRoutes);
+            configCopy.dnsServers.addAll(config.dnsServers);
+            return configCopy;
+        }
+
+        @Override
+        public String toString() {
+            return String.format(
+                    "InitialConfiguration(IPs: {%s}, prefixes: {%s}, DNS: {%s}, v4 gateway: %s)",
+                    join(", ", ipAddresses), join(", ", directlyConnectedRoutes),
+                    join(", ", dnsServers), gateway);
+        }
+
+        public boolean isValid() {
+            if (ipAddresses.isEmpty()) {
+                return false;
+            }
+
+            // For every IP address, there must be at least one prefix containing that address.
+            for (LinkAddress addr : ipAddresses) {
+                if (!any(directlyConnectedRoutes, (p) -> p.contains(addr.getAddress()))) {
+                    return false;
+                }
+            }
+            // For every dns server, there must be at least one prefix containing that address.
+            for (InetAddress addr : dnsServers) {
+                if (!any(directlyConnectedRoutes, (p) -> p.contains(addr))) {
+                    return false;
+                }
+            }
+            // All IPv6 LinkAddresses have an RFC7421-suitable prefix length
+            // (read: compliant with RFC4291#section2.5.4).
+            if (any(ipAddresses, not(InitialConfiguration::isPrefixLengthCompliant))) {
+                return false;
+            }
+            // If directlyConnectedRoutes contains an IPv6 default route
+            // then ipAddresses MUST contain at least one non-ULA GUA.
+            if (any(directlyConnectedRoutes, InitialConfiguration::isIPv6DefaultRoute)
+                    && all(ipAddresses, not(InitialConfiguration::isIPv6GUA))) {
+                return false;
+            }
+            // The prefix length of routes in directlyConnectedRoutes be within reasonable
+            // bounds for IPv6: /48-/64 just as we’d accept in RIOs.
+            if (any(directlyConnectedRoutes, not(InitialConfiguration::isPrefixLengthCompliant))) {
+                return false;
+            }
+            // There no more than one IPv4 address
+            if (ipAddresses.stream().filter(Inet4Address.class::isInstance).count() > 1) {
+                return false;
+            }
+
+            return true;
+        }
+
+        /**
+         * @return true if the given list of addressess and routes satisfies provisioning for this
+         * InitialConfiguration. LinkAddresses and RouteInfo objects are not compared with equality
+         * because addresses and routes seen by Netlink will contain additional fields like flags,
+         * interfaces, and so on. If this InitialConfiguration has no IP address specified, the
+         * provisioning check always fails.
+         *
+         * If the given list of routes is null, only addresses are taken into considerations.
+         */
+        public boolean isProvisionedBy(List<LinkAddress> addresses, List<RouteInfo> routes) {
+            if (ipAddresses.isEmpty()) {
+                return false;
+            }
+
+            for (LinkAddress addr : ipAddresses) {
+                if (!any(addresses, (addrSeen) -> addr.isSameAddressAs(addrSeen))) {
+                    return false;
+                }
+            }
+
+            if (routes != null) {
+                for (IpPrefix prefix : directlyConnectedRoutes) {
+                    if (!any(routes, (routeSeen) -> isDirectlyConnectedRoute(routeSeen, prefix))) {
+                        return false;
+                    }
+                }
+            }
+
+            return true;
+        }
+
+        private static boolean isDirectlyConnectedRoute(RouteInfo route, IpPrefix prefix) {
+            return !route.hasGateway() && prefix.equals(route.getDestination());
+        }
+
+        private static boolean isPrefixLengthCompliant(LinkAddress addr) {
+            return addr.isIPv4() || isCompliantIPv6PrefixLength(addr.getPrefixLength());
+        }
+
+        private static boolean isPrefixLengthCompliant(IpPrefix prefix) {
+            return prefix.isIPv4() || isCompliantIPv6PrefixLength(prefix.getPrefixLength());
+        }
+
+        private static boolean isCompliantIPv6PrefixLength(int prefixLength) {
+            return (NetworkConstants.RFC6177_MIN_PREFIX_LENGTH <= prefixLength)
+                    && (prefixLength <= NetworkConstants.RFC7421_PREFIX_LENGTH);
+        }
+
+        private static boolean isIPv6DefaultRoute(IpPrefix prefix) {
+            return prefix.getAddress().equals(Inet6Address.ANY);
+        }
+
+        private static boolean isIPv6GUA(LinkAddress addr) {
+            return addr.isIPv6() && addr.isGlobalPreferred();
+        }
+    }
+
+    public static final String DUMP_ARG = "ipclient";
+    public static final String DUMP_ARG_CONFIRM = "confirm";
+
+    private static final int CMD_TERMINATE_AFTER_STOP             = 1;
+    private static final int CMD_STOP                             = 2;
+    private static final int CMD_START                            = 3;
+    private static final int CMD_CONFIRM                          = 4;
+    private static final int EVENT_PRE_DHCP_ACTION_COMPLETE       = 5;
+    // Sent by NetlinkTracker to communicate netlink events.
+    private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 6;
+    private static final int CMD_UPDATE_TCP_BUFFER_SIZES          = 7;
+    private static final int CMD_UPDATE_HTTP_PROXY                = 8;
+    private static final int CMD_SET_MULTICAST_FILTER             = 9;
+    private static final int EVENT_PROVISIONING_TIMEOUT           = 10;
+    private static final int EVENT_DHCPACTION_TIMEOUT             = 11;
+
+    private static final int MAX_LOG_RECORDS = 500;
+    private static final int MAX_PACKET_RECORDS = 100;
+
+    private static final boolean NO_CALLBACKS = false;
+    private static final boolean SEND_CALLBACKS = true;
+
+    // This must match the interface prefix in clatd.c.
+    // TODO: Revert this hack once IpClient and Nat464Xlat work in concert.
+    private static final String CLAT_PREFIX = "v4-";
+
+    private final State mStoppedState = new StoppedState();
+    private final State mStoppingState = new StoppingState();
+    private final State mStartedState = new StartedState();
+    private final State mRunningState = new RunningState();
+
+    private final String mTag;
+    private final Context mContext;
+    private final String mInterfaceName;
+    private final String mClatInterfaceName;
+    @VisibleForTesting
+    protected final Callback mCallback;
+    private final INetworkManagementService mNwService;
+    private final NetlinkTracker mNetlinkTracker;
+    private final WakeupMessage mProvisioningTimeoutAlarm;
+    private final WakeupMessage mDhcpActionTimeoutAlarm;
+    private final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
+    private final SharedLog mLog;
+    private final LocalLog mConnectivityPacketLog;
+    private final MessageHandlingLogger mMsgStateLogger;
+    private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
+    private final InterfaceController mInterfaceCtrl;
+
+    private NetworkInterface mNetworkInterface;
+
+    /**
+     * Non-final member variables accessed only from within our StateMachine.
+     */
+    private LinkProperties mLinkProperties;
+    private ProvisioningConfiguration mConfiguration;
+    private IpReachabilityMonitor mIpReachabilityMonitor;
+    private DhcpClient mDhcpClient;
+    private DhcpResults mDhcpResults;
+    private String mTcpBufferSizes;
+    private ProxyInfo mHttpProxy;
+    private ApfFilter mApfFilter;
+    private boolean mMulticastFiltering;
+    private long mStartTimeMillis;
+
+    public IpClient(Context context, String ifName, Callback callback) {
+        this(context, ifName, callback, INetworkManagementService.Stub.asInterface(
+                ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)),
+                NetdService.getInstance());
+    }
+
+    /**
+     * An expanded constructor, useful for dependency injection.
+     * TODO: migrate all test users to mock IpClient directly and remove this ctor.
+     */
+    public IpClient(Context context, String ifName, Callback callback,
+            INetworkManagementService nwService) {
+        this(context, ifName, callback, nwService, NetdService.getInstance());
+    }
+
+    @VisibleForTesting
+    IpClient(Context context, String ifName, Callback callback,
+            INetworkManagementService nwService, INetd netd) {
+        super(IpClient.class.getSimpleName() + "." + ifName);
+        mTag = getName();
+
+        mContext = context;
+        mInterfaceName = ifName;
+        mClatInterfaceName = CLAT_PREFIX + ifName;
+        mCallback = new LoggingCallbackWrapper(callback);
+        mNwService = nwService;
+
+        mLog = new SharedLog(MAX_LOG_RECORDS, mTag);
+        mConnectivityPacketLog = new LocalLog(MAX_PACKET_RECORDS);
+        mMsgStateLogger = new MessageHandlingLogger();
+
+        mInterfaceCtrl = new InterfaceController(mInterfaceName, mNwService, netd, mLog);
+
+        mNetlinkTracker = new NetlinkTracker(
+                mInterfaceName,
+                new NetlinkTracker.Callback() {
+                    @Override
+                    public void update() {
+                        sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED);
+                    }
+                }) {
+            @Override
+            public void interfaceAdded(String iface) {
+                super.interfaceAdded(iface);
+                if (mClatInterfaceName.equals(iface)) {
+                    mCallback.setNeighborDiscoveryOffload(false);
+                } else if (!mInterfaceName.equals(iface)) {
+                    return;
+                }
+
+                final String msg = "interfaceAdded(" + iface +")";
+                logMsg(msg);
+            }
+
+            @Override
+            public void interfaceRemoved(String iface) {
+                super.interfaceRemoved(iface);
+                // TODO: Also observe mInterfaceName going down and take some
+                // kind of appropriate action.
+                if (mClatInterfaceName.equals(iface)) {
+                    // TODO: consider sending a message to the IpClient main
+                    // StateMachine thread, in case "NDO enabled" state becomes
+                    // tied to more things that 464xlat operation.
+                    mCallback.setNeighborDiscoveryOffload(true);
+                } else if (!mInterfaceName.equals(iface)) {
+                    return;
+                }
+
+                final String msg = "interfaceRemoved(" + iface +")";
+                logMsg(msg);
+            }
+
+            private void logMsg(String msg) {
+                Log.d(mTag, msg);
+                getHandler().post(() -> { mLog.log("OBSERVED " + msg); });
+            }
+        };
+
+        mLinkProperties = new LinkProperties();
+        mLinkProperties.setInterfaceName(mInterfaceName);
+
+        mMultinetworkPolicyTracker = new MultinetworkPolicyTracker(mContext, getHandler(),
+                () -> { mLog.log("OBSERVED AvoidBadWifi changed"); });
+
+        mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
+                mTag + ".EVENT_PROVISIONING_TIMEOUT", EVENT_PROVISIONING_TIMEOUT);
+        mDhcpActionTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
+                mTag + ".EVENT_DHCPACTION_TIMEOUT", EVENT_DHCPACTION_TIMEOUT);
+
+        // Anything the StateMachine may access must have been instantiated
+        // before this point.
+        configureAndStartStateMachine();
+
+        // Anything that may send messages to the StateMachine must only be
+        // configured to do so after the StateMachine has started (above).
+        startStateMachineUpdaters();
+    }
+
+    private void configureAndStartStateMachine() {
+        addState(mStoppedState);
+        addState(mStartedState);
+            addState(mRunningState, mStartedState);
+        addState(mStoppingState);
+
+        setInitialState(mStoppedState);
+
+        super.start();
+    }
+
+    private void startStateMachineUpdaters() {
+        try {
+            mNwService.registerObserver(mNetlinkTracker);
+        } catch (RemoteException e) {
+            logError("Couldn't register NetlinkTracker: %s", e);
+        }
+
+        mMultinetworkPolicyTracker.start();
+    }
+
+    private void stopStateMachineUpdaters() {
+        try {
+            mNwService.unregisterObserver(mNetlinkTracker);
+        } catch (RemoteException e) {
+            logError("Couldn't unregister NetlinkTracker: %s", e);
+        }
+
+        mMultinetworkPolicyTracker.shutdown();
+    }
+
+    @Override
+    protected void onQuitting() {
+        mCallback.onQuit();
+    }
+
+    // Shut down this IpClient instance altogether.
+    public void shutdown() {
+        stop();
+        sendMessage(CMD_TERMINATE_AFTER_STOP);
+    }
+
+    public static ProvisioningConfiguration.Builder buildProvisioningConfiguration() {
+        return new ProvisioningConfiguration.Builder();
+    }
+
+    public void startProvisioning(ProvisioningConfiguration req) {
+        if (!req.isValid()) {
+            doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
+            return;
+        }
+
+        getNetworkInterface();
+
+        mCallback.setNeighborDiscoveryOffload(true);
+        sendMessage(CMD_START, new ProvisioningConfiguration(req));
+    }
+
+    // TODO: Delete this.
+    public void startProvisioning(StaticIpConfiguration staticIpConfig) {
+        startProvisioning(buildProvisioningConfiguration()
+                .withStaticConfiguration(staticIpConfig)
+                .build());
+    }
+
+    public void startProvisioning() {
+        startProvisioning(new ProvisioningConfiguration());
+    }
+
+    public void stop() {
+        sendMessage(CMD_STOP);
+    }
+
+    public void confirmConfiguration() {
+        sendMessage(CMD_CONFIRM);
+    }
+
+    public void completedPreDhcpAction() {
+        sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
+    }
+
+    /**
+     * Set the TCP buffer sizes to use.
+     *
+     * This may be called, repeatedly, at any time before or after a call to
+     * #startProvisioning(). The setting is cleared upon calling #stop().
+     */
+    public void setTcpBufferSizes(String tcpBufferSizes) {
+        sendMessage(CMD_UPDATE_TCP_BUFFER_SIZES, tcpBufferSizes);
+    }
+
+    /**
+     * Set the HTTP Proxy configuration to use.
+     *
+     * This may be called, repeatedly, at any time before or after a call to
+     * #startProvisioning(). The setting is cleared upon calling #stop().
+     */
+    public void setHttpProxy(ProxyInfo proxyInfo) {
+        sendMessage(CMD_UPDATE_HTTP_PROXY, proxyInfo);
+    }
+
+    /**
+     * Enable or disable the multicast filter.  Attempts to use APF to accomplish the filtering,
+     * if not, Callback.setFallbackMulticastFilter() is called.
+     */
+    public void setMulticastFilter(boolean enabled) {
+        sendMessage(CMD_SET_MULTICAST_FILTER, enabled);
+    }
+
+    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        if (args != null && args.length > 0 && DUMP_ARG_CONFIRM.equals(args[0])) {
+            // Execute confirmConfiguration() and take no further action.
+            confirmConfiguration();
+            return;
+        }
+
+        // Thread-unsafe access to mApfFilter but just used for debugging.
+        final ApfFilter apfFilter = mApfFilter;
+        final ProvisioningConfiguration provisioningConfig = mConfiguration;
+        final ApfCapabilities apfCapabilities = (provisioningConfig != null)
+                ? provisioningConfig.mApfCapabilities : null;
+
+        IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
+        pw.println(mTag + " APF dump:");
+        pw.increaseIndent();
+        if (apfFilter != null) {
+            apfFilter.dump(pw);
+        } else {
+            pw.print("No active ApfFilter; ");
+            if (provisioningConfig == null) {
+                pw.println("IpClient not yet started.");
+            } else if (apfCapabilities == null || apfCapabilities.apfVersionSupported == 0) {
+                pw.println("Hardware does not support APF.");
+            } else {
+                pw.println("ApfFilter not yet started, APF capabilities: " + apfCapabilities);
+            }
+        }
+        pw.decreaseIndent();
+
+        pw.println();
+        pw.println(mTag + " current ProvisioningConfiguration:");
+        pw.increaseIndent();
+        pw.println(Objects.toString(provisioningConfig, "N/A"));
+        pw.decreaseIndent();
+
+        pw.println();
+        pw.println(mTag + " StateMachine dump:");
+        pw.increaseIndent();
+        mLog.dump(fd, pw, args);
+        pw.decreaseIndent();
+
+        pw.println();
+        pw.println(mTag + " connectivity packet log:");
+        pw.println();
+        pw.println("Debug with python and scapy via:");
+        pw.println("shell$ python");
+        pw.println(">>> from scapy import all as scapy");
+        pw.println(">>> scapy.Ether(\"<paste_hex_string>\".decode(\"hex\")).show2()");
+        pw.println();
+
+        pw.increaseIndent();
+        mConnectivityPacketLog.readOnlyLocalLog().dump(fd, pw, args);
+        pw.decreaseIndent();
+    }
+
+
+    /**
+     * Internals.
+     */
+
+    @Override
+    protected String getWhatToString(int what) {
+        return sWhatToString.get(what, "UNKNOWN: " + Integer.toString(what));
+    }
+
+    @Override
+    protected String getLogRecString(Message msg) {
+        final String logLine = String.format(
+                "%s/%d %d %d %s [%s]",
+                mInterfaceName, mNetworkInterface == null ? -1 : mNetworkInterface.getIndex(),
+                msg.arg1, msg.arg2, Objects.toString(msg.obj), mMsgStateLogger);
+
+        final String richerLogLine = getWhatToString(msg.what) + " " + logLine;
+        mLog.log(richerLogLine);
+        if (DBG) {
+            Log.d(mTag, richerLogLine);
+        }
+
+        mMsgStateLogger.reset();
+        return logLine;
+    }
+
+    @Override
+    protected boolean recordLogRec(Message msg) {
+        // Don't log EVENT_NETLINK_LINKPROPERTIES_CHANGED. They can be noisy,
+        // and we already log any LinkProperties change that results in an
+        // invocation of IpClient.Callback#onLinkPropertiesChange().
+        final boolean shouldLog = (msg.what != EVENT_NETLINK_LINKPROPERTIES_CHANGED);
+        if (!shouldLog) {
+            mMsgStateLogger.reset();
+        }
+        return shouldLog;
+    }
+
+    private void logError(String fmt, Object... args) {
+        final String msg = "ERROR " + String.format(fmt, args);
+        Log.e(mTag, msg);
+        mLog.log(msg);
+    }
+
+    private void getNetworkInterface() {
+        try {
+            mNetworkInterface = NetworkInterface.getByName(mInterfaceName);
+        } catch (SocketException | NullPointerException e) {
+            // TODO: throw new IllegalStateException.
+            logError("Failed to get interface object: %s", e);
+        }
+    }
+
+    // This needs to be called with care to ensure that our LinkProperties
+    // are in sync with the actual LinkProperties of the interface. For example,
+    // we should only call this if we know for sure that there are no IP addresses
+    // assigned to the interface, etc.
+    private void resetLinkProperties() {
+        mNetlinkTracker.clearLinkProperties();
+        mConfiguration = null;
+        mDhcpResults = null;
+        mTcpBufferSizes = "";
+        mHttpProxy = null;
+
+        mLinkProperties = new LinkProperties();
+        mLinkProperties.setInterfaceName(mInterfaceName);
+    }
+
+    private void recordMetric(final int type) {
+        if (mStartTimeMillis <= 0) { Log.wtf(mTag, "Start time undefined!"); }
+        final long duration = SystemClock.elapsedRealtime() - mStartTimeMillis;
+        mMetricsLog.log(mInterfaceName, new IpManagerEvent(type, duration));
+    }
+
+    // For now: use WifiStateMachine's historical notion of provisioned.
+    @VisibleForTesting
+    static boolean isProvisioned(LinkProperties lp, InitialConfiguration config) {
+        // For historical reasons, we should connect even if all we have is
+        // an IPv4 address and nothing else.
+        if (lp.hasIPv4Address() || lp.isProvisioned()) {
+            return true;
+        }
+        if (config == null) {
+            return false;
+        }
+
+        // When an InitialConfiguration is specified, ignore any difference with previous
+        // properties and instead check if properties observed match the desired properties.
+        return config.isProvisionedBy(lp.getLinkAddresses(), lp.getRoutes());
+    }
+
+    // TODO: Investigate folding all this into the existing static function
+    // LinkProperties.compareProvisioning() or some other single function that
+    // takes two LinkProperties objects and returns a ProvisioningChange
+    // object that is a correct and complete assessment of what changed, taking
+    // account of the asymmetries described in the comments in this function.
+    // Then switch to using it everywhere (IpReachabilityMonitor, etc.).
+    private ProvisioningChange compareProvisioning(LinkProperties oldLp, LinkProperties newLp) {
+        ProvisioningChange delta;
+        InitialConfiguration config = mConfiguration != null ? mConfiguration.mInitialConfig : null;
+        final boolean wasProvisioned = isProvisioned(oldLp, config);
+        final boolean isProvisioned = isProvisioned(newLp, config);
+
+        if (!wasProvisioned && isProvisioned) {
+            delta = ProvisioningChange.GAINED_PROVISIONING;
+        } else if (wasProvisioned && isProvisioned) {
+            delta = ProvisioningChange.STILL_PROVISIONED;
+        } else if (!wasProvisioned && !isProvisioned) {
+            delta = ProvisioningChange.STILL_NOT_PROVISIONED;
+        } else {
+            // (wasProvisioned && !isProvisioned)
+            //
+            // Note that this is true even if we lose a configuration element
+            // (e.g., a default gateway) that would not be required to advance
+            // into provisioned state. This is intended: if we have a default
+            // router and we lose it, that's a sure sign of a problem, but if
+            // we connect to a network with no IPv4 DNS servers, we consider
+            // that to be a network without DNS servers and connect anyway.
+            //
+            // See the comment below.
+            delta = ProvisioningChange.LOST_PROVISIONING;
+        }
+
+        final boolean lostIPv6 = oldLp.isIPv6Provisioned() && !newLp.isIPv6Provisioned();
+        final boolean lostIPv4Address = oldLp.hasIPv4Address() && !newLp.hasIPv4Address();
+        final boolean lostIPv6Router = oldLp.hasIPv6DefaultRoute() && !newLp.hasIPv6DefaultRoute();
+
+        // If bad wifi avoidance is disabled, then ignore IPv6 loss of
+        // provisioning. Otherwise, when a hotspot that loses Internet
+        // access sends out a 0-lifetime RA to its clients, the clients
+        // will disconnect and then reconnect, avoiding the bad hotspot,
+        // instead of getting stuck on the bad hotspot. http://b/31827713 .
+        //
+        // This is incorrect because if the hotspot then regains Internet
+        // access with a different prefix, TCP connections on the
+        // deprecated addresses will remain stuck.
+        //
+        // Note that we can still be disconnected by IpReachabilityMonitor
+        // if the IPv6 default gateway (but not the IPv6 DNS servers; see
+        // accompanying code in IpReachabilityMonitor) is unreachable.
+        final boolean ignoreIPv6ProvisioningLoss = !mMultinetworkPolicyTracker.getAvoidBadWifi();
+
+        // Additionally:
+        //
+        // Partial configurations (e.g., only an IPv4 address with no DNS
+        // servers and no default route) are accepted as long as DHCPv4
+        // succeeds. On such a network, isProvisioned() will always return
+        // false, because the configuration is not complete, but we want to
+        // connect anyway. It might be a disconnected network such as a
+        // Chromecast or a wireless printer, for example.
+        //
+        // Because on such a network isProvisioned() will always return false,
+        // delta will never be LOST_PROVISIONING. So check for loss of
+        // provisioning here too.
+        if (lostIPv4Address || (lostIPv6 && !ignoreIPv6ProvisioningLoss)) {
+            delta = ProvisioningChange.LOST_PROVISIONING;
+        }
+
+        // Additionally:
+        //
+        // If the previous link properties had a global IPv6 address and an
+        // IPv6 default route then also consider the loss of that default route
+        // to be a loss of provisioning. See b/27962810.
+        if (oldLp.hasGlobalIPv6Address() && (lostIPv6Router && !ignoreIPv6ProvisioningLoss)) {
+            delta = ProvisioningChange.LOST_PROVISIONING;
+        }
+
+        return delta;
+    }
+
+    private void dispatchCallback(ProvisioningChange delta, LinkProperties newLp) {
+        switch (delta) {
+            case GAINED_PROVISIONING:
+                if (DBG) { Log.d(mTag, "onProvisioningSuccess()"); }
+                recordMetric(IpManagerEvent.PROVISIONING_OK);
+                mCallback.onProvisioningSuccess(newLp);
+                break;
+
+            case LOST_PROVISIONING:
+                if (DBG) { Log.d(mTag, "onProvisioningFailure()"); }
+                recordMetric(IpManagerEvent.PROVISIONING_FAIL);
+                mCallback.onProvisioningFailure(newLp);
+                break;
+
+            default:
+                if (DBG) { Log.d(mTag, "onLinkPropertiesChange()"); }
+                mCallback.onLinkPropertiesChange(newLp);
+                break;
+        }
+    }
+
+    // Updates all IpClient-related state concerned with LinkProperties.
+    // Returns a ProvisioningChange for possibly notifying other interested
+    // parties that are not fronted by IpClient.
+    private ProvisioningChange setLinkProperties(LinkProperties newLp) {
+        if (mApfFilter != null) {
+            mApfFilter.setLinkProperties(newLp);
+        }
+        if (mIpReachabilityMonitor != null) {
+            mIpReachabilityMonitor.updateLinkProperties(newLp);
+        }
+
+        ProvisioningChange delta = compareProvisioning(mLinkProperties, newLp);
+        mLinkProperties = new LinkProperties(newLp);
+
+        if (delta == ProvisioningChange.GAINED_PROVISIONING) {
+            // TODO: Add a proper ProvisionedState and cancel the alarm in
+            // its enter() method.
+            mProvisioningTimeoutAlarm.cancel();
+        }
+
+        return delta;
+    }
+
+    private LinkProperties assembleLinkProperties() {
+        // [1] Create a new LinkProperties object to populate.
+        LinkProperties newLp = new LinkProperties();
+        newLp.setInterfaceName(mInterfaceName);
+
+        // [2] Pull in data from netlink:
+        //         - IPv4 addresses
+        //         - IPv6 addresses
+        //         - IPv6 routes
+        //         - IPv6 DNS servers
+        //
+        // N.B.: this is fundamentally race-prone and should be fixed by
+        // changing NetlinkTracker from a hybrid edge/level model to an
+        // edge-only model, or by giving IpClient its own netlink socket(s)
+        // so as to track all required information directly.
+        LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties();
+        newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
+        for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
+            newLp.addRoute(route);
+        }
+        addAllReachableDnsServers(newLp, netlinkLinkProperties.getDnsServers());
+
+        // [3] Add in data from DHCPv4, if available.
+        //
+        // mDhcpResults is never shared with any other owner so we don't have
+        // to worry about concurrent modification.
+        if (mDhcpResults != null) {
+            for (RouteInfo route : mDhcpResults.getRoutes(mInterfaceName)) {
+                newLp.addRoute(route);
+            }
+            addAllReachableDnsServers(newLp, mDhcpResults.dnsServers);
+            newLp.setDomains(mDhcpResults.domains);
+
+            if (mDhcpResults.mtu != 0) {
+                newLp.setMtu(mDhcpResults.mtu);
+            }
+        }
+
+        // [4] Add in TCP buffer sizes and HTTP Proxy config, if available.
+        if (!TextUtils.isEmpty(mTcpBufferSizes)) {
+            newLp.setTcpBufferSizes(mTcpBufferSizes);
+        }
+        if (mHttpProxy != null) {
+            newLp.setHttpProxy(mHttpProxy);
+        }
+
+        // [5] Add data from InitialConfiguration
+        if (mConfiguration != null && mConfiguration.mInitialConfig != null) {
+            InitialConfiguration config = mConfiguration.mInitialConfig;
+            // Add InitialConfiguration routes and dns server addresses once all addresses
+            // specified in the InitialConfiguration have been observed with Netlink.
+            if (config.isProvisionedBy(newLp.getLinkAddresses(), null)) {
+                for (IpPrefix prefix : config.directlyConnectedRoutes) {
+                    newLp.addRoute(new RouteInfo(prefix, null, mInterfaceName));
+                }
+            }
+            addAllReachableDnsServers(newLp, config.dnsServers);
+        }
+        final LinkProperties oldLp = mLinkProperties;
+        if (DBG) {
+            Log.d(mTag, String.format("Netlink-seen LPs: %s, new LPs: %s; old LPs: %s",
+                    netlinkLinkProperties, newLp, oldLp));
+        }
+
+        // TODO: also learn via netlink routes specified by an InitialConfiguration and specified
+        // from a static IP v4 config instead of manually patching them in in steps [3] and [5].
+        return newLp;
+    }
+
+    private static void addAllReachableDnsServers(
+            LinkProperties lp, Iterable<InetAddress> dnses) {
+        // TODO: Investigate deleting this reachability check.  We should be
+        // able to pass everything down to netd and let netd do evaluation
+        // and RFC6724-style sorting.
+        for (InetAddress dns : dnses) {
+            if (!dns.isAnyLocalAddress() && lp.isReachable(dns)) {
+                lp.addDnsServer(dns);
+            }
+        }
+    }
+
+    // Returns false if we have lost provisioning, true otherwise.
+    private boolean handleLinkPropertiesUpdate(boolean sendCallbacks) {
+        final LinkProperties newLp = assembleLinkProperties();
+        if (Objects.equals(newLp, mLinkProperties)) {
+            return true;
+        }
+        final ProvisioningChange delta = setLinkProperties(newLp);
+        if (sendCallbacks) {
+            dispatchCallback(delta, newLp);
+        }
+        return (delta != ProvisioningChange.LOST_PROVISIONING);
+    }
+
+    private void handleIPv4Success(DhcpResults dhcpResults) {
+        mDhcpResults = new DhcpResults(dhcpResults);
+        final LinkProperties newLp = assembleLinkProperties();
+        final ProvisioningChange delta = setLinkProperties(newLp);
+
+        if (DBG) {
+            Log.d(mTag, "onNewDhcpResults(" + Objects.toString(dhcpResults) + ")");
+        }
+        mCallback.onNewDhcpResults(dhcpResults);
+        dispatchCallback(delta, newLp);
+    }
+
+    private void handleIPv4Failure() {
+        // TODO: Investigate deleting this clearIPv4Address() call.
+        //
+        // DhcpClient will send us CMD_CLEAR_LINKADDRESS in all circumstances
+        // that could trigger a call to this function. If we missed handling
+        // that message in StartedState for some reason we would still clear
+        // any addresses upon entry to StoppedState.
+        mInterfaceCtrl.clearIPv4Address();
+        mDhcpResults = null;
+        if (DBG) { Log.d(mTag, "onNewDhcpResults(null)"); }
+        mCallback.onNewDhcpResults(null);
+
+        handleProvisioningFailure();
+    }
+
+    private void handleProvisioningFailure() {
+        final LinkProperties newLp = assembleLinkProperties();
+        ProvisioningChange delta = setLinkProperties(newLp);
+        // If we've gotten here and we're still not provisioned treat that as
+        // a total loss of provisioning.
+        //
+        // Either (a) static IP configuration failed or (b) DHCPv4 failed AND
+        // there was no usable IPv6 obtained before a non-zero provisioning
+        // timeout expired.
+        //
+        // Regardless: GAME OVER.
+        if (delta == ProvisioningChange.STILL_NOT_PROVISIONED) {
+            delta = ProvisioningChange.LOST_PROVISIONING;
+        }
+
+        dispatchCallback(delta, newLp);
+        if (delta == ProvisioningChange.LOST_PROVISIONING) {
+            transitionTo(mStoppingState);
+        }
+    }
+
+    private void doImmediateProvisioningFailure(int failureType) {
+        logError("onProvisioningFailure(): %s", failureType);
+        recordMetric(failureType);
+        mCallback.onProvisioningFailure(new LinkProperties(mLinkProperties));
+    }
+
+    private boolean startIPv4() {
+        // If we have a StaticIpConfiguration attempt to apply it and
+        // handle the result accordingly.
+        if (mConfiguration.mStaticIpConfig != null) {
+            if (mInterfaceCtrl.setIPv4Address(mConfiguration.mStaticIpConfig.ipAddress)) {
+                handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig));
+            } else {
+                return false;
+            }
+        } else {
+            // Start DHCPv4.
+            mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpClient.this, mInterfaceName);
+            mDhcpClient.registerForPreDhcpNotification();
+            mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP);
+        }
+
+        return true;
+    }
+
+    private boolean startIPv6() {
+        return mInterfaceCtrl.setIPv6PrivacyExtensions(true) &&
+               mInterfaceCtrl.setIPv6AddrGenModeIfSupported(mConfiguration.mIPv6AddrGenMode) &&
+               mInterfaceCtrl.enableIPv6();
+    }
+
+    private boolean applyInitialConfig(InitialConfiguration config) {
+        // TODO: also support specifying a static IPv4 configuration in InitialConfiguration.
+        for (LinkAddress addr : findAll(config.ipAddresses, LinkAddress::isIPv6)) {
+            if (!mInterfaceCtrl.addAddress(addr)) return false;
+        }
+
+        return true;
+    }
+
+    private boolean startIpReachabilityMonitor() {
+        try {
+            mIpReachabilityMonitor = new IpReachabilityMonitor(
+                    mContext,
+                    mInterfaceName,
+                    mLog,
+                    new IpReachabilityMonitor.Callback() {
+                        @Override
+                        public void notifyLost(InetAddress ip, String logMsg) {
+                            mCallback.onReachabilityLost(logMsg);
+                        }
+                    },
+                    mMultinetworkPolicyTracker);
+        } catch (IllegalArgumentException iae) {
+            // Failed to start IpReachabilityMonitor. Log it and call
+            // onProvisioningFailure() immediately.
+            //
+            // See http://b/31038971.
+            logError("IpReachabilityMonitor failure: %s", iae);
+            mIpReachabilityMonitor = null;
+        }
+
+        return (mIpReachabilityMonitor != null);
+    }
+
+    private void stopAllIP() {
+        // We don't need to worry about routes, just addresses, because:
+        //     - disableIpv6() will clear autoconf IPv6 routes as well, and
+        //     - we don't get IPv4 routes from netlink
+        // so we neither react to nor need to wait for changes in either.
+
+        mInterfaceCtrl.disableIPv6();
+        mInterfaceCtrl.clearAllAddresses();
+    }
+
+    class StoppedState extends State {
+        @Override
+        public void enter() {
+            stopAllIP();
+
+            resetLinkProperties();
+            if (mStartTimeMillis > 0) {
+                recordMetric(IpManagerEvent.COMPLETE_LIFECYCLE);
+                mStartTimeMillis = 0;
+            }
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case CMD_TERMINATE_AFTER_STOP:
+                    stopStateMachineUpdaters();
+                    quit();
+                    break;
+
+                case CMD_STOP:
+                    break;
+
+                case CMD_START:
+                    mConfiguration = (ProvisioningConfiguration) msg.obj;
+                    transitionTo(mStartedState);
+                    break;
+
+                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
+                    handleLinkPropertiesUpdate(NO_CALLBACKS);
+                    break;
+
+                case CMD_UPDATE_TCP_BUFFER_SIZES:
+                    mTcpBufferSizes = (String) msg.obj;
+                    handleLinkPropertiesUpdate(NO_CALLBACKS);
+                    break;
+
+                case CMD_UPDATE_HTTP_PROXY:
+                    mHttpProxy = (ProxyInfo) msg.obj;
+                    handleLinkPropertiesUpdate(NO_CALLBACKS);
+                    break;
+
+                case CMD_SET_MULTICAST_FILTER:
+                    mMulticastFiltering = (boolean) msg.obj;
+                    break;
+
+                case DhcpClient.CMD_ON_QUIT:
+                    // Everything is already stopped.
+                    logError("Unexpected CMD_ON_QUIT (already stopped).");
+                    break;
+
+                default:
+                    return NOT_HANDLED;
+            }
+
+            mMsgStateLogger.handled(this, getCurrentState());
+            return HANDLED;
+        }
+    }
+
+    class StoppingState extends State {
+        @Override
+        public void enter() {
+            if (mDhcpClient == null) {
+                // There's no DHCPv4 for which to wait; proceed to stopped.
+                transitionTo(mStoppedState);
+            }
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case CMD_STOP:
+                    break;
+
+                case DhcpClient.CMD_CLEAR_LINKADDRESS:
+                    mInterfaceCtrl.clearIPv4Address();
+                    break;
+
+                case DhcpClient.CMD_ON_QUIT:
+                    mDhcpClient = null;
+                    transitionTo(mStoppedState);
+                    break;
+
+                default:
+                    deferMessage(msg);
+            }
+
+            mMsgStateLogger.handled(this, getCurrentState());
+            return HANDLED;
+        }
+    }
+
+    class StartedState extends State {
+        @Override
+        public void enter() {
+            mStartTimeMillis = SystemClock.elapsedRealtime();
+
+            if (mConfiguration.mProvisioningTimeoutMs > 0) {
+                final long alarmTime = SystemClock.elapsedRealtime() +
+                        mConfiguration.mProvisioningTimeoutMs;
+                mProvisioningTimeoutAlarm.schedule(alarmTime);
+            }
+
+            if (readyToProceed()) {
+                transitionTo(mRunningState);
+            } else {
+                // Clear all IPv4 and IPv6 before proceeding to RunningState.
+                // Clean up any leftover state from an abnormal exit from
+                // tethering or during an IpClient restart.
+                stopAllIP();
+            }
+        }
+
+        @Override
+        public void exit() {
+            mProvisioningTimeoutAlarm.cancel();
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case CMD_STOP:
+                    transitionTo(mStoppingState);
+                    break;
+
+                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
+                    handleLinkPropertiesUpdate(NO_CALLBACKS);
+                    if (readyToProceed()) {
+                        transitionTo(mRunningState);
+                    }
+                    break;
+
+                case EVENT_PROVISIONING_TIMEOUT:
+                    handleProvisioningFailure();
+                    break;
+
+                default:
+                    // It's safe to process messages out of order because the
+                    // only message that can both
+                    //     a) be received at this time and
+                    //     b) affect provisioning state
+                    // is EVENT_NETLINK_LINKPROPERTIES_CHANGED (handled above).
+                    deferMessage(msg);
+            }
+
+            mMsgStateLogger.handled(this, getCurrentState());
+            return HANDLED;
+        }
+
+        boolean readyToProceed() {
+            return (!mLinkProperties.hasIPv4Address() &&
+                    !mLinkProperties.hasGlobalIPv6Address());
+        }
+    }
+
+    class RunningState extends State {
+        private ConnectivityPacketTracker mPacketTracker;
+        private boolean mDhcpActionInFlight;
+
+        @Override
+        public void enter() {
+            // Get the Configuration for ApfFilter from Context
+            final boolean filter802_3Frames =
+                    mContext.getResources().getBoolean(R.bool.config_apfDrop802_3Frames);
+
+            final int[] ethTypeBlackList = mContext.getResources().getIntArray(
+                    R.array.config_apfEthTypeBlackList);
+
+            mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
+                    mCallback, mMulticastFiltering, filter802_3Frames, ethTypeBlackList);
+            // TODO: investigate the effects of any multicast filtering racing/interfering with the
+            // rest of this IP configuration startup.
+            if (mApfFilter == null) {
+                mCallback.setFallbackMulticastFilter(mMulticastFiltering);
+            }
+
+            mPacketTracker = createPacketTracker();
+            if (mPacketTracker != null) mPacketTracker.start(mConfiguration.mDisplayName);
+
+            if (mConfiguration.mEnableIPv6 && !startIPv6()) {
+                doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6);
+                transitionTo(mStoppingState);
+                return;
+            }
+
+            if (mConfiguration.mEnableIPv4 && !startIPv4()) {
+                doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV4);
+                transitionTo(mStoppingState);
+                return;
+            }
+
+            final InitialConfiguration config = mConfiguration.mInitialConfig;
+            if ((config != null) && !applyInitialConfig(config)) {
+                // TODO introduce a new IpManagerEvent constant to distinguish this error case.
+                doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
+                transitionTo(mStoppingState);
+                return;
+            }
+
+            if (mConfiguration.mUsingIpReachabilityMonitor && !startIpReachabilityMonitor()) {
+                doImmediateProvisioningFailure(
+                        IpManagerEvent.ERROR_STARTING_IPREACHABILITYMONITOR);
+                transitionTo(mStoppingState);
+                return;
+            }
+        }
+
+        @Override
+        public void exit() {
+            stopDhcpAction();
+
+            if (mIpReachabilityMonitor != null) {
+                mIpReachabilityMonitor.stop();
+                mIpReachabilityMonitor = null;
+            }
+
+            if (mDhcpClient != null) {
+                mDhcpClient.sendMessage(DhcpClient.CMD_STOP_DHCP);
+                mDhcpClient.doQuit();
+            }
+
+            if (mPacketTracker != null) {
+                mPacketTracker.stop();
+                mPacketTracker = null;
+            }
+
+            if (mApfFilter != null) {
+                mApfFilter.shutdown();
+                mApfFilter = null;
+            }
+
+            resetLinkProperties();
+        }
+
+        private ConnectivityPacketTracker createPacketTracker() {
+            try {
+                return new ConnectivityPacketTracker(
+                        getHandler(), mNetworkInterface, mConnectivityPacketLog);
+            } catch (IllegalArgumentException e) {
+                return null;
+            }
+        }
+
+        private void ensureDhcpAction() {
+            if (!mDhcpActionInFlight) {
+                mCallback.onPreDhcpAction();
+                mDhcpActionInFlight = true;
+                final long alarmTime = SystemClock.elapsedRealtime() +
+                        mConfiguration.mRequestedPreDhcpActionMs;
+                mDhcpActionTimeoutAlarm.schedule(alarmTime);
+            }
+        }
+
+        private void stopDhcpAction() {
+            mDhcpActionTimeoutAlarm.cancel();
+            if (mDhcpActionInFlight) {
+                mCallback.onPostDhcpAction();
+                mDhcpActionInFlight = false;
+            }
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case CMD_STOP:
+                    transitionTo(mStoppingState);
+                    break;
+
+                case CMD_START:
+                    logError("ALERT: START received in StartedState. Please fix caller.");
+                    break;
+
+                case CMD_CONFIRM:
+                    // TODO: Possibly introduce a second type of confirmation
+                    // that both probes (a) on-link neighbors and (b) does
+                    // a DHCPv4 RENEW.  We used to do this on Wi-Fi framework
+                    // roams.
+                    if (mIpReachabilityMonitor != null) {
+                        mIpReachabilityMonitor.probeAll();
+                    }
+                    break;
+
+                case EVENT_PRE_DHCP_ACTION_COMPLETE:
+                    // It's possible to reach here if, for example, someone
+                    // calls completedPreDhcpAction() after provisioning with
+                    // a static IP configuration.
+                    if (mDhcpClient != null) {
+                        mDhcpClient.sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE);
+                    }
+                    break;
+
+                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
+                    if (!handleLinkPropertiesUpdate(SEND_CALLBACKS)) {
+                        transitionTo(mStoppingState);
+                    }
+                    break;
+
+                case CMD_UPDATE_TCP_BUFFER_SIZES:
+                    mTcpBufferSizes = (String) msg.obj;
+                    // This cannot possibly change provisioning state.
+                    handleLinkPropertiesUpdate(SEND_CALLBACKS);
+                    break;
+
+                case CMD_UPDATE_HTTP_PROXY:
+                    mHttpProxy = (ProxyInfo) msg.obj;
+                    // This cannot possibly change provisioning state.
+                    handleLinkPropertiesUpdate(SEND_CALLBACKS);
+                    break;
+
+                case CMD_SET_MULTICAST_FILTER: {
+                    mMulticastFiltering = (boolean) msg.obj;
+                    if (mApfFilter != null) {
+                        mApfFilter.setMulticastFilter(mMulticastFiltering);
+                    } else {
+                        mCallback.setFallbackMulticastFilter(mMulticastFiltering);
+                    }
+                    break;
+                }
+
+                case EVENT_DHCPACTION_TIMEOUT:
+                    stopDhcpAction();
+                    break;
+
+                case DhcpClient.CMD_PRE_DHCP_ACTION:
+                    if (mConfiguration.mRequestedPreDhcpActionMs > 0) {
+                        ensureDhcpAction();
+                    } else {
+                        sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
+                    }
+                    break;
+
+                case DhcpClient.CMD_CLEAR_LINKADDRESS:
+                    mInterfaceCtrl.clearIPv4Address();
+                    break;
+
+                case DhcpClient.CMD_CONFIGURE_LINKADDRESS: {
+                    final LinkAddress ipAddress = (LinkAddress) msg.obj;
+                    if (mInterfaceCtrl.setIPv4Address(ipAddress)) {
+                        mDhcpClient.sendMessage(DhcpClient.EVENT_LINKADDRESS_CONFIGURED);
+                    } else {
+                        logError("Failed to set IPv4 address.");
+                        dispatchCallback(ProvisioningChange.LOST_PROVISIONING,
+                                new LinkProperties(mLinkProperties));
+                        transitionTo(mStoppingState);
+                    }
+                    break;
+                }
+
+                // This message is only received when:
+                //
+                //     a) initial address acquisition succeeds,
+                //     b) renew succeeds or is NAK'd,
+                //     c) rebind succeeds or is NAK'd, or
+                //     c) the lease expires,
+                //
+                // but never when initial address acquisition fails. The latter
+                // condition is now governed by the provisioning timeout.
+                case DhcpClient.CMD_POST_DHCP_ACTION:
+                    stopDhcpAction();
+
+                    switch (msg.arg1) {
+                        case DhcpClient.DHCP_SUCCESS:
+                            handleIPv4Success((DhcpResults) msg.obj);
+                            break;
+                        case DhcpClient.DHCP_FAILURE:
+                            handleIPv4Failure();
+                            break;
+                        default:
+                            logError("Unknown CMD_POST_DHCP_ACTION status: %s", msg.arg1);
+                    }
+                    break;
+
+                case DhcpClient.CMD_ON_QUIT:
+                    // DHCPv4 quit early for some reason.
+                    logError("Unexpected CMD_ON_QUIT.");
+                    mDhcpClient = null;
+                    break;
+
+                default:
+                    return NOT_HANDLED;
+            }
+
+            mMsgStateLogger.handled(this, getCurrentState());
+            return HANDLED;
+        }
+    }
+
+    private static class MessageHandlingLogger {
+        public String processedInState;
+        public String receivedInState;
+
+        public void reset() {
+            processedInState = null;
+            receivedInState = null;
+        }
+
+        public void handled(State processedIn, IState receivedIn) {
+            processedInState = processedIn.getClass().getSimpleName();
+            receivedInState = receivedIn.getName();
+        }
+
+        public String toString() {
+            return String.format("rcvd_in=%s, proc_in=%s",
+                                 receivedInState, processedInState);
+        }
+    }
+
+    // TODO: extract out into CollectionUtils.
+    static <T> boolean any(Iterable<T> coll, Predicate<T> fn) {
+        for (T t : coll) {
+            if (fn.test(t)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    static <T> boolean all(Iterable<T> coll, Predicate<T> fn) {
+        return !any(coll, not(fn));
+    }
+
+    static <T> Predicate<T> not(Predicate<T> fn) {
+        return (t) -> !fn.test(t);
+    }
+
+    static <T> String join(String delimiter, Collection<T> coll) {
+        return coll.stream().map(Object::toString).collect(Collectors.joining(delimiter));
+    }
+
+    static <T> T find(Iterable<T> coll, Predicate<T> fn) {
+        for (T t: coll) {
+            if (fn.test(t)) {
+              return t;
+            }
+        }
+        return null;
+    }
+
+    static <T> List<T> findAll(Collection<T> coll, Predicate<T> fn) {
+        return coll.stream().filter(fn).collect(Collectors.toList());
+    }
+}
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index e33f6c9..b12cb32 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,132 +16,112 @@
 
 package android.net.ip;
 
-import com.android.internal.util.MessageUtils;
-import com.android.internal.util.WakeupMessage;
-
 import android.content.Context;
-import android.net.DhcpResults;
 import android.net.INetd;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties.ProvisioningChange;
 import android.net.LinkProperties;
 import android.net.Network;
-import android.net.ProxyInfo;
-import android.net.RouteInfo;
 import android.net.StaticIpConfiguration;
 import android.net.apf.ApfCapabilities;
-import android.net.apf.ApfFilter;
-import android.net.dhcp.DhcpClient;
-import android.net.metrics.IpConnectivityLog;
-import android.net.metrics.IpManagerEvent;
-import android.net.util.MultinetworkPolicyTracker;
 import android.net.util.NetdService;
-import android.net.util.NetworkConstants;
-import android.net.util.SharedLog;
 import android.os.INetworkManagementService;
-import android.os.Message;
-import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.text.TextUtils;
-import android.util.LocalLog;
-import android.util.Log;
-import android.util.SparseArray;
+import android.net.apf.ApfCapabilities;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.R;
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.IState;
-import com.android.internal.util.Preconditions;
-import com.android.internal.util.State;
-import com.android.internal.util.StateMachine;
-import com.android.server.net.NetlinkTracker;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Objects;
-import java.util.List;
-import java.util.Set;
-import java.util.StringJoiner;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
 
 
-/**
- * IpManager
- *
- * This class provides the interface to IP-layer provisioning and maintenance
- * functionality that can be used by transport layers like Wi-Fi, Ethernet,
- * et cetera.
- *
- * [ Lifetime ]
- * IpManager is designed to be instantiated as soon as the interface name is
- * known and can be as long-lived as the class containing it (i.e. declaring
- * it "private final" is okay).
+/*
+ * TODO: Delete this altogether in favor of its renamed successor: IpClient.
  *
  * @hide
  */
-public class IpManager extends StateMachine {
-    private static final boolean DBG = false;
+public class IpManager extends IpClient {
+    public static class ProvisioningConfiguration extends IpClient.ProvisioningConfiguration {
+        public ProvisioningConfiguration(IpClient.ProvisioningConfiguration ipcConfig) {
+            super(ipcConfig);
+        }
 
-    // For message logging.
-    private static final Class[] sMessageClasses = { IpManager.class, DhcpClient.class };
-    private static final SparseArray<String> sWhatToString =
-            MessageUtils.findMessageNames(sMessageClasses);
+        public static class Builder extends IpClient.ProvisioningConfiguration.Builder {
+            @Override
+            public Builder withoutIPv4() {
+                super.withoutIPv4();
+                return this;
+            }
+            @Override
+            public Builder withoutIPv6() {
+                super.withoutIPv6();
+                return this;
+            }
+            @Override
+            public Builder withoutIpReachabilityMonitor() {
+                super.withoutIpReachabilityMonitor();
+                return this;
+            }
+            @Override
+            public Builder withPreDhcpAction() {
+                super.withPreDhcpAction();
+                return this;
+            }
+            @Override
+            public Builder withPreDhcpAction(int dhcpActionTimeoutMs) {
+                super.withPreDhcpAction(dhcpActionTimeoutMs);
+                return this;
+            }
+            // No Override; locally defined type.
+            public Builder withInitialConfiguration(InitialConfiguration initialConfig) {
+                super.withInitialConfiguration((IpClient.InitialConfiguration) initialConfig);
+                return this;
+            }
+            @Override
+            public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
+                super.withStaticConfiguration(staticConfig);
+                return this;
+            }
+            @Override
+            public Builder withApfCapabilities(ApfCapabilities apfCapabilities) {
+                super.withApfCapabilities(apfCapabilities);
+                return this;
+            }
+            @Override
+            public Builder withProvisioningTimeoutMs(int timeoutMs) {
+                super.withProvisioningTimeoutMs(timeoutMs);
+                return this;
+            }
+            @Override
+            public Builder withIPv6AddrGenModeEUI64() {
+                super.withIPv6AddrGenModeEUI64();
+                return this;
+            }
+            @Override
+            public Builder withIPv6AddrGenModeStablePrivacy() {
+                super.withIPv6AddrGenModeStablePrivacy();
+                return this;
+            }
+            @Override
+            public Builder withNetwork(Network network) {
+                super.withNetwork(network);
+                return this;
+            }
+            @Override
+            public Builder withDisplayName(String displayName) {
+                super.withDisplayName(displayName);
+                return this;
+            }
+            @Override
+            public ProvisioningConfiguration build() {
+                return new ProvisioningConfiguration(super.build());
+            }
+        }
+    }
 
-    /**
-     * Callbacks for handling IpManager events.
-     */
-    public static class Callback {
-        // In order to receive onPreDhcpAction(), call #withPreDhcpAction()
-        // when constructing a ProvisioningConfiguration.
-        //
-        // Implementations of onPreDhcpAction() must call
-        // IpManager#completedPreDhcpAction() to indicate that DHCP is clear
-        // to proceed.
-        public void onPreDhcpAction() {}
-        public void onPostDhcpAction() {}
+    public static ProvisioningConfiguration.Builder buildProvisioningConfiguration() {
+        return new ProvisioningConfiguration.Builder();
+    }
 
-        // This is purely advisory and not an indication of provisioning
-        // success or failure.  This is only here for callers that want to
-        // expose DHCPv4 results to other APIs (e.g., WifiInfo#setInetAddress).
-        // DHCPv4 or static IPv4 configuration failure or success can be
-        // determined by whether or not the passed-in DhcpResults object is
-        // null or not.
-        public void onNewDhcpResults(DhcpResults dhcpResults) {}
+    public static class InitialConfiguration extends IpClient.InitialConfiguration {
+    }
 
-        public void onProvisioningSuccess(LinkProperties newLp) {}
-        public void onProvisioningFailure(LinkProperties newLp) {}
-
-        // Invoked on LinkProperties changes.
-        public void onLinkPropertiesChange(LinkProperties newLp) {}
-
-        // Called when the internal IpReachabilityMonitor (if enabled) has
-        // detected the loss of a critical number of required neighbors.
-        public void onReachabilityLost(String logMsg) {}
-
-        // Called when the IpManager state machine terminates.
-        public void onQuit() {}
-
-        // Install an APF program to filter incoming packets.
-        public void installPacketFilter(byte[] filter) {}
-
-        // If multicast filtering cannot be accomplished with APF, this function will be called to
-        // actuate multicast filtering using another means.
-        public void setFallbackMulticastFilter(boolean enabled) {}
-
-        // Enabled/disable Neighbor Discover offload functionality. This is
-        // called, for example, whenever 464xlat is being started or stopped.
-        public void setNeighborDiscoveryOffload(boolean enable) {}
+    public static class Callback extends IpClient.Callback {
     }
 
     public static class WaitForProvisioningCallback extends Callback {
@@ -173,1569 +153,24 @@
         }
     }
 
-    // Use a wrapper class to log in order to ensure complete and detailed
-    // logging. This method is lighter weight than annotations/reflection
-    // and has the following benefits:
-    //
-    //     - No invoked method can be forgotten.
-    //       Any new method added to IpManager.Callback must be overridden
-    //       here or it will never be called.
-    //
-    //     - No invoking call site can be forgotten.
-    //       Centralized logging in this way means call sites don't need to
-    //       remember to log, and therefore no call site can be forgotten.
-    //
-    //     - No variation in log format among call sites.
-    //       Encourages logging of any available arguments, and all call sites
-    //       are necessarily logged identically.
-    //
-    // TODO: Find an lighter weight approach.
-    private class LoggingCallbackWrapper extends Callback {
-        private static final String PREFIX = "INVOKE ";
-        private Callback mCallback;
-
-        public LoggingCallbackWrapper(Callback callback) {
-            mCallback = callback;
-        }
-
-        private void log(String msg) {
-            mLog.log(PREFIX + msg);
-        }
-
-        @Override
-        public void onPreDhcpAction() {
-            mCallback.onPreDhcpAction();
-            log("onPreDhcpAction()");
-        }
-        @Override
-        public void onPostDhcpAction() {
-            mCallback.onPostDhcpAction();
-            log("onPostDhcpAction()");
-        }
-        @Override
-        public void onNewDhcpResults(DhcpResults dhcpResults) {
-            mCallback.onNewDhcpResults(dhcpResults);
-            log("onNewDhcpResults({" + dhcpResults + "})");
-        }
-        @Override
-        public void onProvisioningSuccess(LinkProperties newLp) {
-            mCallback.onProvisioningSuccess(newLp);
-            log("onProvisioningSuccess({" + newLp + "})");
-        }
-        @Override
-        public void onProvisioningFailure(LinkProperties newLp) {
-            mCallback.onProvisioningFailure(newLp);
-            log("onProvisioningFailure({" + newLp + "})");
-        }
-        @Override
-        public void onLinkPropertiesChange(LinkProperties newLp) {
-            mCallback.onLinkPropertiesChange(newLp);
-            log("onLinkPropertiesChange({" + newLp + "})");
-        }
-        @Override
-        public void onReachabilityLost(String logMsg) {
-            mCallback.onReachabilityLost(logMsg);
-            log("onReachabilityLost(" + logMsg + ")");
-        }
-        @Override
-        public void onQuit() {
-            mCallback.onQuit();
-            log("onQuit()");
-        }
-        @Override
-        public void installPacketFilter(byte[] filter) {
-            mCallback.installPacketFilter(filter);
-            log("installPacketFilter(byte[" + filter.length + "])");
-        }
-        @Override
-        public void setFallbackMulticastFilter(boolean enabled) {
-            mCallback.setFallbackMulticastFilter(enabled);
-            log("setFallbackMulticastFilter(" + enabled + ")");
-        }
-        @Override
-        public void setNeighborDiscoveryOffload(boolean enable) {
-            mCallback.setNeighborDiscoveryOffload(enable);
-            log("setNeighborDiscoveryOffload(" + enable + ")");
-        }
-    }
-
-    /**
-     * This class encapsulates parameters to be passed to
-     * IpManager#startProvisioning(). A defensive copy is made by IpManager
-     * and the values specified herein are in force until IpManager#stop()
-     * is called.
-     *
-     * Example use:
-     *
-     *     final ProvisioningConfiguration config =
-     *             mIpManager.buildProvisioningConfiguration()
-     *                     .withPreDhcpAction()
-     *                     .withProvisioningTimeoutMs(36 * 1000)
-     *                     .build();
-     *     mIpManager.startProvisioning(config);
-     *     ...
-     *     mIpManager.stop();
-     *
-     * The specified provisioning configuration will only be active until
-     * IpManager#stop() is called. Future calls to IpManager#startProvisioning()
-     * must specify the configuration again.
-     */
-    public static class ProvisioningConfiguration {
-        // TODO: Delete this default timeout once those callers that care are
-        // fixed to pass in their preferred timeout.
-        //
-        // We pick 36 seconds so we can send DHCP requests at
-        //
-        //     t=0, t=2, t=6, t=14, t=30
-        //
-        // allowing for 10% jitter.
-        private static final int DEFAULT_TIMEOUT_MS = 36 * 1000;
-
-        public static class Builder {
-            private ProvisioningConfiguration mConfig = new ProvisioningConfiguration();
-
-            public Builder withoutIPv4() {
-                mConfig.mEnableIPv4 = false;
-                return this;
-            }
-
-            public Builder withoutIPv6() {
-                mConfig.mEnableIPv6 = false;
-                return this;
-            }
-
-            public Builder withoutIpReachabilityMonitor() {
-                mConfig.mUsingIpReachabilityMonitor = false;
-                return this;
-            }
-
-            public Builder withPreDhcpAction() {
-                mConfig.mRequestedPreDhcpActionMs = DEFAULT_TIMEOUT_MS;
-                return this;
-            }
-
-            public Builder withPreDhcpAction(int dhcpActionTimeoutMs) {
-                mConfig.mRequestedPreDhcpActionMs = dhcpActionTimeoutMs;
-                return this;
-            }
-
-            public Builder withInitialConfiguration(InitialConfiguration initialConfig) {
-                mConfig.mInitialConfig = initialConfig;
-                return this;
-            }
-
-            public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
-                mConfig.mStaticIpConfig = staticConfig;
-                return this;
-            }
-
-            public Builder withApfCapabilities(ApfCapabilities apfCapabilities) {
-                mConfig.mApfCapabilities = apfCapabilities;
-                return this;
-            }
-
-            public Builder withProvisioningTimeoutMs(int timeoutMs) {
-                mConfig.mProvisioningTimeoutMs = timeoutMs;
-                return this;
-            }
-
-            public Builder withIPv6AddrGenModeEUI64() {
-                mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_EUI64;
-                return this;
-            }
-
-            public Builder withIPv6AddrGenModeStablePrivacy() {
-                mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
-                return this;
-            }
-
-            public Builder withNetwork(Network network) {
-                mConfig.mNetwork = network;
-                return this;
-            }
-
-            public Builder withDisplayName(String displayName) {
-                mConfig.mDisplayName = displayName;
-                return this;
-            }
-
-            public ProvisioningConfiguration build() {
-                return new ProvisioningConfiguration(mConfig);
-            }
-        }
-
-        /* package */ boolean mEnableIPv4 = true;
-        /* package */ boolean mEnableIPv6 = true;
-        /* package */ boolean mUsingIpReachabilityMonitor = true;
-        /* package */ int mRequestedPreDhcpActionMs;
-        /* package */ InitialConfiguration mInitialConfig;
-        /* package */ StaticIpConfiguration mStaticIpConfig;
-        /* package */ ApfCapabilities mApfCapabilities;
-        /* package */ int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS;
-        /* package */ int mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
-        /* package */ Network mNetwork = null;
-        /* package */ String mDisplayName = null;
-
-        public ProvisioningConfiguration() {} // used by Builder
-
-        public ProvisioningConfiguration(ProvisioningConfiguration other) {
-            mEnableIPv4 = other.mEnableIPv4;
-            mEnableIPv6 = other.mEnableIPv6;
-            mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor;
-            mRequestedPreDhcpActionMs = other.mRequestedPreDhcpActionMs;
-            mInitialConfig = InitialConfiguration.copy(other.mInitialConfig);
-            mStaticIpConfig = other.mStaticIpConfig;
-            mApfCapabilities = other.mApfCapabilities;
-            mProvisioningTimeoutMs = other.mProvisioningTimeoutMs;
-            mIPv6AddrGenMode = other.mIPv6AddrGenMode;
-            mNetwork = other.mNetwork;
-            mDisplayName = other.mDisplayName;
-        }
-
-        @Override
-        public String toString() {
-            return new StringJoiner(", ", getClass().getSimpleName() + "{", "}")
-                    .add("mEnableIPv4: " + mEnableIPv4)
-                    .add("mEnableIPv6: " + mEnableIPv6)
-                    .add("mUsingIpReachabilityMonitor: " + mUsingIpReachabilityMonitor)
-                    .add("mRequestedPreDhcpActionMs: " + mRequestedPreDhcpActionMs)
-                    .add("mInitialConfig: " + mInitialConfig)
-                    .add("mStaticIpConfig: " + mStaticIpConfig)
-                    .add("mApfCapabilities: " + mApfCapabilities)
-                    .add("mProvisioningTimeoutMs: " + mProvisioningTimeoutMs)
-                    .add("mIPv6AddrGenMode: " + mIPv6AddrGenMode)
-                    .add("mNetwork: " + mNetwork)
-                    .add("mDisplayName: " + mDisplayName)
-                    .toString();
-        }
-
-        public boolean isValid() {
-            return (mInitialConfig == null) || mInitialConfig.isValid();
-        }
-    }
-
-    public static class InitialConfiguration {
-        public final Set<LinkAddress> ipAddresses = new HashSet<>();
-        public final Set<IpPrefix> directlyConnectedRoutes = new HashSet<>();
-        public final Set<InetAddress> dnsServers = new HashSet<>();
-        public Inet4Address gateway; // WiFi legacy behavior with static ipv4 config
-
-        public static InitialConfiguration copy(InitialConfiguration config) {
-            if (config == null) {
-                return null;
-            }
-            InitialConfiguration configCopy = new InitialConfiguration();
-            configCopy.ipAddresses.addAll(config.ipAddresses);
-            configCopy.directlyConnectedRoutes.addAll(config.directlyConnectedRoutes);
-            configCopy.dnsServers.addAll(config.dnsServers);
-            return configCopy;
-        }
-
-        @Override
-        public String toString() {
-            return String.format(
-                    "InitialConfiguration(IPs: {%s}, prefixes: {%s}, DNS: {%s}, v4 gateway: %s)",
-                    join(", ", ipAddresses), join(", ", directlyConnectedRoutes),
-                    join(", ", dnsServers), gateway);
-        }
-
-        public boolean isValid() {
-            if (ipAddresses.isEmpty()) {
-                return false;
-            }
-
-            // For every IP address, there must be at least one prefix containing that address.
-            for (LinkAddress addr : ipAddresses) {
-                if (!any(directlyConnectedRoutes, (p) -> p.contains(addr.getAddress()))) {
-                    return false;
-                }
-            }
-            // For every dns server, there must be at least one prefix containing that address.
-            for (InetAddress addr : dnsServers) {
-                if (!any(directlyConnectedRoutes, (p) -> p.contains(addr))) {
-                    return false;
-                }
-            }
-            // All IPv6 LinkAddresses have an RFC7421-suitable prefix length
-            // (read: compliant with RFC4291#section2.5.4).
-            if (any(ipAddresses, not(InitialConfiguration::isPrefixLengthCompliant))) {
-                return false;
-            }
-            // If directlyConnectedRoutes contains an IPv6 default route
-            // then ipAddresses MUST contain at least one non-ULA GUA.
-            if (any(directlyConnectedRoutes, InitialConfiguration::isIPv6DefaultRoute)
-                    && all(ipAddresses, not(InitialConfiguration::isIPv6GUA))) {
-                return false;
-            }
-            // The prefix length of routes in directlyConnectedRoutes be within reasonable
-            // bounds for IPv6: /48-/64 just as we’d accept in RIOs.
-            if (any(directlyConnectedRoutes, not(InitialConfiguration::isPrefixLengthCompliant))) {
-                return false;
-            }
-            // There no more than one IPv4 address
-            if (ipAddresses.stream().filter(Inet4Address.class::isInstance).count() > 1) {
-                return false;
-            }
-
-            return true;
-        }
-
-        /**
-         * @return true if the given list of addressess and routes satisfies provisioning for this
-         * InitialConfiguration. LinkAddresses and RouteInfo objects are not compared with equality
-         * because addresses and routes seen by Netlink will contain additional fields like flags,
-         * interfaces, and so on. If this InitialConfiguration has no IP address specified, the
-         * provisioning check always fails.
-         *
-         * If the given list of routes is null, only addresses are taken into considerations.
-         */
-        public boolean isProvisionedBy(List<LinkAddress> addresses, List<RouteInfo> routes) {
-            if (ipAddresses.isEmpty()) {
-                return false;
-            }
-
-            for (LinkAddress addr : ipAddresses) {
-                if (!any(addresses, (addrSeen) -> addr.isSameAddressAs(addrSeen))) {
-                    return false;
-                }
-            }
-
-            if (routes != null) {
-                for (IpPrefix prefix : directlyConnectedRoutes) {
-                    if (!any(routes, (routeSeen) -> isDirectlyConnectedRoute(routeSeen, prefix))) {
-                        return false;
-                    }
-                }
-            }
-
-            return true;
-        }
-
-        private static boolean isDirectlyConnectedRoute(RouteInfo route, IpPrefix prefix) {
-            return !route.hasGateway() && prefix.equals(route.getDestination());
-        }
-
-        private static boolean isPrefixLengthCompliant(LinkAddress addr) {
-            return addr.isIPv4() || isCompliantIPv6PrefixLength(addr.getPrefixLength());
-        }
-
-        private static boolean isPrefixLengthCompliant(IpPrefix prefix) {
-            return prefix.isIPv4() || isCompliantIPv6PrefixLength(prefix.getPrefixLength());
-        }
-
-        private static boolean isCompliantIPv6PrefixLength(int prefixLength) {
-            return (NetworkConstants.RFC6177_MIN_PREFIX_LENGTH <= prefixLength)
-                    && (prefixLength <= NetworkConstants.RFC7421_PREFIX_LENGTH);
-        }
-
-        private static boolean isIPv6DefaultRoute(IpPrefix prefix) {
-            return prefix.getAddress().equals(Inet6Address.ANY);
-        }
-
-        private static boolean isIPv6GUA(LinkAddress addr) {
-            return addr.isIPv6() && addr.isGlobalPreferred();
-        }
-    }
-
-    public static final String DUMP_ARG = "ipmanager";
-    public static final String DUMP_ARG_CONFIRM = "confirm";
-
-    private static final int CMD_TERMINATE_AFTER_STOP             = 1;
-    private static final int CMD_STOP                             = 2;
-    private static final int CMD_START                            = 3;
-    private static final int CMD_CONFIRM                          = 4;
-    private static final int EVENT_PRE_DHCP_ACTION_COMPLETE       = 5;
-    // Sent by NetlinkTracker to communicate netlink events.
-    private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 6;
-    private static final int CMD_UPDATE_TCP_BUFFER_SIZES          = 7;
-    private static final int CMD_UPDATE_HTTP_PROXY                = 8;
-    private static final int CMD_SET_MULTICAST_FILTER             = 9;
-    private static final int EVENT_PROVISIONING_TIMEOUT           = 10;
-    private static final int EVENT_DHCPACTION_TIMEOUT             = 11;
-
-    private static final int MAX_LOG_RECORDS = 500;
-    private static final int MAX_PACKET_RECORDS = 100;
-
-    private static final boolean NO_CALLBACKS = false;
-    private static final boolean SEND_CALLBACKS = true;
-
-    // This must match the interface prefix in clatd.c.
-    // TODO: Revert this hack once IpManager and Nat464Xlat work in concert.
-    private static final String CLAT_PREFIX = "v4-";
-
-    private final State mStoppedState = new StoppedState();
-    private final State mStoppingState = new StoppingState();
-    private final State mStartedState = new StartedState();
-    private final State mRunningState = new RunningState();
-
-    private final String mTag;
-    private final Context mContext;
-    private final String mInterfaceName;
-    private final String mClatInterfaceName;
-    @VisibleForTesting
-    protected final Callback mCallback;
-    private final INetworkManagementService mNwService;
-    private final NetlinkTracker mNetlinkTracker;
-    private final WakeupMessage mProvisioningTimeoutAlarm;
-    private final WakeupMessage mDhcpActionTimeoutAlarm;
-    private final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
-    private final SharedLog mLog;
-    private final LocalLog mConnectivityPacketLog;
-    private final MessageHandlingLogger mMsgStateLogger;
-    private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
-    private final InterfaceController mInterfaceCtrl;
-
-    private NetworkInterface mNetworkInterface;
-
-    /**
-     * Non-final member variables accessed only from within our StateMachine.
-     */
-    private LinkProperties mLinkProperties;
-    private ProvisioningConfiguration mConfiguration;
-    private IpReachabilityMonitor mIpReachabilityMonitor;
-    private DhcpClient mDhcpClient;
-    private DhcpResults mDhcpResults;
-    private String mTcpBufferSizes;
-    private ProxyInfo mHttpProxy;
-    private ApfFilter mApfFilter;
-    private boolean mMulticastFiltering;
-    private long mStartTimeMillis;
-
     public IpManager(Context context, String ifName, Callback callback) {
         this(context, ifName, callback, INetworkManagementService.Stub.asInterface(
                 ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)),
                 NetdService.getInstance());
     }
 
-    /**
-     * An expanded constructor, useful for dependency injection.
-     * TODO: migrate all test users to mock IpManager directly and remove this ctor.
-     */
     public IpManager(Context context, String ifName, Callback callback,
             INetworkManagementService nwService) {
         this(context, ifName, callback, nwService, NetdService.getInstance());
     }
 
     @VisibleForTesting
-    IpManager(Context context, String ifName, Callback callback,
+    public IpManager(Context context, String ifName, Callback callback,
             INetworkManagementService nwService, INetd netd) {
-        super(IpManager.class.getSimpleName() + "." + ifName);
-        mTag = getName();
-
-        mContext = context;
-        mInterfaceName = ifName;
-        mClatInterfaceName = CLAT_PREFIX + ifName;
-        mCallback = new LoggingCallbackWrapper(callback);
-        mNwService = nwService;
-
-        mLog = new SharedLog(MAX_LOG_RECORDS, mTag);
-        mConnectivityPacketLog = new LocalLog(MAX_PACKET_RECORDS);
-        mMsgStateLogger = new MessageHandlingLogger();
-
-        mInterfaceCtrl = new InterfaceController(mInterfaceName, mNwService, netd, mLog);
-
-        mNetlinkTracker = new NetlinkTracker(
-                mInterfaceName,
-                new NetlinkTracker.Callback() {
-                    @Override
-                    public void update() {
-                        sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED);
-                    }
-                }) {
-            @Override
-            public void interfaceAdded(String iface) {
-                super.interfaceAdded(iface);
-                if (mClatInterfaceName.equals(iface)) {
-                    mCallback.setNeighborDiscoveryOffload(false);
-                } else if (!mInterfaceName.equals(iface)) {
-                    return;
-                }
-
-                final String msg = "interfaceAdded(" + iface +")";
-                logMsg(msg);
-            }
-
-            @Override
-            public void interfaceRemoved(String iface) {
-                super.interfaceRemoved(iface);
-                // TODO: Also observe mInterfaceName going down and take some
-                // kind of appropriate action.
-                if (mClatInterfaceName.equals(iface)) {
-                    // TODO: consider sending a message to the IpManager main
-                    // StateMachine thread, in case "NDO enabled" state becomes
-                    // tied to more things that 464xlat operation.
-                    mCallback.setNeighborDiscoveryOffload(true);
-                } else if (!mInterfaceName.equals(iface)) {
-                    return;
-                }
-
-                final String msg = "interfaceRemoved(" + iface +")";
-                logMsg(msg);
-            }
-
-            private void logMsg(String msg) {
-                Log.d(mTag, msg);
-                getHandler().post(() -> { mLog.log("OBSERVED " + msg); });
-            }
-        };
-
-        mLinkProperties = new LinkProperties();
-        mLinkProperties.setInterfaceName(mInterfaceName);
-
-        mMultinetworkPolicyTracker = new MultinetworkPolicyTracker(mContext, getHandler(),
-                () -> { mLog.log("OBSERVED AvoidBadWifi changed"); });
-
-        mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
-                mTag + ".EVENT_PROVISIONING_TIMEOUT", EVENT_PROVISIONING_TIMEOUT);
-        mDhcpActionTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
-                mTag + ".EVENT_DHCPACTION_TIMEOUT", EVENT_DHCPACTION_TIMEOUT);
-
-        // Anything the StateMachine may access must have been instantiated
-        // before this point.
-        configureAndStartStateMachine();
-
-        // Anything that may send messages to the StateMachine must only be
-        // configured to do so after the StateMachine has started (above).
-        startStateMachineUpdaters();
-    }
-
-    private void configureAndStartStateMachine() {
-        addState(mStoppedState);
-        addState(mStartedState);
-            addState(mRunningState, mStartedState);
-        addState(mStoppingState);
-
-        setInitialState(mStoppedState);
-
-        super.start();
-    }
-
-    private void startStateMachineUpdaters() {
-        try {
-            mNwService.registerObserver(mNetlinkTracker);
-        } catch (RemoteException e) {
-            logError("Couldn't register NetlinkTracker: %s", e);
-        }
-
-        mMultinetworkPolicyTracker.start();
-    }
-
-    private void stopStateMachineUpdaters() {
-        try {
-            mNwService.unregisterObserver(mNetlinkTracker);
-        } catch (RemoteException e) {
-            logError("Couldn't unregister NetlinkTracker: %s", e);
-        }
-
-        mMultinetworkPolicyTracker.shutdown();
-    }
-
-    @Override
-    protected void onQuitting() {
-        mCallback.onQuit();
-    }
-
-    // Shut down this IpManager instance altogether.
-    public void shutdown() {
-        stop();
-        sendMessage(CMD_TERMINATE_AFTER_STOP);
-    }
-
-    public static ProvisioningConfiguration.Builder buildProvisioningConfiguration() {
-        return new ProvisioningConfiguration.Builder();
+        super(context, ifName, callback, nwService, netd);
     }
 
     public void startProvisioning(ProvisioningConfiguration req) {
-        if (!req.isValid()) {
-            doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
-            return;
-        }
-
-        getNetworkInterface();
-
-        mCallback.setNeighborDiscoveryOffload(true);
-        sendMessage(CMD_START, new ProvisioningConfiguration(req));
-    }
-
-    // TODO: Delete this.
-    public void startProvisioning(StaticIpConfiguration staticIpConfig) {
-        startProvisioning(buildProvisioningConfiguration()
-                .withStaticConfiguration(staticIpConfig)
-                .build());
-    }
-
-    public void startProvisioning() {
-        startProvisioning(new ProvisioningConfiguration());
-    }
-
-    public void stop() {
-        sendMessage(CMD_STOP);
-    }
-
-    public void confirmConfiguration() {
-        sendMessage(CMD_CONFIRM);
-    }
-
-    public void completedPreDhcpAction() {
-        sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
-    }
-
-    /**
-     * Set the TCP buffer sizes to use.
-     *
-     * This may be called, repeatedly, at any time before or after a call to
-     * #startProvisioning(). The setting is cleared upon calling #stop().
-     */
-    public void setTcpBufferSizes(String tcpBufferSizes) {
-        sendMessage(CMD_UPDATE_TCP_BUFFER_SIZES, tcpBufferSizes);
-    }
-
-    /**
-     * Set the HTTP Proxy configuration to use.
-     *
-     * This may be called, repeatedly, at any time before or after a call to
-     * #startProvisioning(). The setting is cleared upon calling #stop().
-     */
-    public void setHttpProxy(ProxyInfo proxyInfo) {
-        sendMessage(CMD_UPDATE_HTTP_PROXY, proxyInfo);
-    }
-
-    /**
-     * Enable or disable the multicast filter.  Attempts to use APF to accomplish the filtering,
-     * if not, Callback.setFallbackMulticastFilter() is called.
-     */
-    public void setMulticastFilter(boolean enabled) {
-        sendMessage(CMD_SET_MULTICAST_FILTER, enabled);
-    }
-
-    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
-        if (args != null && args.length > 0 && DUMP_ARG_CONFIRM.equals(args[0])) {
-            // Execute confirmConfiguration() and take no further action.
-            confirmConfiguration();
-            return;
-        }
-
-        // Thread-unsafe access to mApfFilter but just used for debugging.
-        final ApfFilter apfFilter = mApfFilter;
-        final ProvisioningConfiguration provisioningConfig = mConfiguration;
-        final ApfCapabilities apfCapabilities = (provisioningConfig != null)
-                ? provisioningConfig.mApfCapabilities : null;
-
-        IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
-        pw.println(mTag + " APF dump:");
-        pw.increaseIndent();
-        if (apfFilter != null) {
-            apfFilter.dump(pw);
-        } else {
-            pw.print("No active ApfFilter; ");
-            if (provisioningConfig == null) {
-                pw.println("IpManager not yet started.");
-            } else if (apfCapabilities == null || apfCapabilities.apfVersionSupported == 0) {
-                pw.println("Hardware does not support APF.");
-            } else {
-                pw.println("ApfFilter not yet started, APF capabilities: " + apfCapabilities);
-            }
-        }
-        pw.decreaseIndent();
-
-        pw.println();
-        pw.println(mTag + " current ProvisioningConfiguration:");
-        pw.increaseIndent();
-        pw.println(Objects.toString(provisioningConfig, "N/A"));
-        pw.decreaseIndent();
-
-        pw.println();
-        pw.println(mTag + " StateMachine dump:");
-        pw.increaseIndent();
-        mLog.dump(fd, pw, args);
-        pw.decreaseIndent();
-
-        pw.println();
-        pw.println(mTag + " connectivity packet log:");
-        pw.println();
-        pw.println("Debug with python and scapy via:");
-        pw.println("shell$ python");
-        pw.println(">>> from scapy import all as scapy");
-        pw.println(">>> scapy.Ether(\"<paste_hex_string>\".decode(\"hex\")).show2()");
-        pw.println();
-
-        pw.increaseIndent();
-        mConnectivityPacketLog.readOnlyLocalLog().dump(fd, pw, args);
-        pw.decreaseIndent();
-    }
-
-
-    /**
-     * Internals.
-     */
-
-    @Override
-    protected String getWhatToString(int what) {
-        return sWhatToString.get(what, "UNKNOWN: " + Integer.toString(what));
-    }
-
-    @Override
-    protected String getLogRecString(Message msg) {
-        final String logLine = String.format(
-                "%s/%d %d %d %s [%s]",
-                mInterfaceName, mNetworkInterface == null ? -1 : mNetworkInterface.getIndex(),
-                msg.arg1, msg.arg2, Objects.toString(msg.obj), mMsgStateLogger);
-
-        final String richerLogLine = getWhatToString(msg.what) + " " + logLine;
-        mLog.log(richerLogLine);
-        if (DBG) {
-            Log.d(mTag, richerLogLine);
-        }
-
-        mMsgStateLogger.reset();
-        return logLine;
-    }
-
-    @Override
-    protected boolean recordLogRec(Message msg) {
-        // Don't log EVENT_NETLINK_LINKPROPERTIES_CHANGED. They can be noisy,
-        // and we already log any LinkProperties change that results in an
-        // invocation of IpManager.Callback#onLinkPropertiesChange().
-        final boolean shouldLog = (msg.what != EVENT_NETLINK_LINKPROPERTIES_CHANGED);
-        if (!shouldLog) {
-            mMsgStateLogger.reset();
-        }
-        return shouldLog;
-    }
-
-    private void logError(String fmt, Object... args) {
-        final String msg = "ERROR " + String.format(fmt, args);
-        Log.e(mTag, msg);
-        mLog.log(msg);
-    }
-
-    private void getNetworkInterface() {
-        try {
-            mNetworkInterface = NetworkInterface.getByName(mInterfaceName);
-        } catch (SocketException | NullPointerException e) {
-            // TODO: throw new IllegalStateException.
-            logError("Failed to get interface object: %s", e);
-        }
-    }
-
-    // This needs to be called with care to ensure that our LinkProperties
-    // are in sync with the actual LinkProperties of the interface. For example,
-    // we should only call this if we know for sure that there are no IP addresses
-    // assigned to the interface, etc.
-    private void resetLinkProperties() {
-        mNetlinkTracker.clearLinkProperties();
-        mConfiguration = null;
-        mDhcpResults = null;
-        mTcpBufferSizes = "";
-        mHttpProxy = null;
-
-        mLinkProperties = new LinkProperties();
-        mLinkProperties.setInterfaceName(mInterfaceName);
-    }
-
-    private void recordMetric(final int type) {
-        if (mStartTimeMillis <= 0) { Log.wtf(mTag, "Start time undefined!"); }
-        final long duration = SystemClock.elapsedRealtime() - mStartTimeMillis;
-        mMetricsLog.log(mInterfaceName, new IpManagerEvent(type, duration));
-    }
-
-    // For now: use WifiStateMachine's historical notion of provisioned.
-    @VisibleForTesting
-    static boolean isProvisioned(LinkProperties lp, InitialConfiguration config) {
-        // For historical reasons, we should connect even if all we have is
-        // an IPv4 address and nothing else.
-        if (lp.hasIPv4Address() || lp.isProvisioned()) {
-            return true;
-        }
-        if (config == null) {
-            return false;
-        }
-
-        // When an InitialConfiguration is specified, ignore any difference with previous
-        // properties and instead check if properties observed match the desired properties.
-        return config.isProvisionedBy(lp.getLinkAddresses(), lp.getRoutes());
-    }
-
-    // TODO: Investigate folding all this into the existing static function
-    // LinkProperties.compareProvisioning() or some other single function that
-    // takes two LinkProperties objects and returns a ProvisioningChange
-    // object that is a correct and complete assessment of what changed, taking
-    // account of the asymmetries described in the comments in this function.
-    // Then switch to using it everywhere (IpReachabilityMonitor, etc.).
-    private ProvisioningChange compareProvisioning(LinkProperties oldLp, LinkProperties newLp) {
-        ProvisioningChange delta;
-        InitialConfiguration config = mConfiguration != null ? mConfiguration.mInitialConfig : null;
-        final boolean wasProvisioned = isProvisioned(oldLp, config);
-        final boolean isProvisioned = isProvisioned(newLp, config);
-
-        if (!wasProvisioned && isProvisioned) {
-            delta = ProvisioningChange.GAINED_PROVISIONING;
-        } else if (wasProvisioned && isProvisioned) {
-            delta = ProvisioningChange.STILL_PROVISIONED;
-        } else if (!wasProvisioned && !isProvisioned) {
-            delta = ProvisioningChange.STILL_NOT_PROVISIONED;
-        } else {
-            // (wasProvisioned && !isProvisioned)
-            //
-            // Note that this is true even if we lose a configuration element
-            // (e.g., a default gateway) that would not be required to advance
-            // into provisioned state. This is intended: if we have a default
-            // router and we lose it, that's a sure sign of a problem, but if
-            // we connect to a network with no IPv4 DNS servers, we consider
-            // that to be a network without DNS servers and connect anyway.
-            //
-            // See the comment below.
-            delta = ProvisioningChange.LOST_PROVISIONING;
-        }
-
-        final boolean lostIPv6 = oldLp.isIPv6Provisioned() && !newLp.isIPv6Provisioned();
-        final boolean lostIPv4Address = oldLp.hasIPv4Address() && !newLp.hasIPv4Address();
-        final boolean lostIPv6Router = oldLp.hasIPv6DefaultRoute() && !newLp.hasIPv6DefaultRoute();
-
-        // If bad wifi avoidance is disabled, then ignore IPv6 loss of
-        // provisioning. Otherwise, when a hotspot that loses Internet
-        // access sends out a 0-lifetime RA to its clients, the clients
-        // will disconnect and then reconnect, avoiding the bad hotspot,
-        // instead of getting stuck on the bad hotspot. http://b/31827713 .
-        //
-        // This is incorrect because if the hotspot then regains Internet
-        // access with a different prefix, TCP connections on the
-        // deprecated addresses will remain stuck.
-        //
-        // Note that we can still be disconnected by IpReachabilityMonitor
-        // if the IPv6 default gateway (but not the IPv6 DNS servers; see
-        // accompanying code in IpReachabilityMonitor) is unreachable.
-        final boolean ignoreIPv6ProvisioningLoss = !mMultinetworkPolicyTracker.getAvoidBadWifi();
-
-        // Additionally:
-        //
-        // Partial configurations (e.g., only an IPv4 address with no DNS
-        // servers and no default route) are accepted as long as DHCPv4
-        // succeeds. On such a network, isProvisioned() will always return
-        // false, because the configuration is not complete, but we want to
-        // connect anyway. It might be a disconnected network such as a
-        // Chromecast or a wireless printer, for example.
-        //
-        // Because on such a network isProvisioned() will always return false,
-        // delta will never be LOST_PROVISIONING. So check for loss of
-        // provisioning here too.
-        if (lostIPv4Address || (lostIPv6 && !ignoreIPv6ProvisioningLoss)) {
-            delta = ProvisioningChange.LOST_PROVISIONING;
-        }
-
-        // Additionally:
-        //
-        // If the previous link properties had a global IPv6 address and an
-        // IPv6 default route then also consider the loss of that default route
-        // to be a loss of provisioning. See b/27962810.
-        if (oldLp.hasGlobalIPv6Address() && (lostIPv6Router && !ignoreIPv6ProvisioningLoss)) {
-            delta = ProvisioningChange.LOST_PROVISIONING;
-        }
-
-        return delta;
-    }
-
-    private void dispatchCallback(ProvisioningChange delta, LinkProperties newLp) {
-        switch (delta) {
-            case GAINED_PROVISIONING:
-                if (DBG) { Log.d(mTag, "onProvisioningSuccess()"); }
-                recordMetric(IpManagerEvent.PROVISIONING_OK);
-                mCallback.onProvisioningSuccess(newLp);
-                break;
-
-            case LOST_PROVISIONING:
-                if (DBG) { Log.d(mTag, "onProvisioningFailure()"); }
-                recordMetric(IpManagerEvent.PROVISIONING_FAIL);
-                mCallback.onProvisioningFailure(newLp);
-                break;
-
-            default:
-                if (DBG) { Log.d(mTag, "onLinkPropertiesChange()"); }
-                mCallback.onLinkPropertiesChange(newLp);
-                break;
-        }
-    }
-
-    // Updates all IpManager-related state concerned with LinkProperties.
-    // Returns a ProvisioningChange for possibly notifying other interested
-    // parties that are not fronted by IpManager.
-    private ProvisioningChange setLinkProperties(LinkProperties newLp) {
-        if (mApfFilter != null) {
-            mApfFilter.setLinkProperties(newLp);
-        }
-        if (mIpReachabilityMonitor != null) {
-            mIpReachabilityMonitor.updateLinkProperties(newLp);
-        }
-
-        ProvisioningChange delta = compareProvisioning(mLinkProperties, newLp);
-        mLinkProperties = new LinkProperties(newLp);
-
-        if (delta == ProvisioningChange.GAINED_PROVISIONING) {
-            // TODO: Add a proper ProvisionedState and cancel the alarm in
-            // its enter() method.
-            mProvisioningTimeoutAlarm.cancel();
-        }
-
-        return delta;
-    }
-
-    private LinkProperties assembleLinkProperties() {
-        // [1] Create a new LinkProperties object to populate.
-        LinkProperties newLp = new LinkProperties();
-        newLp.setInterfaceName(mInterfaceName);
-
-        // [2] Pull in data from netlink:
-        //         - IPv4 addresses
-        //         - IPv6 addresses
-        //         - IPv6 routes
-        //         - IPv6 DNS servers
-        //
-        // N.B.: this is fundamentally race-prone and should be fixed by
-        // changing NetlinkTracker from a hybrid edge/level model to an
-        // edge-only model, or by giving IpManager its own netlink socket(s)
-        // so as to track all required information directly.
-        LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties();
-        newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
-        for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
-            newLp.addRoute(route);
-        }
-        addAllReachableDnsServers(newLp, netlinkLinkProperties.getDnsServers());
-
-        // [3] Add in data from DHCPv4, if available.
-        //
-        // mDhcpResults is never shared with any other owner so we don't have
-        // to worry about concurrent modification.
-        if (mDhcpResults != null) {
-            for (RouteInfo route : mDhcpResults.getRoutes(mInterfaceName)) {
-                newLp.addRoute(route);
-            }
-            addAllReachableDnsServers(newLp, mDhcpResults.dnsServers);
-            newLp.setDomains(mDhcpResults.domains);
-
-            if (mDhcpResults.mtu != 0) {
-                newLp.setMtu(mDhcpResults.mtu);
-            }
-        }
-
-        // [4] Add in TCP buffer sizes and HTTP Proxy config, if available.
-        if (!TextUtils.isEmpty(mTcpBufferSizes)) {
-            newLp.setTcpBufferSizes(mTcpBufferSizes);
-        }
-        if (mHttpProxy != null) {
-            newLp.setHttpProxy(mHttpProxy);
-        }
-
-        // [5] Add data from InitialConfiguration
-        if (mConfiguration != null && mConfiguration.mInitialConfig != null) {
-            InitialConfiguration config = mConfiguration.mInitialConfig;
-            // Add InitialConfiguration routes and dns server addresses once all addresses
-            // specified in the InitialConfiguration have been observed with Netlink.
-            if (config.isProvisionedBy(newLp.getLinkAddresses(), null)) {
-                for (IpPrefix prefix : config.directlyConnectedRoutes) {
-                    newLp.addRoute(new RouteInfo(prefix, null, mInterfaceName));
-                }
-            }
-            addAllReachableDnsServers(newLp, config.dnsServers);
-        }
-        final LinkProperties oldLp = mLinkProperties;
-        if (DBG) {
-            Log.d(mTag, String.format("Netlink-seen LPs: %s, new LPs: %s; old LPs: %s",
-                    netlinkLinkProperties, newLp, oldLp));
-        }
-
-        // TODO: also learn via netlink routes specified by an InitialConfiguration and specified
-        // from a static IP v4 config instead of manually patching them in in steps [3] and [5].
-        return newLp;
-    }
-
-    private static void addAllReachableDnsServers(
-            LinkProperties lp, Iterable<InetAddress> dnses) {
-        // TODO: Investigate deleting this reachability check.  We should be
-        // able to pass everything down to netd and let netd do evaluation
-        // and RFC6724-style sorting.
-        for (InetAddress dns : dnses) {
-            if (!dns.isAnyLocalAddress() && lp.isReachable(dns)) {
-                lp.addDnsServer(dns);
-            }
-        }
-    }
-
-    // Returns false if we have lost provisioning, true otherwise.
-    private boolean handleLinkPropertiesUpdate(boolean sendCallbacks) {
-        final LinkProperties newLp = assembleLinkProperties();
-        if (Objects.equals(newLp, mLinkProperties)) {
-            return true;
-        }
-        final ProvisioningChange delta = setLinkProperties(newLp);
-        if (sendCallbacks) {
-            dispatchCallback(delta, newLp);
-        }
-        return (delta != ProvisioningChange.LOST_PROVISIONING);
-    }
-
-    private void handleIPv4Success(DhcpResults dhcpResults) {
-        mDhcpResults = new DhcpResults(dhcpResults);
-        final LinkProperties newLp = assembleLinkProperties();
-        final ProvisioningChange delta = setLinkProperties(newLp);
-
-        if (DBG) {
-            Log.d(mTag, "onNewDhcpResults(" + Objects.toString(dhcpResults) + ")");
-        }
-        mCallback.onNewDhcpResults(dhcpResults);
-        dispatchCallback(delta, newLp);
-    }
-
-    private void handleIPv4Failure() {
-        // TODO: Investigate deleting this clearIPv4Address() call.
-        //
-        // DhcpClient will send us CMD_CLEAR_LINKADDRESS in all circumstances
-        // that could trigger a call to this function. If we missed handling
-        // that message in StartedState for some reason we would still clear
-        // any addresses upon entry to StoppedState.
-        mInterfaceCtrl.clearIPv4Address();
-        mDhcpResults = null;
-        if (DBG) { Log.d(mTag, "onNewDhcpResults(null)"); }
-        mCallback.onNewDhcpResults(null);
-
-        handleProvisioningFailure();
-    }
-
-    private void handleProvisioningFailure() {
-        final LinkProperties newLp = assembleLinkProperties();
-        ProvisioningChange delta = setLinkProperties(newLp);
-        // If we've gotten here and we're still not provisioned treat that as
-        // a total loss of provisioning.
-        //
-        // Either (a) static IP configuration failed or (b) DHCPv4 failed AND
-        // there was no usable IPv6 obtained before a non-zero provisioning
-        // timeout expired.
-        //
-        // Regardless: GAME OVER.
-        if (delta == ProvisioningChange.STILL_NOT_PROVISIONED) {
-            delta = ProvisioningChange.LOST_PROVISIONING;
-        }
-
-        dispatchCallback(delta, newLp);
-        if (delta == ProvisioningChange.LOST_PROVISIONING) {
-            transitionTo(mStoppingState);
-        }
-    }
-
-    private void doImmediateProvisioningFailure(int failureType) {
-        logError("onProvisioningFailure(): %s", failureType);
-        recordMetric(failureType);
-        mCallback.onProvisioningFailure(new LinkProperties(mLinkProperties));
-    }
-
-    private boolean startIPv4() {
-        // If we have a StaticIpConfiguration attempt to apply it and
-        // handle the result accordingly.
-        if (mConfiguration.mStaticIpConfig != null) {
-            if (mInterfaceCtrl.setIPv4Address(mConfiguration.mStaticIpConfig.ipAddress)) {
-                handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig));
-            } else {
-                return false;
-            }
-        } else {
-            // Start DHCPv4.
-            mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpManager.this, mInterfaceName);
-            mDhcpClient.registerForPreDhcpNotification();
-            mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP);
-        }
-
-        return true;
-    }
-
-    private boolean startIPv6() {
-        return mInterfaceCtrl.setIPv6PrivacyExtensions(true) &&
-               mInterfaceCtrl.setIPv6AddrGenModeIfSupported(mConfiguration.mIPv6AddrGenMode) &&
-               mInterfaceCtrl.enableIPv6();
-    }
-
-    private boolean applyInitialConfig(InitialConfiguration config) {
-        // TODO: also support specifying a static IPv4 configuration in InitialConfiguration.
-        for (LinkAddress addr : findAll(config.ipAddresses, LinkAddress::isIPv6)) {
-            if (!mInterfaceCtrl.addAddress(addr)) return false;
-        }
-
-        return true;
-    }
-
-    private boolean startIpReachabilityMonitor() {
-        try {
-            mIpReachabilityMonitor = new IpReachabilityMonitor(
-                    mContext,
-                    mInterfaceName,
-                    mLog,
-                    new IpReachabilityMonitor.Callback() {
-                        @Override
-                        public void notifyLost(InetAddress ip, String logMsg) {
-                            mCallback.onReachabilityLost(logMsg);
-                        }
-                    },
-                    mMultinetworkPolicyTracker);
-        } catch (IllegalArgumentException iae) {
-            // Failed to start IpReachabilityMonitor. Log it and call
-            // onProvisioningFailure() immediately.
-            //
-            // See http://b/31038971.
-            logError("IpReachabilityMonitor failure: %s", iae);
-            mIpReachabilityMonitor = null;
-        }
-
-        return (mIpReachabilityMonitor != null);
-    }
-
-    private void stopAllIP() {
-        // We don't need to worry about routes, just addresses, because:
-        //     - disableIpv6() will clear autoconf IPv6 routes as well, and
-        //     - we don't get IPv4 routes from netlink
-        // so we neither react to nor need to wait for changes in either.
-
-        mInterfaceCtrl.disableIPv6();
-        mInterfaceCtrl.clearAllAddresses();
-    }
-
-    class StoppedState extends State {
-        @Override
-        public void enter() {
-            stopAllIP();
-
-            resetLinkProperties();
-            if (mStartTimeMillis > 0) {
-                recordMetric(IpManagerEvent.COMPLETE_LIFECYCLE);
-                mStartTimeMillis = 0;
-            }
-        }
-
-        @Override
-        public boolean processMessage(Message msg) {
-            switch (msg.what) {
-                case CMD_TERMINATE_AFTER_STOP:
-                    stopStateMachineUpdaters();
-                    quit();
-                    break;
-
-                case CMD_STOP:
-                    break;
-
-                case CMD_START:
-                    mConfiguration = (ProvisioningConfiguration) msg.obj;
-                    transitionTo(mStartedState);
-                    break;
-
-                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
-                    handleLinkPropertiesUpdate(NO_CALLBACKS);
-                    break;
-
-                case CMD_UPDATE_TCP_BUFFER_SIZES:
-                    mTcpBufferSizes = (String) msg.obj;
-                    handleLinkPropertiesUpdate(NO_CALLBACKS);
-                    break;
-
-                case CMD_UPDATE_HTTP_PROXY:
-                    mHttpProxy = (ProxyInfo) msg.obj;
-                    handleLinkPropertiesUpdate(NO_CALLBACKS);
-                    break;
-
-                case CMD_SET_MULTICAST_FILTER:
-                    mMulticastFiltering = (boolean) msg.obj;
-                    break;
-
-                case DhcpClient.CMD_ON_QUIT:
-                    // Everything is already stopped.
-                    logError("Unexpected CMD_ON_QUIT (already stopped).");
-                    break;
-
-                default:
-                    return NOT_HANDLED;
-            }
-
-            mMsgStateLogger.handled(this, getCurrentState());
-            return HANDLED;
-        }
-    }
-
-    class StoppingState extends State {
-        @Override
-        public void enter() {
-            if (mDhcpClient == null) {
-                // There's no DHCPv4 for which to wait; proceed to stopped.
-                transitionTo(mStoppedState);
-            }
-        }
-
-        @Override
-        public boolean processMessage(Message msg) {
-            switch (msg.what) {
-                case CMD_STOP:
-                    break;
-
-                case DhcpClient.CMD_CLEAR_LINKADDRESS:
-                    mInterfaceCtrl.clearIPv4Address();
-                    break;
-
-                case DhcpClient.CMD_ON_QUIT:
-                    mDhcpClient = null;
-                    transitionTo(mStoppedState);
-                    break;
-
-                default:
-                    deferMessage(msg);
-            }
-
-            mMsgStateLogger.handled(this, getCurrentState());
-            return HANDLED;
-        }
-    }
-
-    class StartedState extends State {
-        @Override
-        public void enter() {
-            mStartTimeMillis = SystemClock.elapsedRealtime();
-
-            if (mConfiguration.mProvisioningTimeoutMs > 0) {
-                final long alarmTime = SystemClock.elapsedRealtime() +
-                        mConfiguration.mProvisioningTimeoutMs;
-                mProvisioningTimeoutAlarm.schedule(alarmTime);
-            }
-
-            if (readyToProceed()) {
-                transitionTo(mRunningState);
-            } else {
-                // Clear all IPv4 and IPv6 before proceeding to RunningState.
-                // Clean up any leftover state from an abnormal exit from
-                // tethering or during an IpManager restart.
-                stopAllIP();
-            }
-        }
-
-        @Override
-        public void exit() {
-            mProvisioningTimeoutAlarm.cancel();
-        }
-
-        @Override
-        public boolean processMessage(Message msg) {
-            switch (msg.what) {
-                case CMD_STOP:
-                    transitionTo(mStoppingState);
-                    break;
-
-                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
-                    handleLinkPropertiesUpdate(NO_CALLBACKS);
-                    if (readyToProceed()) {
-                        transitionTo(mRunningState);
-                    }
-                    break;
-
-                case EVENT_PROVISIONING_TIMEOUT:
-                    handleProvisioningFailure();
-                    break;
-
-                default:
-                    // It's safe to process messages out of order because the
-                    // only message that can both
-                    //     a) be received at this time and
-                    //     b) affect provisioning state
-                    // is EVENT_NETLINK_LINKPROPERTIES_CHANGED (handled above).
-                    deferMessage(msg);
-            }
-
-            mMsgStateLogger.handled(this, getCurrentState());
-            return HANDLED;
-        }
-
-        boolean readyToProceed() {
-            return (!mLinkProperties.hasIPv4Address() &&
-                    !mLinkProperties.hasGlobalIPv6Address());
-        }
-    }
-
-    class RunningState extends State {
-        private ConnectivityPacketTracker mPacketTracker;
-        private boolean mDhcpActionInFlight;
-
-        @Override
-        public void enter() {
-            // Get the Configuration for ApfFilter from Context
-            final boolean filter802_3Frames =
-                    mContext.getResources().getBoolean(R.bool.config_apfDrop802_3Frames);
-
-            final int[] ethTypeBlackList = mContext.getResources().getIntArray(
-                    R.array.config_apfEthTypeBlackList);
-
-            mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
-                    mCallback, mMulticastFiltering, filter802_3Frames, ethTypeBlackList);
-            // TODO: investigate the effects of any multicast filtering racing/interfering with the
-            // rest of this IP configuration startup.
-            if (mApfFilter == null) {
-                mCallback.setFallbackMulticastFilter(mMulticastFiltering);
-            }
-
-            mPacketTracker = createPacketTracker();
-            if (mPacketTracker != null) mPacketTracker.start(mConfiguration.mDisplayName);
-
-            if (mConfiguration.mEnableIPv6 && !startIPv6()) {
-                doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6);
-                transitionTo(mStoppingState);
-                return;
-            }
-
-            if (mConfiguration.mEnableIPv4 && !startIPv4()) {
-                doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV4);
-                transitionTo(mStoppingState);
-                return;
-            }
-
-            final InitialConfiguration config = mConfiguration.mInitialConfig;
-            if ((config != null) && !applyInitialConfig(config)) {
-                // TODO introduce a new IpManagerEvent constant to distinguish this error case.
-                doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
-                transitionTo(mStoppingState);
-                return;
-            }
-
-            if (mConfiguration.mUsingIpReachabilityMonitor && !startIpReachabilityMonitor()) {
-                doImmediateProvisioningFailure(
-                        IpManagerEvent.ERROR_STARTING_IPREACHABILITYMONITOR);
-                transitionTo(mStoppingState);
-                return;
-            }
-        }
-
-        @Override
-        public void exit() {
-            stopDhcpAction();
-
-            if (mIpReachabilityMonitor != null) {
-                mIpReachabilityMonitor.stop();
-                mIpReachabilityMonitor = null;
-            }
-
-            if (mDhcpClient != null) {
-                mDhcpClient.sendMessage(DhcpClient.CMD_STOP_DHCP);
-                mDhcpClient.doQuit();
-            }
-
-            if (mPacketTracker != null) {
-                mPacketTracker.stop();
-                mPacketTracker = null;
-            }
-
-            if (mApfFilter != null) {
-                mApfFilter.shutdown();
-                mApfFilter = null;
-            }
-
-            resetLinkProperties();
-        }
-
-        private ConnectivityPacketTracker createPacketTracker() {
-            try {
-                return new ConnectivityPacketTracker(
-                        getHandler(), mNetworkInterface, mConnectivityPacketLog);
-            } catch (IllegalArgumentException e) {
-                return null;
-            }
-        }
-
-        private void ensureDhcpAction() {
-            if (!mDhcpActionInFlight) {
-                mCallback.onPreDhcpAction();
-                mDhcpActionInFlight = true;
-                final long alarmTime = SystemClock.elapsedRealtime() +
-                        mConfiguration.mRequestedPreDhcpActionMs;
-                mDhcpActionTimeoutAlarm.schedule(alarmTime);
-            }
-        }
-
-        private void stopDhcpAction() {
-            mDhcpActionTimeoutAlarm.cancel();
-            if (mDhcpActionInFlight) {
-                mCallback.onPostDhcpAction();
-                mDhcpActionInFlight = false;
-            }
-        }
-
-        @Override
-        public boolean processMessage(Message msg) {
-            switch (msg.what) {
-                case CMD_STOP:
-                    transitionTo(mStoppingState);
-                    break;
-
-                case CMD_START:
-                    logError("ALERT: START received in StartedState. Please fix caller.");
-                    break;
-
-                case CMD_CONFIRM:
-                    // TODO: Possibly introduce a second type of confirmation
-                    // that both probes (a) on-link neighbors and (b) does
-                    // a DHCPv4 RENEW.  We used to do this on Wi-Fi framework
-                    // roams.
-                    if (mIpReachabilityMonitor != null) {
-                        mIpReachabilityMonitor.probeAll();
-                    }
-                    break;
-
-                case EVENT_PRE_DHCP_ACTION_COMPLETE:
-                    // It's possible to reach here if, for example, someone
-                    // calls completedPreDhcpAction() after provisioning with
-                    // a static IP configuration.
-                    if (mDhcpClient != null) {
-                        mDhcpClient.sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE);
-                    }
-                    break;
-
-                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
-                    if (!handleLinkPropertiesUpdate(SEND_CALLBACKS)) {
-                        transitionTo(mStoppingState);
-                    }
-                    break;
-
-                case CMD_UPDATE_TCP_BUFFER_SIZES:
-                    mTcpBufferSizes = (String) msg.obj;
-                    // This cannot possibly change provisioning state.
-                    handleLinkPropertiesUpdate(SEND_CALLBACKS);
-                    break;
-
-                case CMD_UPDATE_HTTP_PROXY:
-                    mHttpProxy = (ProxyInfo) msg.obj;
-                    // This cannot possibly change provisioning state.
-                    handleLinkPropertiesUpdate(SEND_CALLBACKS);
-                    break;
-
-                case CMD_SET_MULTICAST_FILTER: {
-                    mMulticastFiltering = (boolean) msg.obj;
-                    if (mApfFilter != null) {
-                        mApfFilter.setMulticastFilter(mMulticastFiltering);
-                    } else {
-                        mCallback.setFallbackMulticastFilter(mMulticastFiltering);
-                    }
-                    break;
-                }
-
-                case EVENT_DHCPACTION_TIMEOUT:
-                    stopDhcpAction();
-                    break;
-
-                case DhcpClient.CMD_PRE_DHCP_ACTION:
-                    if (mConfiguration.mRequestedPreDhcpActionMs > 0) {
-                        ensureDhcpAction();
-                    } else {
-                        sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
-                    }
-                    break;
-
-                case DhcpClient.CMD_CLEAR_LINKADDRESS:
-                    mInterfaceCtrl.clearIPv4Address();
-                    break;
-
-                case DhcpClient.CMD_CONFIGURE_LINKADDRESS: {
-                    final LinkAddress ipAddress = (LinkAddress) msg.obj;
-                    if (mInterfaceCtrl.setIPv4Address(ipAddress)) {
-                        mDhcpClient.sendMessage(DhcpClient.EVENT_LINKADDRESS_CONFIGURED);
-                    } else {
-                        logError("Failed to set IPv4 address.");
-                        dispatchCallback(ProvisioningChange.LOST_PROVISIONING,
-                                new LinkProperties(mLinkProperties));
-                        transitionTo(mStoppingState);
-                    }
-                    break;
-                }
-
-                // This message is only received when:
-                //
-                //     a) initial address acquisition succeeds,
-                //     b) renew succeeds or is NAK'd,
-                //     c) rebind succeeds or is NAK'd, or
-                //     c) the lease expires,
-                //
-                // but never when initial address acquisition fails. The latter
-                // condition is now governed by the provisioning timeout.
-                case DhcpClient.CMD_POST_DHCP_ACTION:
-                    stopDhcpAction();
-
-                    switch (msg.arg1) {
-                        case DhcpClient.DHCP_SUCCESS:
-                            handleIPv4Success((DhcpResults) msg.obj);
-                            break;
-                        case DhcpClient.DHCP_FAILURE:
-                            handleIPv4Failure();
-                            break;
-                        default:
-                            logError("Unknown CMD_POST_DHCP_ACTION status: %s", msg.arg1);
-                    }
-                    break;
-
-                case DhcpClient.CMD_ON_QUIT:
-                    // DHCPv4 quit early for some reason.
-                    logError("Unexpected CMD_ON_QUIT.");
-                    mDhcpClient = null;
-                    break;
-
-                default:
-                    return NOT_HANDLED;
-            }
-
-            mMsgStateLogger.handled(this, getCurrentState());
-            return HANDLED;
-        }
-    }
-
-    private static class MessageHandlingLogger {
-        public String processedInState;
-        public String receivedInState;
-
-        public void reset() {
-            processedInState = null;
-            receivedInState = null;
-        }
-
-        public void handled(State processedIn, IState receivedIn) {
-            processedInState = processedIn.getClass().getSimpleName();
-            receivedInState = receivedIn.getName();
-        }
-
-        public String toString() {
-            return String.format("rcvd_in=%s, proc_in=%s",
-                                 receivedInState, processedInState);
-        }
-    }
-
-    // TODO: extract out into CollectionUtils.
-    static <T> boolean any(Iterable<T> coll, Predicate<T> fn) {
-        for (T t : coll) {
-            if (fn.test(t)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    static <T> boolean all(Iterable<T> coll, Predicate<T> fn) {
-        return !any(coll, not(fn));
-    }
-
-    static <T> Predicate<T> not(Predicate<T> fn) {
-        return (t) -> !fn.test(t);
-    }
-
-    static <T> String join(String delimiter, Collection<T> coll) {
-        return coll.stream().map(Object::toString).collect(Collectors.joining(delimiter));
-    }
-
-    static <T> T find(Iterable<T> coll, Predicate<T> fn) {
-        for (T t: coll) {
-            if (fn.test(t)) {
-              return t;
-            }
-        }
-        return null;
-    }
-
-    static <T> List<T> findAll(Collection<T> coll, Predicate<T> fn) {
-        return coll.stream().filter(fn).collect(Collectors.toList());
+        super.startProvisioning((IpClient.ProvisioningConfiguration) req);
     }
 }
diff --git a/services/net/java/android/net/netlink/NetlinkSocket.java b/services/net/java/android/net/netlink/NetlinkSocket.java
index a9e0cd9..f5f211d 100644
--- a/services/net/java/android/net/netlink/NetlinkSocket.java
+++ b/services/net/java/android/net/netlink/NetlinkSocket.java
@@ -96,7 +96,7 @@
         mDescriptor = Os.socket(
                 OsConstants.AF_NETLINK, OsConstants.SOCK_DGRAM, nlProto);
 
-        Libcore.os.setsockoptInt(
+        Os.setsockoptInt(
                 mDescriptor, OsConstants.SOL_SOCKET,
                 OsConstants.SO_RCVBUF, SOCKET_RECV_BUFSIZE);
     }
diff --git a/services/tests/notification/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/notification/src/com/android/server/notification/ZenModeHelperTest.java
new file mode 100644
index 0000000..cbe9650
--- /dev/null
+++ b/services/tests/notification/src/com/android/server/notification/ZenModeHelperTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distriZenbuted 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.notification;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.media.AudioAttributes;
+import android.provider.Settings;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class ZenModeHelperTest extends NotificationTestCase {
+
+    @Mock ConditionProviders mConditionProviders;
+    private TestableLooper mTestableLooper;
+    private ZenModeHelper mZenModeHelperSpy;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mTestableLooper = TestableLooper.get(this);
+        mZenModeHelperSpy = spy(new ZenModeHelper(getContext(), mTestableLooper.getLooper(),
+                mConditionProviders));
+    }
+
+    @Test
+    public void testZenOff_NoMuteApplied() {
+        mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_OFF;
+        assertTrue(mZenModeHelperSpy.mConfig.allowAlarms);
+        mZenModeHelperSpy.applyRestrictions();
+
+        doNothing().when(mZenModeHelperSpy).applyRestrictions(anyBoolean(), anyInt());
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+                AudioAttributes.USAGE_ALARM);
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+                AudioAttributes.USAGE_MEDIA);
+    }
+
+    @Test
+    public void testZenOn_AllowAlarmsMedia_NoAlarmMediaMuteApplied() {
+        mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        assertTrue(mZenModeHelperSpy.mConfig.allowAlarms);
+        assertTrue(mZenModeHelperSpy.mConfig.allowMediaSystemOther);
+        mZenModeHelperSpy.applyRestrictions();
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+                AudioAttributes.USAGE_ALARM);
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+                AudioAttributes.USAGE_MEDIA);
+    }
+
+    @Test
+    public void testZenOn_DisallowAlarmsMedia_AlarmMediaMuteApplied() {
+
+        mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mConfig.allowAlarms = false;
+        mZenModeHelperSpy.mConfig.allowMediaSystemOther = false;
+        assertFalse(mZenModeHelperSpy.mConfig.allowAlarms);
+        assertFalse(mZenModeHelperSpy.mConfig.allowMediaSystemOther);
+        mZenModeHelperSpy.applyRestrictions();
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+                AudioAttributes.USAGE_ALARM);
+
+        // Media is a catch-all that includes games and system sounds
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+                AudioAttributes.USAGE_MEDIA);
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+                AudioAttributes.USAGE_GAME);
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+                AudioAttributes.USAGE_ASSISTANCE_SONIFICATION);
+    }
+}
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 6d7d4cb..8e41a55 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -33,7 +33,10 @@
     aidl/com/android/servicestests/aidl/ICmdReceiverService.aidl
 LOCAL_SRC_FILES += $(call all-java-files-under, test-apps/JobTestApp/src)
 
-LOCAL_JAVA_LIBRARIES := android.test.mock legacy-android-test
+LOCAL_JAVA_LIBRARIES := \
+    android.hidl.manager-V1.0-java \
+    android.test.mock \
+    legacy-android-test \
 
 LOCAL_PACKAGE_NAME := FrameworksServicesTests
 LOCAL_COMPATIBILITY_SUITE := device-tests
diff --git a/services/tests/servicestests/assets/shortcut/shortcut_api27_backup.xml b/services/tests/servicestests/assets/shortcut/shortcut_api27_backup.xml
new file mode 100644
index 0000000..266ab99
--- /dev/null
+++ b/services/tests/servicestests/assets/shortcut/shortcut_api27_backup.xml
@@ -0,0 +1,19 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<user>
+    <launcher-pins package-name="com.android.launcher.1" launcher-user="0">
+        <package-info version="9" last_udpate_time="1230768000000">
+            <signature hash="0X8l7PvMeFf3vr6kaTCL4LJYCUPpbROjrZihNnXEv8I" />
+        </package-info>
+        <package package-name="com.android.test.1" package-user="0">
+            <pin value="s1" />
+        </package>
+    </launcher-pins>
+    <package name="com.android.test.1" call-count="0" last-reset="1506991428317">
+        <package-info version="8" last_udpate_time="1506534668998">
+            <signature hash="zDmdc5A/Bu5pQDKrBTjwVjT/fhzl6OUKwzCocUhPNM8" />
+        </package-info>
+        <shortcut id="s1" activity="com.android.test.1/com.example.android.shortcutsample.Main" title="Leak wakelock" titleid="0" textid="0" dmessageid="0" timestamp="1507674156622" flags="130">
+            <intent intent-base="#Intent;action=com.example.android.shortcutsample.LEAK;launchFlags=0x1000c000;component=com.example.android.shortcutsample/.Main;end" />
+        </shortcut>
+    </package>
+</user>
diff --git a/services/tests/servicestests/res/values/strings.xml b/services/tests/servicestests/res/values/strings.xml
index 121c1de..1253d44 100644
--- a/services/tests/servicestests/res/values/strings.xml
+++ b/services/tests/servicestests/res/values/strings.xml
@@ -21,6 +21,9 @@
     <string name="shortcut_title2"></string>
     <string name="shortcut_text2"></string>
     <string name="shortcut_disabled_message2"></string>
+    <string name="shortcut_title3"></string>
+    <string name="shortcut_text3"></string>
+    <string name="shortcut_disabled_message3"></string>
     <string name="test_account_type1_authenticator_label">AccountManagerService Test Account Type1</string>
     <string name="test_account_type2_authenticator_label">AccountManagerService Test Account Type2</string>
     <string name="test_account_type1">com.android.server.accounts.account_manager_service_test.account.type1</string>
diff --git a/services/tests/servicestests/res/xml/shortcut_5_altalt.xml b/services/tests/servicestests/res/xml/shortcut_5_altalt.xml
new file mode 100644
index 0000000..b17895e
--- /dev/null
+++ b/services/tests/servicestests/res/xml/shortcut_5_altalt.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
+    <shortcut
+        android:shortcutId="ms1"
+        android:enabled="true"
+        android:icon="@drawable/icon1"
+        android:shortcutShortLabel="@string/shortcut_title1"
+        android:shortcutLongLabel="@string/shortcut_text1"
+        android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
+        >
+        <intent
+            android:action="action1"
+            android:data="http://a.b.c/1"
+            >
+        </intent>
+        <categories android:name="android.shortcut.conversation" />
+        <categories android:name="android.shortcut.media" />
+    </shortcut>
+    <shortcut
+        android:shortcutId="ms2"
+        android:enabled="true"
+        android:icon="@drawable/icon2"
+        android:shortcutShortLabel="@string/shortcut_title2"
+        android:shortcutLongLabel="@string/shortcut_text2"
+        android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
+        >
+        <intent
+            android:action="action2"
+            >
+        </intent>
+        <categories android:name="android.shortcut.conversation" />
+    </shortcut>
+    <shortcut
+        android:shortcutId="ms3"
+        android:shortcutShortLabel="@string/shortcut_title1"
+        android:shortcutLongLabel="@string/shortcut_title2"
+        android:shortcutDisabledMessage="@string/shortcut_disabled_message3"
+        >
+        <intent
+            android:action="android.intent.action.VIEW"
+            >
+        </intent>
+    </shortcut>
+    <shortcut
+        android:shortcutId="ms4"
+        android:shortcutShortLabel="@string/shortcut_title2"
+        android:shortcutLongLabel="@string/shortcut_title2"
+        >
+        <intent
+            android:action="android.intent.action.VIEW2"
+            >
+        </intent>
+        <categories />
+        <categories android:name="" />
+        <categories android:name="cat" />
+    </shortcut>
+    <shortcut
+        android:shortcutId="ms5"
+        android:shortcutShortLabel="@string/shortcut_title1"
+        >
+        <intent
+            android:action="action"
+            android:data="http://www/"
+            android:targetPackage="abc"
+            android:targetClass=".xyz"
+            android:mimeType="foo/bar"
+            >
+            <categories android:name="cat1" />
+            <categories android:name="cat2" />
+            <extra android:name="key1" android:value="value1" />
+            <extra android:name="key2" android:value="value2" />
+        </intent>
+    </shortcut>
+</shortcuts>
diff --git a/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java b/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java
new file mode 100644
index 0000000..daaad7a8
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static junit.framework.Assert.*;
+import static org.mockito.Mockito.*;
+
+import android.hardware.health.V2_0.IHealth;
+import android.hidl.manager.V1_0.IServiceManager;
+import android.hidl.manager.V1_0.IServiceNotification;
+import android.os.RemoteException;
+import android.support.test.filters.SmallTest;
+import android.test.AndroidTestCase;
+import android.util.Slog;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.NoSuchElementException;
+
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+
+
+public class BatteryServiceTest extends AndroidTestCase {
+
+    @Mock IServiceManager mMockedManager;
+    @Mock IHealth mMockedHal;
+
+    @Mock BatteryService.HealthServiceWrapper.Callback mCallback;
+    @Mock BatteryService.HealthServiceWrapper.IServiceManagerSupplier mManagerSupplier;
+    @Mock BatteryService.HealthServiceWrapper.IHealthSupplier mHealthServiceSupplier;
+    BatteryService.HealthServiceWrapper mWrapper;
+
+    private static final String HEALTHD = BatteryService.HealthServiceWrapper.INSTANCE_HEALTHD;
+    private static final String VENDOR = BatteryService.HealthServiceWrapper.INSTANCE_VENDOR;
+
+    @Override
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    public static <T> ArgumentMatcher<T> isOneOf(Collection<T> collection) {
+        return new ArgumentMatcher<T>() {
+            @Override public boolean matches(T e) {
+                return collection.contains(e);
+            }
+            @Override public String toString() {
+                return collection.toString();
+            }
+        };
+    }
+
+    private void initForInstances(String... instanceNamesArr) throws Exception {
+        final Collection<String> instanceNames = Arrays.asList(instanceNamesArr);
+        doAnswer((invocation) -> {
+                Slog.e("BatteryServiceTest", "health: onRegistration " + invocation.getArguments()[2]);
+                ((IServiceNotification)invocation.getArguments()[2]).onRegistration(
+                        IHealth.kInterfaceName,
+                        (String)invocation.getArguments()[1],
+                        true /* preexisting */);
+                return null;
+            }).when(mMockedManager).registerForNotifications(
+                eq(IHealth.kInterfaceName),
+                argThat(isOneOf(instanceNames)),
+                any(IServiceNotification.class));
+
+        doReturn(mMockedHal).when(mMockedManager)
+            .get(eq(IHealth.kInterfaceName), argThat(isOneOf(instanceNames)));
+
+        doReturn(IServiceManager.Transport.HWBINDER).when(mMockedManager)
+            .getTransport(eq(IHealth.kInterfaceName), argThat(isOneOf(instanceNames)));
+
+        doReturn(mMockedManager).when(mManagerSupplier).get();
+        doReturn(mMockedHal).when(mHealthServiceSupplier)
+            .get(argThat(isOneOf(instanceNames)));
+
+        mWrapper = new BatteryService.HealthServiceWrapper();
+    }
+
+    @SmallTest
+    public void testWrapPreferVendor() throws Exception {
+        initForInstances(VENDOR, HEALTHD);
+        mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier);
+        verify(mCallback).onRegistration(same(null), same(mMockedHal), eq(VENDOR));
+    }
+
+    @SmallTest
+    public void testUseHealthd() throws Exception {
+        initForInstances(HEALTHD);
+        mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier);
+        verify(mCallback).onRegistration(same(null), same(mMockedHal), eq(HEALTHD));
+    }
+
+    @SmallTest
+    public void testNoService() throws Exception {
+        initForInstances("unrelated");
+        try {
+            mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier);
+            fail("Expect NoSuchElementException");
+        } catch (NoSuchElementException ex) {
+            // expected
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityCacheTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityCacheTest.java
index 02f645a..c8dc9ff 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityCacheTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityCacheTest.java
@@ -77,7 +77,6 @@
         mAccessibilityCache.clear();
         AccessibilityInteractionClient.getInstance().clearCache();
         assertEquals(0, numA11yWinInfosInUse.get());
-        assertEquals(0, numA11yNodeInfosInUse.get());
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
index 50824e3..8a54c4e 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
@@ -16,7 +16,6 @@
 
 package com.android.server.accessibility;
 
-import static android.util.ExceptionUtils.propagate;
 import static android.view.MotionEvent.ACTION_DOWN;
 import static android.view.MotionEvent.ACTION_MOVE;
 import static android.view.MotionEvent.ACTION_POINTER_DOWN;
@@ -105,8 +104,8 @@
         MagnificationGestureHandler h = new MagnificationGestureHandler(
                 mContext, mMagnificationController,
                 detectTripleTap, detectShortcutTrigger);
-        mHandler = new TestHandler(h.mDetectingStateHandler, mClock);
-        h.mDetectingStateHandler.mHandler = mHandler;
+        mHandler = new TestHandler(h.mDetectingState, mClock);
+        h.mDetectingState.mHandler = mHandler;
         h.setNext(strictMock(EventStreamTransformation.class));
         return h;
     }
@@ -229,7 +228,7 @@
         allowEventDelegation();
         tap();
         // no fast forward
-        verify(mMgh.mNext, times(2)).onMotionEvent(any(), any(), anyInt());
+        verify(mMgh.getNext(), times(2)).onMotionEvent(any(), any(), anyInt());
     }
 
     private void assertTransition(int fromState, Runnable transitionAction, int toState) {
@@ -250,7 +249,7 @@
     }
 
     private void allowEventDelegation() {
-        doNothing().when(mMgh.mNext).onMotionEvent(any(), any(), anyInt());
+        doNothing().when(mMgh.getNext()).onMotionEvent(any(), any(), anyInt());
     }
 
     private void fastForward1sec() {
@@ -272,7 +271,7 @@
 
             case STATE_IDLE: {
                 check(tapCount() < 2, state);
-                check(!mMgh.mShortcutTriggered, state);
+                check(!mMgh.mDetectingState.mShortcutTriggered, state);
                 check(!isZoomed(), state);
             } break;
             case STATE_ZOOMED: {
@@ -288,28 +287,28 @@
                 check(tapCount() == 2, state);
             } break;
             case STATE_DRAGGING: {
-                check(mMgh.mCurrentState == MagnificationGestureHandler.STATE_VIEWPORT_DRAGGING,
+                check(mMgh.mCurrentState == mMgh.mViewportDraggingState,
                         state);
-                check(mMgh.mViewportDraggingStateHandler.mZoomedInBeforeDrag, state);
+                check(mMgh.mViewportDraggingState.mZoomedInBeforeDrag, state);
             } break;
             case STATE_DRAGGING_TMP: {
-                check(mMgh.mCurrentState == MagnificationGestureHandler.STATE_VIEWPORT_DRAGGING,
+                check(mMgh.mCurrentState == mMgh.mViewportDraggingState,
                         state);
-                check(!mMgh.mViewportDraggingStateHandler.mZoomedInBeforeDrag, state);
+                check(!mMgh.mViewportDraggingState.mZoomedInBeforeDrag, state);
             } break;
             case STATE_SHORTCUT_TRIGGERED: {
-                check(mMgh.mShortcutTriggered, state);
+                check(mMgh.mDetectingState.mShortcutTriggered, state);
                 check(!isZoomed(), state);
             } break;
             case STATE_PANNING: {
-                check(mMgh.mCurrentState == MagnificationGestureHandler.STATE_PANNING_SCALING,
+                check(mMgh.mCurrentState == mMgh.mPanningScalingState,
                         state);
-                check(!mMgh.mPanningScalingStateHandler.mScaling, state);
+                check(!mMgh.mPanningScalingState.mScaling, state);
             } break;
             case STATE_SCALING_AND_PANNING: {
-                check(mMgh.mCurrentState == MagnificationGestureHandler.STATE_PANNING_SCALING,
+                check(mMgh.mCurrentState == mMgh.mPanningScalingState,
                         state);
-                check(mMgh.mPanningScalingStateHandler.mScaling, state);
+                check(mMgh.mPanningScalingState.mScaling, state);
             } break;
             default: throw new IllegalArgumentException("Illegal state: " + state);
         }
@@ -432,7 +431,7 @@
     }
 
     private int tapCount() {
-        return mMgh.mDetectingStateHandler.tapCount();
+        return mMgh.mDetectingState.tapCount();
     }
 
     private static String stateToString(int state) {
@@ -492,7 +491,7 @@
     }
 
     private long defaultDownTime() {
-        MotionEvent lastDown = mMgh.mDetectingStateHandler.mLastDown;
+        MotionEvent lastDown = mMgh.mDetectingState.mLastDown;
         return lastDown == null ? mClock.now() - 1 : lastDown.getDownTime();
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
index 6b93d0e..60a55fa 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
@@ -77,7 +77,7 @@
     @Test
     public void testRestoringInvalidTask() throws Exception {
         TaskRecord task = mSupervisor.anyTaskForIdLocked(0 /*taskId*/,
-                MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, null);
+                MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, null, false /* onTop */);
         assertNull(task);
     }
 
@@ -116,9 +116,9 @@
         mSupervisor.moveActivityToPinnedStackLocked(secondActivity, sourceBounds,
                 0f /*aspectRatio*/, false, "secondMove");
 
-        // Need to get pinned stack again as a new instance might have been created.
+        // Need to get stacks again as a new instance might have been created.
         pinnedStack = display.getPinnedStack();
-
+        mFullscreenStack = display.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
         // Ensure stacks have swapped tasks.
         ensureStackPlacement(pinnedStack, secondTask);
         ensureStackPlacement(mFullscreenStack, firstTask);
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
index e1623b0..026abce 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
@@ -60,7 +60,7 @@
     public void setUp() throws Exception {
         super.setUp();
         mService = createActivityManagerService();
-        mStarter = new ActivityStarter(mService, mService.mStackSupervisor);
+        mStarter = new ActivityStarter(mService);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index cc8bd69..20077f3 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -103,15 +103,21 @@
 
     protected static TaskRecord createTask(ActivityStackSupervisor supervisor,
             ComponentName component, ActivityStack stack) {
+        return createTask(supervisor, component, 0 /* flags */, 0 /* taskId */, stack);
+    }
+
+    protected static TaskRecord createTask(ActivityStackSupervisor supervisor,
+            ComponentName component, int flags, int taskId, ActivityStack stack) {
         final ActivityInfo aInfo = new ActivityInfo();
         aInfo.applicationInfo = new ApplicationInfo();
         aInfo.applicationInfo.packageName = component.getPackageName();
 
         Intent intent = new Intent();
         intent.setComponent(component);
+        intent.setFlags(flags);
 
-        final TaskRecord task = new TaskRecord(supervisor.mService, 0, aInfo, intent /*intent*/,
-                null /*_taskDescription*/);
+        final TaskRecord task = new TaskRecord(supervisor.mService, taskId, aInfo,
+                intent /*intent*/, null /*_taskDescription*/);
         supervisor.setFocusStackUnchecked("test", stack);
         stack.addTask(task, true, "creating test task");
         task.setStack(stack);
diff --git a/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java b/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java
index f9d7f9d4..4c1d3e9 100644
--- a/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java
@@ -189,6 +189,8 @@
 
         // THEN lock task mode should be started
         verifyLockTaskStarted(STATUS_BAR_MASK_PINNED);
+        // THEN screen pinning toast should be shown
+        verify(mLockTaskNotify).showPinningStartToast();
     }
 
     @Test
@@ -255,8 +257,6 @@
         // WHEN system calls stopLockTaskMode
         mLockTaskController.stopLockTaskMode(true, SYSTEM_UID);
 
-        // THEN a lock tash toast should be shown
-        verify(mLockTaskNotify).showToast(LOCK_TASK_MODE_LOCKED);
         // THEN lock task mode should still be active
         assertEquals(LOCK_TASK_MODE_LOCKED, mLockTaskController.getLockTaskModeState());
     }
@@ -302,6 +302,8 @@
         verifyLockTaskStopped(times(1));
         // THEN the keyguard should be shown
         verify(mLockPatternUtils).requireCredentialEntry(UserHandle.USER_ALL);
+        // THEN screen pinning toast should be shown
+        verify(mLockTaskNotify).showPinningExitToast();
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
new file mode 100644
index 0000000..e607228
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.Debug;
+import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.MutableLong;
+import android.util.SparseBooleanArray;
+
+import com.android.server.am.RecentTasks.Callbacks;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * runtest --path frameworks/base/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
+ */
+@MediumTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class RecentTasksTest extends ActivityTestsBase {
+    private static final int TEST_USER_0_ID = 0;
+    private static final int TEST_USER_1_ID = 10;
+    private static final int TEST_QUIET_USER_ID = 20;
+    private static final UserInfo DEFAULT_USER_INFO = new UserInfo();
+    private static final UserInfo QUIET_USER_INFO = new UserInfo();
+    private static int LAST_TASK_ID = 1;
+
+    private Context mContext = InstrumentationRegistry.getContext();
+    private ActivityManagerService mService;
+    private ActivityStack mStack;
+    private TestTaskPersister mTaskPersister;
+    private RecentTasks mRecentTasks;
+
+    private static ArrayList<TaskRecord> mTasks = new ArrayList<>();
+    private static ArrayList<TaskRecord> mSameDocumentTasks = new ArrayList<>();
+
+    private CallbacksRecorder mCallbacksRecorder;
+
+    class TestUserController extends UserController {
+        TestUserController(ActivityManagerService service) {
+            super(service);
+        }
+
+        @Override
+        int[] getCurrentProfileIds() {
+            return new int[] { TEST_USER_0_ID, TEST_QUIET_USER_ID };
+        }
+
+        @Override
+        UserInfo getUserInfo(int userId) {
+            switch (userId) {
+                case TEST_USER_0_ID:
+                case TEST_USER_1_ID:
+                    return DEFAULT_USER_INFO;
+                case TEST_QUIET_USER_ID:
+                    return QUIET_USER_INFO;
+            }
+            return null;
+        }
+    }
+
+    @Before
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        mService = createActivityManagerService();
+        mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+        mTaskPersister = new TestTaskPersister(mContext.getFilesDir());
+        mRecentTasks = new RecentTasks(mService, mTaskPersister, new TestUserController(mService));
+        mRecentTasks.loadParametersFromResources(mContext.getResources());
+        mCallbacksRecorder = new CallbacksRecorder();
+        mRecentTasks.registerCallback(mCallbacksRecorder);
+        QUIET_USER_INFO.flags = UserInfo.FLAG_MANAGED_PROFILE | UserInfo.FLAG_QUIET_MODE;
+
+        mTasks.add(createTask(".Task1"));
+        mTasks.add(createTask(".Task2"));
+        mTasks.add(createTask(".Task3"));
+        mTasks.add(createTask(".Task4"));
+        mTasks.add(createTask(".Task5"));
+
+        mSameDocumentTasks.add(createDocumentTask(".DocumentTask1", null /* affinity */));
+        mSameDocumentTasks.add(createDocumentTask(".DocumentTask1", null /* affinity */));
+    }
+
+    @Test
+    public void testCallbacks() throws Exception {
+        // Add some tasks
+        mRecentTasks.add(mTasks.get(0));
+        mRecentTasks.add(mTasks.get(1));
+        assertTrue(mCallbacksRecorder.added.contains(mTasks.get(0))
+                && mCallbacksRecorder.added.contains(mTasks.get(1)));
+        assertTrue(mCallbacksRecorder.trimmed.isEmpty());
+        assertTrue(mCallbacksRecorder.removed.isEmpty());
+        mCallbacksRecorder.clear();
+
+        // Remove some tasks
+        mRecentTasks.remove(mTasks.get(0));
+        mRecentTasks.remove(mTasks.get(1));
+        assertTrue(mCallbacksRecorder.added.isEmpty());
+        assertTrue(mCallbacksRecorder.trimmed.isEmpty());
+        assertTrue(mCallbacksRecorder.removed.contains(mTasks.get(0)));
+        assertTrue(mCallbacksRecorder.removed.contains(mTasks.get(1)));
+        mCallbacksRecorder.clear();
+
+        // Add a task which will trigger the trimming of another
+        TaskRecord documentTask1 = createDocumentTask(".DocumentTask1", null /* affinity */);
+        documentTask1.maxRecents = 1;
+        TaskRecord documentTask2 = createDocumentTask(".DocumentTask1", null /* affinity */);
+        mRecentTasks.add(documentTask1);
+        mRecentTasks.add(documentTask2);
+        assertTrue(mCallbacksRecorder.added.contains(documentTask1));
+        assertTrue(mCallbacksRecorder.added.contains(documentTask2));
+        assertTrue(mCallbacksRecorder.trimmed.contains(documentTask1));
+        assertTrue(mCallbacksRecorder.removed.contains(documentTask1));
+        mCallbacksRecorder.clear();
+
+        // Remove the callback, ensure we don't get any calls
+        mRecentTasks.unregisterCallback(mCallbacksRecorder);
+        mRecentTasks.add(mTasks.get(0));
+        mRecentTasks.remove(mTasks.get(0));
+        assertTrue(mCallbacksRecorder.added.isEmpty());
+        assertTrue(mCallbacksRecorder.trimmed.isEmpty());
+        assertTrue(mCallbacksRecorder.removed.isEmpty());
+    }
+
+    @Test
+    public void testUsersTasks() throws Exception {
+        // Setup some tasks for the users
+        mTaskPersister.userTaskIdsOverride = new SparseBooleanArray();
+        mTaskPersister.userTaskIdsOverride.put(1, true);
+        mTaskPersister.userTaskIdsOverride.put(2, true);
+        mTaskPersister.userTasksOverride = new ArrayList<>();
+        mTaskPersister.userTasksOverride.add(createTask(".UserTask1"));
+        mTaskPersister.userTasksOverride.add(createTask(".UserTask2"));
+
+        // Assert no user tasks are initially loaded
+        assertTrue(mRecentTasks.usersWithRecentsLoadedLocked().length == 0);
+
+        // Load user 0 tasks
+        mRecentTasks.loadUserRecentsLocked(TEST_USER_0_ID);
+        assertTrue(arrayContainsUser(mRecentTasks.usersWithRecentsLoadedLocked(), TEST_USER_0_ID));
+        assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID));
+        assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_0_ID));
+
+        // Load user 1 tasks
+        mRecentTasks.loadUserRecentsLocked(TEST_USER_1_ID);
+        assertTrue(arrayContainsUser(mRecentTasks.usersWithRecentsLoadedLocked(), TEST_USER_0_ID));
+        assertTrue(arrayContainsUser(mRecentTasks.usersWithRecentsLoadedLocked(), TEST_USER_1_ID));
+        assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID));
+        assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_0_ID));
+        assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_1_ID));
+        assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_1_ID));
+
+        // Unload user 1 tasks
+        mRecentTasks.unloadUserDataFromMemoryLocked(TEST_USER_1_ID);
+        assertTrue(arrayContainsUser(mRecentTasks.usersWithRecentsLoadedLocked(), TEST_USER_0_ID));
+        assertFalse(arrayContainsUser(mRecentTasks.usersWithRecentsLoadedLocked(), TEST_USER_1_ID));
+        assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID));
+        assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_0_ID));
+
+        // Unload user 0 tasks
+        mRecentTasks.unloadUserDataFromMemoryLocked(TEST_USER_0_ID);
+        assertFalse(arrayContainsUser(mRecentTasks.usersWithRecentsLoadedLocked(), TEST_USER_0_ID));
+        assertFalse(arrayContainsUser(mRecentTasks.usersWithRecentsLoadedLocked(), TEST_USER_1_ID));
+    }
+
+    @Test
+    public void testOrderedIteration() throws Exception {
+        MutableLong prevLastActiveTime = new MutableLong(0);
+        final ArrayList<TaskRecord> tasks = mRecentTasks.getRawTasks();
+        for (int i = 0; i < tasks.size(); i++) {
+            final TaskRecord task = tasks.get(i);
+            assertTrue(task.lastActiveTime >= prevLastActiveTime.value);
+            prevLastActiveTime.value = task.lastActiveTime;
+        }
+    }
+
+    @Test
+    public void testTrimToGlobalMaxNumRecents() throws Exception {
+        // Limit the global maximum number of recent tasks to a fixed size
+        mRecentTasks.setGlobalMaxNumTasks(2 /* globalMaxNumTasks */);
+
+        // Add N+1 tasks
+        mRecentTasks.add(mTasks.get(0));
+        mRecentTasks.add(mTasks.get(1));
+        mRecentTasks.add(mTasks.get(2));
+
+        // Ensure that the last task was trimmed as an inactive task
+        assertTrimmed(mTasks.get(0));
+    }
+
+    @Test
+    public void testTrimQuietProfileTasks() throws Exception {
+        TaskRecord qt1 = createTask(".QuietTask1", TEST_QUIET_USER_ID);
+        TaskRecord qt2 = createTask(".QuietTask2", TEST_QUIET_USER_ID);
+        mRecentTasks.add(qt1);
+        mRecentTasks.add(qt2);
+
+        mRecentTasks.add(mTasks.get(0));
+        mRecentTasks.add(mTasks.get(1));
+
+        // Ensure that the quiet user's tasks was trimmed once the new tasks were added
+        assertTrimmed(qt1, qt2);
+    }
+
+    @Test
+    public void testSessionDuration() throws Exception {
+        mRecentTasks.setParameters(-1 /* min */, -1 /* max */, 50 /* ms */);
+
+        TaskRecord t1 = createTask(".Task1");
+        t1.touchActiveTime();
+        mRecentTasks.add(t1);
+
+        // Force a small sleep just beyond the session duration
+        SystemClock.sleep(75);
+
+        TaskRecord t2 = createTask(".Task2");
+        t2.touchActiveTime();
+        mRecentTasks.add(t2);
+
+        // Assert that the old task has been removed due to being out of the active session
+        assertTrimmed(t1);
+    }
+
+    @Test
+    public void testVisibleTasks_excludedFromRecents() throws Exception {
+        mRecentTasks.setParameters(-1 /* min */, 4 /* max */, -1 /* ms */);
+
+        TaskRecord excludedTask1 = createTask(".ExcludedTask1", FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS,
+                TEST_USER_0_ID);
+        TaskRecord excludedTask2 = createTask(".ExcludedTask2", FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS,
+                TEST_USER_0_ID);
+
+        mRecentTasks.add(excludedTask1);
+        mRecentTasks.add(mTasks.get(0));
+        mRecentTasks.add(mTasks.get(1));
+        mRecentTasks.add(mTasks.get(2));
+        mRecentTasks.add(excludedTask2);
+
+        // The last excluded task should be trimmed, while the first-most excluded task should not
+        assertTrimmed(excludedTask1);
+    }
+
+    @Test
+    public void testVisibleTasks_minNum() throws Exception {
+        mRecentTasks.setParameters(5 /* min */, -1 /* max */, 25 /* ms */);
+
+        for (int i = 0; i < 4; i++) {
+            final TaskRecord task = mTasks.get(i);
+            task.touchActiveTime();
+            mRecentTasks.add(task);
+        }
+
+        // Force a small sleep just beyond the session duration
+        SystemClock.sleep(50);
+
+        // Add a new task to trigger tasks to be trimmed
+        mRecentTasks.add(mTasks.get(4));
+
+        // Ensure that there are a minimum number of tasks regardless of session length
+        assertTrue(mCallbacksRecorder.trimmed.isEmpty());
+        assertTrue(mCallbacksRecorder.removed.isEmpty());
+    }
+
+    @Test
+    public void testVisibleTasks_maxNum() throws Exception {
+        mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */);
+
+        for (int i = 0; i < 5; i++) {
+            final TaskRecord task = mTasks.get(i);
+            task.touchActiveTime();
+            mRecentTasks.add(task);
+        }
+
+        // Ensure that only the last number of max tasks are kept
+        assertTrimmed(mTasks.get(0), mTasks.get(1));
+    }
+
+    private ComponentName createComponent(String className) {
+        return new ComponentName(mContext.getPackageName(), className);
+    }
+
+    private TaskRecord createTask(String className) {
+        return createTask(className, TEST_USER_0_ID);
+    }
+
+    private TaskRecord createTask(String className, int userId) {
+        return createTask(className, 0 /* flags */, userId);
+    }
+
+    private TaskRecord createTask(String className, int flags, int userId) {
+        TaskRecord task = createTask(mService.mStackSupervisor, createComponent(className), flags,
+                LAST_TASK_ID++, mStack);
+        task.userId = userId;
+        task.touchActiveTime();
+        return task;
+    }
+
+    private TaskRecord createDocumentTask(String className, String affinity) {
+        TaskRecord task = createTask(className, FLAG_ACTIVITY_NEW_DOCUMENT, TEST_USER_0_ID);
+        task.affinity = affinity;
+        return task;
+    }
+
+    private boolean arrayContainsUser(int[] userIds, int targetUserId) {
+        Arrays.sort(userIds);
+        return Arrays.binarySearch(userIds, targetUserId) >= 0;
+    }
+
+    private void assertTrimmed(TaskRecord... tasks) {
+        final ArrayList<TaskRecord> trimmed = mCallbacksRecorder.trimmed;
+        final ArrayList<TaskRecord> removed = mCallbacksRecorder.removed;
+        assertTrue("Expected " + tasks.length + " trimmed tasks, got " + trimmed.size(),
+                trimmed.size() == tasks.length);
+        assertTrue("Expected " + tasks.length + " removed tasks, got " + removed.size(),
+                removed.size() == tasks.length);
+        for (TaskRecord task : tasks) {
+            assertTrue("Expected trimmed task: " + task, trimmed.contains(task));
+            assertTrue("Expected removed task: " + task, removed.contains(task));
+        }
+    }
+
+    private static class CallbacksRecorder implements Callbacks {
+        ArrayList<TaskRecord> added = new ArrayList<>();
+        ArrayList<TaskRecord> trimmed = new ArrayList<>();
+        ArrayList<TaskRecord> removed = new ArrayList<>();
+
+        void clear() {
+            added.clear();
+            trimmed.clear();
+            removed.clear();
+        }
+
+        @Override
+        public void onRecentTaskAdded(TaskRecord task) {
+            added.add(task);
+        }
+
+        @Override
+        public void onRecentTaskRemoved(TaskRecord task, boolean wasTrimmed) {
+            if (wasTrimmed) {
+                trimmed.add(task);
+            }
+            removed.add(task);
+        }
+    }
+
+    private static class TestTaskPersister extends TaskPersister {
+
+        SparseBooleanArray userTaskIdsOverride;
+        ArrayList<TaskRecord> userTasksOverride;
+
+        TestTaskPersister(File workingDir) {
+            super(workingDir);
+        }
+
+        @Override
+        SparseBooleanArray loadPersistedTaskIdsForUser(int userId) {
+            if (userTaskIdsOverride != null) {
+                return userTaskIdsOverride;
+            }
+            return super.loadPersistedTaskIdsForUser(userId);
+        }
+
+        @Override
+        List<TaskRecord> restoreTasksForUserLocked(int userId, SparseBooleanArray preaddedTasks) {
+            if (userTasksOverride != null) {
+                return userTasksOverride;
+            }
+            return super.restoreTasksForUserLocked(userId, preaddedTasks);
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
index f4c4ea9..1bb93cc 100644
--- a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
@@ -247,6 +247,26 @@
         assertEquals(7, updates.size());
     }
 
+    public void testUpdatesReceived_queueEmptyAfterStartListening() {
+        int widgetId = setupHostAndWidget();
+        int widgetId2 = bindNewWidget();
+        mService.stopListening(mPkgName, HOST_ID);
+
+        sendDummyUpdates(widgetId, 22, 23);
+        sendDummyUpdates(widgetId2, 100, 101, 102);
+
+        List<PendingHostUpdate> updates = mService.startListening(
+                mMockHost, mPkgName, HOST_ID, new int[]{widgetId, widgetId2}).getList();
+        // 3 updates for first widget and 4 for second
+        assertEquals(7, updates.size());
+
+        // Stop and start listening again
+        mService.stopListening(mPkgName, HOST_ID);
+        updates = mService.startListening(
+                mMockHost, mPkgName, HOST_ID, new int[]{widgetId, widgetId2}).getList();
+        assertTrue(updates.isEmpty());
+    }
+
     public void testGetInstalledProvidersForPackage() {
         List<AppWidgetProviderInfo> allProviders = mManager.getInstalledProviders();
         assertTrue(!allProviders.isEmpty());
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 3c64582..6bb5bc6 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -319,7 +319,8 @@
         }
 
         @Override
-        boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId) {
+        boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId,
+                int callingPid, int callingUid) {
             return mDefaultLauncherChecker.test(callingPackage, userId);
         }
 
@@ -452,6 +453,11 @@
         }
 
         @Override
+        boolean injectCheckAccessShortcutsPermission(int callingPid, int callingUid) {
+            return mInjectCheckAccessShortcutsPermission;
+        }
+
+        @Override
         void wtf(String message, Throwable th) {
             // During tests, WTF is fatal.
             fail(message + "  exception: " + th + "\n" + Log.getStackTraceString(th));
@@ -697,6 +703,8 @@
 
     protected String mInjectedBuildFingerprint = "build1";
 
+    protected boolean mInjectCheckAccessShortcutsPermission = false;
+
     static {
         QUERY_ALL.setQueryFlags(
                 ShortcutQuery.FLAG_GET_ALL_KINDS);
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 951f226..b5e8e1c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -15,6 +15,11 @@
  */
 package com.android.server.pm;
 
+import static android.content.pm.ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED;
+import static android.content.pm.ShortcutInfo.DISABLED_REASON_NOT_DISABLED;
+import static android.content.pm.ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH;
+import static android.content.pm.ShortcutInfo.DISABLED_REASON_VERSION_LOWER;
+
 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.anyOrNull;
 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.anyStringOrNull;
 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDisabled;
@@ -71,7 +76,9 @@
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.LauncherApps;
+import android.content.pm.LauncherApps.PinItemRequest;
 import android.content.pm.LauncherApps.ShortcutQuery;
+import android.content.pm.PackageInfo;
 import android.content.pm.ShortcutInfo;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.CompressFormat;
@@ -101,7 +108,6 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.function.BiConsumer;
-import java.util.function.BiPredicate;
 
 /**
  * Tests for ShortcutService and ShortcutManager.
@@ -250,7 +256,7 @@
         final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource(
                 getTestContext().getResources(), R.drawable.icon2));
         final Icon icon3 = Icon.createWithAdaptiveBitmap(BitmapFactory.decodeResource(
-            getTestContext().getResources(), R.drawable.icon2));
+                getTestContext().getResources(), R.drawable.icon2));
 
         final ShortcutInfo si1 = makeShortcut(
                 "shortcut1",
@@ -706,13 +712,13 @@
         assertBitmapSize(128, 128, bmp);
 
         Drawable dr = mLauncherApps.getShortcutIconDrawable(
-            makeShortcutWithIcon("bmp64x64", bmp64x64_maskable), 0);
+                makeShortcutWithIcon("bmp64x64", bmp64x64_maskable), 0);
         assertTrue(dr instanceof AdaptiveIconDrawable);
         float viewportPercentage = 1 / (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction());
         assertEquals((int) (bmp64x64_maskable.getBitmap().getWidth() * viewportPercentage),
-            dr.getIntrinsicWidth());
+                dr.getIntrinsicWidth());
         assertEquals((int) (bmp64x64_maskable.getBitmap().getHeight() * viewportPercentage),
-            dr.getIntrinsicHeight());
+                dr.getIntrinsicHeight());
     }
 
     public void testCleanupDanglingBitmaps() throws Exception {
@@ -1118,8 +1124,8 @@
             // Set resource icon
             assertTrue(mManager.updateShortcuts(list(
                     new ShortcutInfo.Builder(mClientContext, "s1")
-                    .setIcon(Icon.createWithResource(getTestContext(), R.drawable.black_32x32))
-                    .build()
+                            .setIcon(Icon.createWithResource(getTestContext(), R.drawable.black_32x32))
+                            .build()
             )));
 
             assertWith(getCallerShortcuts())
@@ -1131,9 +1137,9 @@
             // Set bitmap icon
             assertTrue(mManager.updateShortcuts(list(
                     new ShortcutInfo.Builder(mClientContext, "s1")
-                    .setIcon(Icon.createWithBitmap(BitmapFactory.decodeResource(
-                            getTestContext().getResources(), R.drawable.black_64x64)))
-                    .build()
+                            .setIcon(Icon.createWithBitmap(BitmapFactory.decodeResource(
+                                    getTestContext().getResources(), R.drawable.black_64x64)))
+                            .build()
             )));
 
             assertWith(getCallerShortcuts())
@@ -1669,6 +1675,10 @@
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
 
+            mManager.updateShortcuts(list(
+                    new ShortcutInfo.Builder(mClientContext, "s2").setDisabledMessage("xyz")
+                            .build()));
+
             mManager.disableShortcuts(list("s2"));
 
             assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
@@ -1704,6 +1714,10 @@
             assertWith(mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
                     /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))
                     .haveIds("s2")
+                    .areAllWithDisabledReason(ShortcutInfo.DISABLED_REASON_BY_APP)
+                    .forAllShortcuts(si -> {
+                        assertEquals("xyz", si.getDisabledMessage());
+                    })
                     .areAllPinned()
                     .areAllNotWithKeyFieldsOnly()
                     .areAllDisabled();
@@ -1888,7 +1902,7 @@
                     "s1", "s2");
         });
 
-        dumpsysOnLogcat();
+        dumpsysOnLogcat("Before launcher 2");
 
         runWithCaller(LAUNCHER_2, USER_0, () -> {
             // Launcher2 still has no pinned ones.
@@ -1901,6 +1915,27 @@
                     /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))
                     /* none */);
 
+            // Make sure FLAG_MATCH_ALL_PINNED will be ignored.
+            assertWith(mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_MATCH_PINNED
+                            | ShortcutQuery.FLAG_MATCH_ALL_PINNED), getCallingUser()))
+                    .isEmpty();
+
+            // Make sure the special permission works.
+            mInjectCheckAccessShortcutsPermission = true;
+
+            dumpsysOnLogcat("All-pinned");
+
+            assertWith(mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_MATCH_PINNED
+                            | ShortcutQuery.FLAG_MATCH_ALL_PINNED), getCallingUser()))
+                    .haveIds("s1", "s2");
+            assertWith(mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_MATCH_PINNED), getCallingUser()))
+                    .isEmpty();
+
+            mInjectCheckAccessShortcutsPermission = false;
+
             assertShortcutIds(assertAllDynamic(
                     mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
                     /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
@@ -2126,7 +2161,7 @@
 
             final ShortcutQuery q = new ShortcutQuery().setQueryFlags(
                     ShortcutQuery.FLAG_MATCH_DYNAMIC | ShortcutQuery.FLAG_MATCH_PINNED
-                    | ShortcutQuery.FLAG_MATCH_MANIFEST);
+                            | ShortcutQuery.FLAG_MATCH_MANIFEST);
 
             // No shortcuts are visible.
             assertWith(mLauncherApps.getShortcuts(q, HANDLE_USER_0)).isEmpty();
@@ -2668,10 +2703,10 @@
                     "Title 1",
                     makeComponent(ShortcutActivity.class),
                     /* icon =*/ null,
-                    new Intent[] {makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
+                    new Intent[]{makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
                             "key1", "val1", "nest", makeBundle("key", 123))
                             .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK),
-                    new Intent("act2").setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)},
+                            new Intent("act2").setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)},
                     /* rank */ 10);
 
             final ShortcutInfo s1_2 = makeShortcut(
@@ -2776,8 +2811,8 @@
             // Not launchable.
             doReturn(ActivityManager.START_CLASS_NOT_FOUND)
                     .when(mMockActivityManagerInternal).startActivitiesAsPackage(
-                            anyStringOrNull(), anyInt(),
-                            anyOrNull(Intent[].class), anyOrNull(Bundle.class));
+                    anyStringOrNull(), anyInt(),
+                    anyOrNull(Intent[].class), anyOrNull(Bundle.class));
             assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_0,
                     ActivityNotFoundException.class);
 
@@ -2911,7 +2946,7 @@
                     .revertToOriginalList()
                     .selectByIds("s1", "s2")
                     .areAllDynamic()
-                    ;
+            ;
         });
 
         // 3 Update the app with no manifest shortcuts.  (Pinned one will survive.)
@@ -3309,13 +3344,13 @@
         });
 
 
-        final SparseArray<ShortcutUser> users =  mService.getShortcutsForTest();
+        final SparseArray<ShortcutUser> users = mService.getShortcutsForTest();
         assertEquals(2, users.size());
         assertEquals(USER_0, users.keyAt(0));
         assertEquals(USER_10, users.keyAt(1));
 
-        final ShortcutUser user0 =  users.get(USER_0);
-        final ShortcutUser user10 =  users.get(USER_10);
+        final ShortcutUser user0 = users.get(USER_0);
+        final ShortcutUser user10 = users.get(USER_10);
 
 
         // Check the registered packages.
@@ -3531,7 +3566,7 @@
                 new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
                 R.xml.shortcut_2);
         updatePackageVersion(CALLING_PACKAGE_1, 1);
-                mService.mPackageMonitor.onReceive(getTestContext(),
+        mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
 
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -3548,7 +3583,7 @@
                 new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
                 R.xml.shortcut_1);
         updatePackageVersion(CALLING_PACKAGE_1, 1);
-                mService.mPackageMonitor.onReceive(getTestContext(),
+        mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
 
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -3853,52 +3888,77 @@
         assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
     }
 
-    protected void checkCanRestoreTo(boolean expected, ShortcutPackageInfo spi,
-            int version, String... signatures) {
-        assertEquals(expected, spi.canRestoreTo(mService, genPackage(
-                "dummy", /* uid */ 0, version, signatures)));
+    protected void checkCanRestoreTo(int expected, ShortcutPackageInfo spi,
+            boolean anyVersionOk, int version, boolean nowBackupAllowed, String... signatures) {
+        final PackageInfo pi = genPackage("dummy", /* uid */ 0, version, signatures);
+        if (!nowBackupAllowed) {
+            pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP;
+        }
+        assertEquals(expected, spi.canRestoreTo(mService, pi, anyVersionOk));
     }
 
     public void testCanRestoreTo() {
         addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "sig1");
-        addPackage(CALLING_PACKAGE_2, CALLING_UID_1, 10, "sig1", "sig2");
+        addPackage(CALLING_PACKAGE_2, CALLING_UID_2, 10, "sig1", "sig2");
+        addPackage(CALLING_PACKAGE_3, CALLING_UID_3, 10, "sig1");
+
+        updatePackageInfo(CALLING_PACKAGE_3,
+                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
 
         final ShortcutPackageInfo spi1 = ShortcutPackageInfo.generateForInstalledPackageForTest(
                 mService, CALLING_PACKAGE_1, USER_0);
         final ShortcutPackageInfo spi2 = ShortcutPackageInfo.generateForInstalledPackageForTest(
                 mService, CALLING_PACKAGE_2, USER_0);
+        final ShortcutPackageInfo spi3 = ShortcutPackageInfo.generateForInstalledPackageForTest(
+                mService, CALLING_PACKAGE_3, USER_0);
 
-        checkCanRestoreTo(true, spi1, 10, "sig1");
-        checkCanRestoreTo(true, spi1, 10, "x", "sig1");
-        checkCanRestoreTo(true, spi1, 10, "sig1", "y");
-        checkCanRestoreTo(true, spi1, 10, "x", "sig1", "y");
-        checkCanRestoreTo(true, spi1, 11, "sig1");
+        checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi1, false, 10, true, "sig1");
+        checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi1, false, 10, true, "x", "sig1");
+        checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi1, false, 10, true, "sig1", "y");
+        checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi1, false, 10, true, "x", "sig1", "y");
+        checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi1, false, 11, true, "sig1");
 
-        checkCanRestoreTo(false, spi1, 10 /* empty */);
-        checkCanRestoreTo(false, spi1, 10, "x");
-        checkCanRestoreTo(false, spi1, 10, "x", "y");
-        checkCanRestoreTo(false, spi1, 10, "x");
-        checkCanRestoreTo(false, spi1, 9, "sig1");
+        checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, spi1, false, 10, true/* empty */);
+        checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, spi1, false, 10, true, "x");
+        checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, spi1, false, 10, true, "x", "y");
+        checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH, spi1, false, 10, true, "x");
+        checkCanRestoreTo(DISABLED_REASON_VERSION_LOWER, spi1, false, 9, true, "sig1");
 
-        checkCanRestoreTo(true, spi2, 10, "sig1", "sig2");
-        checkCanRestoreTo(true, spi2, 10, "sig2", "sig1");
-        checkCanRestoreTo(true, spi2, 10, "x", "sig1", "sig2");
-        checkCanRestoreTo(true, spi2, 10, "x", "sig2", "sig1");
-        checkCanRestoreTo(true, spi2, 10, "sig1", "sig2", "y");
-        checkCanRestoreTo(true, spi2, 10, "sig2", "sig1", "y");
-        checkCanRestoreTo(true, spi2, 10, "x", "sig1", "sig2", "y");
-        checkCanRestoreTo(true, spi2, 10, "x", "sig2", "sig1", "y");
-        checkCanRestoreTo(true, spi2, 11, "x", "sig2", "sig1", "y");
+        // Any version okay.
+        checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi1, true, 9, true, "sig1");
+        checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi1, true, 9, true, "sig1");
 
-        checkCanRestoreTo(false, spi2, 10, "sig1", "sig2x");
-        checkCanRestoreTo(false, spi2, 10, "sig2", "sig1x");
-        checkCanRestoreTo(false, spi2, 10, "x", "sig1x", "sig2");
-        checkCanRestoreTo(false, spi2, 10, "x", "sig2x", "sig1");
-        checkCanRestoreTo(false, spi2, 10, "sig1", "sig2x", "y");
-        checkCanRestoreTo(false, spi2, 10, "sig2", "sig1x", "y");
-        checkCanRestoreTo(false, spi2, 10, "x", "sig1x", "sig2", "y");
-        checkCanRestoreTo(false, spi2, 10, "x", "sig2x", "sig1", "y");
-        checkCanRestoreTo(false, spi2, 11, "x", "sig2x", "sig1", "y");
+        checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi2, false, 10, true, "sig1", "sig2");
+        checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi2, false, 10, true, "sig2", "sig1");
+        checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi2, false, 10, true, "x", "sig1", "sig2");
+        checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi2, false, 10, true, "x", "sig2", "sig1");
+        checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi2, false, 10, true, "sig1", "sig2", "y");
+        checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi2, false, 10, true, "sig2", "sig1", "y");
+        checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi2, false, 10, true, "x", "sig1", "sig2", "y");
+        checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi2, false, 10, true, "x", "sig2", "sig1", "y");
+        checkCanRestoreTo(DISABLED_REASON_NOT_DISABLED, spi2, false, 11, true, "x", "sig2", "sig1", "y");
+
+        checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH,
+                spi2, false, 10, true, "sig1", "sig2x");
+        checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH,
+                spi2, false, 10, true, "sig2", "sig1x");
+        checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH,
+                spi2, false, 10, true, "x", "sig1x", "sig2");
+        checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH,
+                spi2, false, 10, true, "x", "sig2x", "sig1");
+        checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH,
+                spi2, false, 10, true, "sig1", "sig2x", "y");
+        checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH,
+                spi2, false, 10, true, "sig2", "sig1x", "y");
+        checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH,
+                spi2, false, 10, true, "x", "sig1x", "sig2", "y");
+        checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH,
+                spi2, false, 10, true, "x", "sig2x", "sig1", "y");
+        checkCanRestoreTo(DISABLED_REASON_SIGNATURE_MISMATCH,
+                spi2, false, 11, true, "x", "sig2x", "sig1", "y");
+
+        checkCanRestoreTo(DISABLED_REASON_BACKUP_NOT_SUPPORTED, spi1, true, 10, false, "sig1");
+        checkCanRestoreTo(DISABLED_REASON_BACKUP_NOT_SUPPORTED, spi3, true, 10, true, "sig1");
     }
 
     public void testHandlePackageDelete() {
@@ -3929,7 +3989,7 @@
                 new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
                 R.xml.shortcut_1);
         updatePackageVersion(CALLING_PACKAGE_1, 1);
-                mService.mPackageMonitor.onReceive(getTestContext(),
+        mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertWith(getCallerShortcuts())
@@ -4080,7 +4140,7 @@
         assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
         assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
 
-                mService.mPackageMonitor.onReceive(getTestContext(),
+        mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageDataClear(CALLING_PACKAGE_1, USER_0));
 
         assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
@@ -4099,7 +4159,7 @@
 
         mRunningUsers.put(USER_10, true);
 
-                mService.mPackageMonitor.onReceive(getTestContext(),
+        mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageDataClear(CALLING_PACKAGE_2, USER_10));
 
         assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
@@ -4126,7 +4186,7 @@
                 new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
                 R.xml.shortcut_2);
         updatePackageVersion(CALLING_PACKAGE_1, 1);
-                mService.mPackageMonitor.onReceive(getTestContext(),
+        mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageAddIntent(CALLING_PACKAGE_1, USER_10));
 
         runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
@@ -4389,7 +4449,7 @@
 
         // Update the package.
         updatePackageVersion(CALLING_PACKAGE_1, 1);
-                mService.mPackageMonitor.onReceive(getTestContext(),
+        mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0));
 
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -4524,7 +4584,7 @@
         mRunningUsers.put(USER_10, true);
 
         updatePackageVersion(CALLING_PACKAGE_1, 1);
-                mService.mPackageMonitor.onReceive(getTestContext(),
+        mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageAddIntent(CALLING_PACKAGE_1, USER_10));
 
         runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
@@ -4552,11 +4612,11 @@
                     .revertToOriginalList()
                     .selectByIds("ms1-alt", "s2")
                     .areAllWithActivity(ACTIVITY2)
-                    ;
+            ;
         });
 
         // First, no changes.
-                mService.mPackageMonitor.onReceive(getTestContext(),
+        mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageChangedIntent(CALLING_PACKAGE_1, USER_10));
 
         runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
@@ -4579,7 +4639,7 @@
 
         // Disable activity 1
         mEnabledActivityChecker = (activity, userId) -> !ACTIVITY1.equals(activity);
-                mService.mPackageMonitor.onReceive(getTestContext(),
+        mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageChangedIntent(CALLING_PACKAGE_1, USER_10));
 
         runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
@@ -4599,7 +4659,7 @@
         // Re-enable activity 1.
         // Manifest shortcuts will be re-published, but dynamic ones are not.
         mEnabledActivityChecker = (activity, userId) -> true;
-                mService.mPackageMonitor.onReceive(getTestContext(),
+        mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageChangedIntent(CALLING_PACKAGE_1, USER_10));
 
         runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
@@ -4617,13 +4677,13 @@
                     .revertToOriginalList()
                     .selectByIds("ms1-alt", "s2")
                     .areAllWithActivity(ACTIVITY2)
-                    ;
+            ;
         });
 
         // Disable activity 2
         // Because "ms1-alt" and "s2" are both pinned, they will remain, but disabled.
         mEnabledActivityChecker = (activity, userId) -> !ACTIVITY2.equals(activity);
-                mService.mPackageMonitor.onReceive(getTestContext(),
+        mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageChangedIntent(CALLING_PACKAGE_1, USER_10));
 
         runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
@@ -4686,7 +4746,7 @@
         setCaller(LAUNCHER_1, USER_0);
         assertForLauncherCallback(mLauncherApps, () -> {
             updatePackageVersion(CALLING_PACKAGE_1, 1);
-                    mService.mPackageMonitor.onReceive(getTestContext(),
+            mService.mPackageMonitor.onReceive(getTestContext(),
                     genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0));
         }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
                 // Make sure the launcher gets callbacks.
@@ -4708,12 +4768,11 @@
                     .areAllNotDynamic()
                     .areAllDisabled()
                     .areAllPinned()
-                    ;
+            ;
         });
     }
 
     protected void prepareForBackupTest() {
-
         prepareCrossProfileDataSet();
 
         backupAndRestore();
@@ -4749,66 +4808,45 @@
         assertFileExistsWithContent("user-0/shortcut_dump/restore-4.txt");
         assertFileExistsWithContent("user-0/shortcut_dump/restore-5-finish.txt");
 
-        checkBackupAndRestore_success();
+        checkBackupAndRestore_success(/*firstRestore=*/ true);
     }
 
     public void testBackupAndRestore_backupRestoreTwice() {
         prepareForBackupTest();
 
-        // Note doing a backup & restore again here shouldn't affect the result.
-        dumpsysOnLogcat("Before second backup");
+        checkBackupAndRestore_success(/*firstRestore=*/ true);
+
+        // Run a backup&restore again. Note the shortcuts that weren't restored in the previous
+        // restore are disabled, so they won't be restored again.
+        dumpsysOnLogcat("Before second backup&restore");
 
         backupAndRestore();
 
-        dumpsysOnLogcat("After second backup");
+        dumpsysOnLogcat("After second backup&restore");
 
-        checkBackupAndRestore_success();
-    }
-
-    public void testBackupAndRestore_backupRestoreMultiple() {
-        prepareForBackupTest();
-
-        // Note doing a backup & restore again here shouldn't affect the result.
-        backupAndRestore();
-
-        // This also shouldn't affect the result.
-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
-            assertTrue(mManager.setDynamicShortcuts(list(
-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
-                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
-        });
-
-        backupAndRestore();
-
-        checkBackupAndRestore_success();
+        checkBackupAndRestore_success(/*firstRestore=*/ false);
     }
 
     public void testBackupAndRestore_restoreToNewVersion() {
         prepareForBackupTest();
 
-        // Note doing a backup & restore again here shouldn't affect the result.
-        backupAndRestore();
-
         addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 2);
         addPackage(LAUNCHER_1, LAUNCHER_UID_1, 5);
 
-        checkBackupAndRestore_success();
+        checkBackupAndRestore_success(/*firstRestore=*/ true);
     }
 
     public void testBackupAndRestore_restoreToSuperSetSignatures() {
         prepareForBackupTest();
 
-        // Note doing a backup & restore again here shouldn't affect the result.
-        backupAndRestore();
-
         // Change package signatures.
         addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 1, "sigx", CALLING_PACKAGE_1);
         addPackage(LAUNCHER_1, LAUNCHER_UID_1, 4, LAUNCHER_1, "sigy");
 
-        checkBackupAndRestore_success();
+        checkBackupAndRestore_success(/*firstRestore=*/ true);
     }
 
-    protected void checkBackupAndRestore_success() {
+    protected void checkBackupAndRestore_success(boolean firstRestore) {
         // Make sure non-system user is not restored.
         final ShortcutUser userP0 = mService.getUserShortcutsLocked(USER_P0);
         assertEquals(0, userP0.getAllPackagesForTest().size());
@@ -4818,12 +4856,13 @@
         final ShortcutUser user0 = mService.getUserShortcutsLocked(USER_0);
         assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_1));
         assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_2));
+
+        assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_3));
         assertExistsAndShadow(user0.getAllLaunchersForTest().get(
                 PackageWithUser.of(USER_0, LAUNCHER_1)));
         assertExistsAndShadow(user0.getAllLaunchersForTest().get(
                 PackageWithUser.of(USER_0, LAUNCHER_2)));
 
-        assertNull(user0.getAllPackagesForTest().get(CALLING_PACKAGE_3));
         assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_3)));
         assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_P0, LAUNCHER_1)));
 
@@ -4835,14 +4874,16 @@
 
                     .revertToOriginalList()
                     .selectPinned()
-                    .haveIds("s1", "s2");
+                    .haveIds("s1", "s2")
+                    .areAllEnabled();
         });
 
         installPackage(USER_0, LAUNCHER_1);
         runWithCaller(LAUNCHER_1, USER_0, () -> {
             assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
                     .areAllPinned()
-                    .haveIds("s1");
+                    .haveIds("s1")
+                    .areAllEnabled();
 
             assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
                     .isEmpty();
@@ -4862,17 +4903,20 @@
 
                     .revertToOriginalList()
                     .selectPinned()
-                    .haveIds("s1", "s2", "s3");
+                    .haveIds("s1", "s2", "s3")
+                    .areAllEnabled();
         });
 
         runWithCaller(LAUNCHER_1, USER_0, () -> {
             assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
                     .areAllPinned()
-                    .haveIds("s1");
+                    .haveIds("s1")
+                    .areAllEnabled();
 
             assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
                     .areAllPinned()
-                    .haveIds("s1", "s2");
+                    .haveIds("s1", "s2")
+                    .areAllEnabled();
 
             assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
                     .isEmpty();
@@ -4910,14 +4954,28 @@
         runWithCaller(LAUNCHER_2, USER_0, () -> {
             assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
                     .areAllPinned()
-                    .haveIds("s2");
+                    .haveIds("s2")
+                    .areAllEnabled();
 
             assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
                     .areAllPinned()
-                    .haveIds("s2", "s3");
+                    .haveIds("s2", "s3")
+                    .areAllEnabled();
 
-            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
-                    .isEmpty();
+            if (firstRestore) {
+                assertWith(
+                        mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                        .haveIds("s2", "s3", "s4")
+                        .areAllDisabled()
+                        .areAllPinned()
+                        .areAllNotDynamic()
+                        .areAllWithDisabledReason(
+                                ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED);
+            } else {
+                assertWith(
+                        mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                        .isEmpty();
+            }
 
             assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0))
                     .isEmpty();
@@ -4937,14 +4995,27 @@
         runWithCaller(LAUNCHER_1, USER_0, () -> {
             assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
                     .areAllPinned()
-                    .haveIds("s1");
+                    .haveIds("s1")
+                    .areAllEnabled();
 
             assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
                     .areAllPinned()
-                    .haveIds("s1", "s2");
+                    .haveIds("s1", "s2")
+                    .areAllEnabled();
 
-            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
-                    .isEmpty();
+            if (firstRestore) {
+                assertWith(
+                        mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                        .haveIds("s1", "s2", "s3")
+                        .areAllDisabled()
+                        .areAllPinned()
+                        .areAllNotDynamic()
+                        .areAllWithDisabledReason(ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED);
+            } else {
+                assertWith(
+                        mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                        .isEmpty();
+            }
 
             assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0))
                     .isEmpty();
@@ -4954,45 +5025,39 @@
         runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
             assertWith(getCallerVisibleShortcuts())
                     .areAllPinned()
-                    .haveIds("s1", "s2", "s3");
+                    .haveIds("s1", "s2", "s3")
+                    .areAllEnabled();
         });
     }
 
     public void testBackupAndRestore_publisherLowerVersion() {
         prepareForBackupTest();
 
-        // Note doing a backup & restore again here shouldn't affect the result.
-        backupAndRestore();
-
         addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 0); // Lower version
 
-        checkBackupAndRestore_publisherNotRestored();
+        checkBackupAndRestore_publisherNotRestored(ShortcutInfo.DISABLED_REASON_VERSION_LOWER);
     }
 
     public void testBackupAndRestore_publisherWrongSignature() {
         prepareForBackupTest();
 
-        // Note doing a backup & restore again here shouldn't affect the result.
-        backupAndRestore();
-
         addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "sigx"); // different signature
 
-        checkBackupAndRestore_publisherNotRestored();
+        checkBackupAndRestore_publisherNotRestored(ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH);
     }
 
     public void testBackupAndRestore_publisherNoLongerBackupTarget() {
         prepareForBackupTest();
 
-        // Note doing a backup & restore again here shouldn't affect the result.
-        backupAndRestore();
-
         updatePackageInfo(CALLING_PACKAGE_1,
                 pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
 
-        checkBackupAndRestore_publisherNotRestored();
+        checkBackupAndRestore_publisherNotRestored(
+                ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED);
     }
 
-    protected void checkBackupAndRestore_publisherNotRestored() {
+    protected void checkBackupAndRestore_publisherNotRestored(
+            int package1DisabledReason) {
         installPackage(USER_0, CALLING_PACKAGE_1);
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertEquals(0, mManager.getDynamicShortcuts().size());
@@ -5014,27 +5079,53 @@
 
         installPackage(USER_0, LAUNCHER_1);
         runWithCaller(LAUNCHER_1, USER_0, () -> {
-            assertShortcutIds(assertAllPinned(
-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
-                    /* empty */);
-            assertShortcutIds(assertAllPinned(
-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
-                    "s1", "s2");
-            assertShortcutIds(assertAllPinned(
-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
-                    /* empty */);
+            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    .haveIds("s1")
+                    .areAllPinned()
+                    .areAllDisabled()
+                    .areAllWithDisabledReason(package1DisabledReason)
+                    .forAllShortcuts(si -> {
+                        switch (package1DisabledReason) {
+                            case ShortcutInfo.DISABLED_REASON_VERSION_LOWER:
+                                assertEquals("This shortcut requires latest app",
+                                        si.getDisabledMessage());
+                                break;
+                            case ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH:
+                                assertEquals(
+                                        "Couldn\u2019t restore shortcut because of app"
+                                        + " signature mismatch",
+                                        si.getDisabledMessage());
+                                break;
+                            case ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED:
+                                assertEquals(
+                                        "Couldn\u2019t restore shortcut because app"
+                                        + " doesn\u2019t support backup and restore",
+                                        si.getDisabledMessage());
+                                break;
+                            default:
+                                fail("Unhandled disabled reason: " + package1DisabledReason);
+                        }
+                    });
+            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+                    .haveIds("s1", "s2")
+                    .areAllPinned()
+                    .areAllEnabled();
+            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    .isEmpty();
         });
         installPackage(USER_0, LAUNCHER_2);
         runWithCaller(LAUNCHER_2, USER_0, () -> {
-            assertShortcutIds(assertAllPinned(
-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
-                    /* empty */);
-            assertShortcutIds(assertAllPinned(
-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
-                    "s2", "s3");
-            assertShortcutIds(assertAllPinned(
-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
-                    /* empty */);
+            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    .haveIds("s2")
+                    .areAllPinned()
+                    .areAllDisabled()
+                    .areAllWithDisabledReason(package1DisabledReason);
+            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+                    .haveIds("s2", "s3")
+                    .areAllPinned()
+                    .areAllEnabled();
+            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    .isEmpty();
         });
 
         installPackage(USER_0, CALLING_PACKAGE_3);
@@ -5044,46 +5135,51 @@
         });
 
         runWithCaller(LAUNCHER_1, USER_0, () -> {
-            assertShortcutIds(assertAllPinned(
-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
-                    /* empty */);
-            assertShortcutIds(assertAllPinned(
-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
-                    "s1", "s2");
-            assertShortcutIds(assertAllPinned(
-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
-                    /* empty */);
+            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    .haveIds("s1")
+                    .areAllPinned()
+                    .areAllDisabled()
+                    .areAllWithDisabledReason(package1DisabledReason);
+            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+                    .haveIds("s1", "s2")
+                    .areAllPinned()
+                    .areAllEnabled();
+            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    .haveIds("s1", "s2", "s3")
+                    .areAllPinned()
+                    .areAllDisabled()
+                    .areAllWithDisabledReason(ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED);
         });
         runWithCaller(LAUNCHER_2, USER_0, () -> {
-            assertShortcutIds(assertAllPinned(
-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
-                    /* empty */);
-            assertShortcutIds(assertAllPinned(
-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
-                    "s2", "s3");
-            assertShortcutIds(assertAllPinned(
-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
-                    /* empty */);
+            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    .haveIds("s2")
+                    .areAllPinned()
+                    .areAllDisabled()
+                    .areAllWithDisabledReason(package1DisabledReason);
+            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+                    .haveIds("s2", "s3")
+                    .areAllPinned()
+                    .areAllEnabled();
+            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    .haveIds("s2", "s3", "s4")
+                    .areAllPinned()
+                    .areAllDisabled()
+                    .areAllWithDisabledReason(ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED);
         });
     }
 
     public void testBackupAndRestore_launcherLowerVersion() {
         prepareForBackupTest();
 
-        // Note doing a backup & restore again here shouldn't affect the result.
-        backupAndRestore();
-
         addPackage(LAUNCHER_1, LAUNCHER_UID_1, 0); // Lower version
 
-        checkBackupAndRestore_launcherNotRestored();
+        // Note, we restore pinned shortcuts even if the launcher is of a lower version.
+        checkBackupAndRestore_success(/*firstRestore=*/ true);
     }
 
     public void testBackupAndRestore_launcherWrongSignature() {
         prepareForBackupTest();
 
-        // Note doing a backup & restore again here shouldn't affect the result.
-        backupAndRestore();
-
         addPackage(LAUNCHER_1, LAUNCHER_UID_1, 10, "sigx"); // different signature
 
         checkBackupAndRestore_launcherNotRestored();
@@ -5092,9 +5188,6 @@
     public void testBackupAndRestore_launcherNoLongerBackupTarget() {
         prepareForBackupTest();
 
-        // Note doing a backup & restore again here shouldn't affect the result.
-        backupAndRestore();
-
         updatePackageInfo(LAUNCHER_1,
                 pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
 
@@ -5185,18 +5278,12 @@
             assertShortcutIds(assertAllPinned(
                     mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
                     "s2", "s3");
-            assertShortcutIds(assertAllPinned(
-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
-                    /* empty */);
         });
     }
 
     public void testBackupAndRestore_launcherAndPackageNoLongerBackupTarget() {
         prepareForBackupTest();
 
-        // Note doing a backup & restore again here shouldn't affect the result.
-        backupAndRestore();
-
         updatePackageInfo(CALLING_PACKAGE_1,
                 pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
 
@@ -5235,15 +5322,15 @@
         });
         installPackage(USER_0, LAUNCHER_2);
         runWithCaller(LAUNCHER_2, USER_0, () -> {
-            assertShortcutIds(assertAllPinned(
-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
-                    /* empty */);
-            assertShortcutIds(assertAllPinned(
-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
-                    "s2", "s3");
-            assertShortcutIds(assertAllPinned(
-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
-                    /* empty */);
+            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    .areAllPinned()
+                    .haveIds("s2")
+                    .areAllDisabled();
+            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+                    .areAllPinned()
+                    .haveIds("s2", "s3");
+            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    .isEmpty();
         });
 
         // Because launcher 1 wasn't restored, "s1" is no longer pinned.
@@ -5272,15 +5359,21 @@
                     /* empty */);
         });
         runWithCaller(LAUNCHER_2, USER_0, () -> {
-            assertShortcutIds(assertAllPinned(
-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
-                    /* empty */);
-            assertShortcutIds(assertAllPinned(
-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
-                    "s2", "s3");
-            assertShortcutIds(assertAllPinned(
+            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    .areAllPinned()
+                    .haveIds("s2")
+                    .areAllDisabled();
+            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+                    .areAllPinned()
+                    .haveIds("s2", "s3");
+            assertWith(
                     mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
-                    /* empty */);
+                    .haveIds("s2", "s3", "s4")
+                    .areAllDisabled()
+                    .areAllPinned()
+                    .areAllNotDynamic()
+                    .areAllWithDisabledReason(
+                            ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED);
         });
     }
 
@@ -5305,12 +5398,12 @@
         final ShortcutUser user0 = mService.getUserShortcutsLocked(USER_0);
         assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_1));
         assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_2));
+        assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_3));
         assertExistsAndShadow(user0.getAllLaunchersForTest().get(
                 PackageWithUser.of(USER_0, LAUNCHER_1)));
         assertExistsAndShadow(user0.getAllLaunchersForTest().get(
                 PackageWithUser.of(USER_0, LAUNCHER_2)));
 
-        assertNull(user0.getAllPackagesForTest().get(CALLING_PACKAGE_3));
         assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_3)));
         assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_P0, LAUNCHER_1)));
 
@@ -5421,7 +5514,7 @@
                     .revertToOriginalList()
                     .selectByIds("s1", "s2")
                     .areAllNotDynamic()
-                    ;
+            ;
         });
     }
 
@@ -5555,6 +5648,287 @@
         });
     }
 
+
+    /**
+     * Restored to a lower version with no manifest shortcuts. All shortcuts are now invisible,
+     * and all calls from the publisher should ignore them.
+     */
+    public void testBackupAndRestore_disabledShortcutsAreIgnored() {
+        // Publish two manifest shortcuts.
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_5_altalt);
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        mService.mPackageMonitor.onReceive(mServiceContext,
+                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcutWithShortLabel("s1", "original-title"),
+                    makeShortcut("s2"), makeShortcut("s3"))));
+        });
+
+        // Pin from launcher 1.
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("ms1", "ms2", "ms3", "ms4", "s1", "s2"), HANDLE_USER_0);
+        });
+
+        backupAndRestore();
+
+        // Lower the version and remove the manifest shortcuts.
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_0);
+        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 0); // Lower version
+
+        // When re-installing the app, the manifest shortcut should be re-published.
+        mService.mPackageMonitor.onReceive(mServiceContext,
+                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+        mService.mPackageMonitor.onReceive(mServiceContext,
+                genPackageAddIntent(LAUNCHER_1, USER_0));
+
+        // No shortcuts should be visible to the publisher.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertWith(getCallerVisibleShortcuts())
+                    .isEmpty();
+        });
+
+        final Runnable checkAllDisabledForLauncher = () -> {
+            runWithCaller(LAUNCHER_1, USER_0, () -> {
+                assertWith(getShortcutAsLauncher(USER_0))
+                        .areAllPinned()
+                        .haveIds("ms1", "ms2", "ms3", "ms4", "s1", "s2")
+                        .areAllDisabled()
+                        .areAllWithDisabledReason(ShortcutInfo.DISABLED_REASON_VERSION_LOWER)
+
+                        .forShortcutWithId("s1", si -> {
+                            assertEquals("original-title", si.getShortLabel());
+                        })
+                        .forShortcutWithId("ms1", si -> {
+                            assertEquals("string-com.android.test.1-user:0-res:"
+                                            + R.string.shortcut_title1 + "/en"
+                                    , si.getShortLabel());
+                        })
+                        .forShortcutWithId("ms2", si -> {
+                            assertEquals("string-com.android.test.1-user:0-res:"
+                                            + R.string.shortcut_title2 + "/en"
+                                    , si.getShortLabel());
+                        })
+                        .forShortcutWithId("ms3", si -> {
+                            assertEquals("string-com.android.test.1-user:0-res:"
+                                            + R.string.shortcut_title1 + "/en"
+                                    , si.getShortLabel());
+                            assertEquals("string-com.android.test.1-user:0-res:"
+                                            + R.string.shortcut_title2 + "/en"
+                                    , si.getLongLabel());
+                        })
+                        .forShortcutWithId("ms4", si -> {
+                            assertEquals("string-com.android.test.1-user:0-res:"
+                                            + R.string.shortcut_title2 + "/en"
+                                    , si.getShortLabel());
+                            assertEquals("string-com.android.test.1-user:0-res:"
+                                            + R.string.shortcut_title2 + "/en"
+                                    , si.getLongLabel());
+                        });
+            });
+        };
+
+        checkAllDisabledForLauncher.run();
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+
+            makeCallerForeground(); // CALLING_PACKAGE_1 is now in the foreground.
+
+            // All changing API calls should be ignored.
+
+            getManager().enableShortcuts(list("ms1", "ms2", "ms3", "ms4", "s1", "s2"));
+            checkAllDisabledForLauncher.run();
+
+            getManager().enableShortcuts(list("ms1", "ms2", "ms3", "ms4", "s1", "s2"));
+            checkAllDisabledForLauncher.run();
+
+            getManager().enableShortcuts(list("ms1", "ms2", "ms3", "ms4", "s1", "s2"));
+            checkAllDisabledForLauncher.run();
+
+            getManager().removeAllDynamicShortcuts();
+            getManager().removeDynamicShortcuts(list("ms1", "ms2", "ms3", "ms4", "s1", "s2"));
+            checkAllDisabledForLauncher.run();
+
+            getManager().updateShortcuts(list(makeShortcutWithShortLabel("s1", "new-title")));
+            checkAllDisabledForLauncher.run();
+
+
+            // Add a shortcut -- even though ms1 was immutable, it will succeed.
+            assertTrue(getManager().addDynamicShortcuts(list(
+                    makeShortcutWithShortLabel("ms1", "original-title"))));
+
+            runWithCaller(LAUNCHER_1, USER_0, () -> {
+                assertWith(getShortcutAsLauncher(USER_0))
+                        .haveIds("ms1", "ms2", "ms3", "ms4", "s1", "s2")
+
+                        .selectByIds("ms1")
+                        .areAllEnabled()
+                        .areAllDynamic()
+                        .areAllPinned()
+                        .forAllShortcuts(si -> {
+                            assertEquals("original-title", si.getShortLabel());
+                        })
+
+                        // The rest still exist and disabled.
+                        .revertToOriginalList()
+                        .selectByIds("ms2", "ms3", "ms4", "s1", "s2")
+                        .areAllDisabled()
+                        .areAllPinned()
+                ;
+            });
+
+            assertTrue(getManager().setDynamicShortcuts(list(
+                    makeShortcutWithShortLabel("ms2", "new-title-2"))));
+
+            runWithCaller(LAUNCHER_1, USER_0, () -> {
+                assertWith(getShortcutAsLauncher(USER_0))
+                        .haveIds("ms1", "ms2", "ms3", "ms4", "s1", "s2")
+
+                        .selectByIds("ms1")
+                        .areAllEnabled()
+                        .areAllNotDynamic() // ms1 was not in the list, so no longer dynamic.
+                        .areAllPinned()
+                        .areAllMutable()
+                        .forAllShortcuts(si -> {
+                            assertEquals("original-title", si.getShortLabel());
+                        })
+
+                        .revertToOriginalList()
+                        .selectByIds("ms2")
+                        .areAllEnabled()
+                        .areAllDynamic()
+                        .areAllPinned()
+                        .areAllMutable()
+                        .forAllShortcuts(si -> {
+                            assertEquals("new-title-2", si.getShortLabel());
+                        })
+
+                        // The rest still exist and disabled.
+                        .revertToOriginalList()
+                        .selectByIds("ms3", "ms4", "s1", "s2")
+                        .areAllDisabled()
+                        .areAllPinned()
+                ;
+            });
+
+            // Prepare for requestPinShortcut().
+            setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+            mPinConfirmActivityFetcher = (packageName, userId) ->
+                    new ComponentName(packageName, PIN_CONFIRM_ACTIVITY_CLASS);
+
+            mManager.requestPinShortcut(
+                    makeShortcutWithShortLabel("ms3", "new-title-3"),
+                    /*PendingIntent=*/ null);
+
+            // Note this was pinned, so it'll be accepted right away.
+            runWithCaller(LAUNCHER_1, USER_0, () -> {
+                assertWith(getShortcutAsLauncher(USER_0))
+                        .selectByIds("ms3")
+                        .areAllEnabled()
+                        .areAllNotDynamic()
+                        .areAllPinned()
+                        .areAllMutable()
+                        .forAllShortcuts(si -> {
+                            assertEquals("new-title-3", si.getShortLabel());
+                            // The new one replaces the old manifest shortcut, so the long label
+                            // should be gone now.
+                            assertNull(si.getLongLabel());
+                        });
+            });
+
+            // Now, change the launcher to launcher2, and request pin again.
+            setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_2, USER_0));
+
+            reset(mServiceContext);
+
+            assertTrue(mManager.isRequestPinShortcutSupported());
+            mManager.requestPinShortcut(
+                    makeShortcutWithShortLabel("ms4", "new-title-4"),
+                    /*PendingIntent=*/ null);
+
+            // Initially there should be no pinned shortcuts for L2.
+            runWithCaller(LAUNCHER_2, USER_0, () -> {
+                assertWith(getShortcutAsLauncher(USER_0))
+                        .selectPinned()
+                        .isEmpty();
+
+                final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+
+                verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
+
+                assertEquals(LauncherApps.ACTION_CONFIRM_PIN_SHORTCUT,
+                        intent.getValue().getAction());
+                assertEquals(LAUNCHER_2, intent.getValue().getComponent().getPackageName());
+
+                // Check the request object.
+                final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
+
+                assertNotNull(request);
+                assertEquals(PinItemRequest.REQUEST_TYPE_SHORTCUT, request.getRequestType());
+
+                assertWith(request.getShortcutInfo())
+                        .haveIds("ms4")
+                        .areAllOrphan()
+                        .forAllShortcuts(si -> {
+                            assertEquals("new-title-4", si.getShortLabel());
+                            // The new one replaces the old manifest shortcut, so the long label
+                            // should be gone now.
+                            assertNull(si.getLongLabel());
+                        });
+                assertTrue(request.accept());
+
+                assertWith(getShortcutAsLauncher(USER_0))
+                        .selectPinned()
+                        .haveIds("ms4")
+                        .areAllEnabled();
+            });
+        });
+    }
+
+    /**
+     * Test for restoring the pre-P backup format.
+     */
+    public void testBackupAndRestore_api27format() throws Exception {
+        final byte[] payload = readTestAsset("shortcut/shortcut_api27_backup.xml").getBytes();
+
+        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "22222");
+        addPackage(LAUNCHER_1, LAUNCHER_UID_1, 10, "11111");
+
+        runWithSystemUid(() -> mService.applyRestore(payload, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .areAllPinned()
+                    .haveIds("s1")
+                    .areAllEnabled();
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertWith(getShortcutAsLauncher(USER_0))
+                    .areAllPinned()
+                    .haveIds("s1")
+                    .areAllEnabled();
+        });
+        // Make sure getBackupSourceVersionCode and isBackupSourceBackupAllowed
+        // are correct. We didn't have them in the old format.
+        assertEquals(8, mService.getPackageShortcutForTest(CALLING_PACKAGE_1, USER_0)
+                .getPackageInfo().getBackupSourceVersionCode());
+        assertTrue(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, USER_0)
+                .getPackageInfo().isBackupSourceBackupAllowed());
+
+        assertEquals(9, mService.getLauncherShortcutForTest(LAUNCHER_1, USER_0)
+                .getPackageInfo().getBackupSourceVersionCode());
+        assertTrue(mService.getLauncherShortcutForTest(LAUNCHER_1, USER_0)
+                .getPackageInfo().isBackupSourceBackupAllowed());
+
+    }
+
     public void testSaveAndLoad_crossProfile() {
         prepareCrossProfileDataSet();
 
@@ -6048,7 +6422,7 @@
 
         addManifestShortcutResource(
                 new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
-                R.xml.shortcut_5);
+                R.xml.shortcut_5_altalt);
         updatePackageVersion(CALLING_PACKAGE_2, 1);
                 mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageAddIntent(CALLING_PACKAGE_2, USER_0));
@@ -6090,6 +6464,8 @@
                 mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageAddIntent(CALLING_PACKAGE_2, USER_0));
 
+        dumpsysOnLogcat("After updating package 2");
+
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
                     mManager.getManifestShortcuts()))),
@@ -6110,11 +6486,27 @@
                     "ms2", "ms3");
             // ms3 is no longer in manifest, so should be disabled.
             // but ms1 and ms2 should be enabled.
-            assertAllEnabled(list(getCallerShortcut("ms1")));
-            assertAllEnabled(list(getCallerShortcut("ms2")));
-            assertAllDisabled(list(getCallerShortcut("ms3")));
+            assertWith(getCallerShortcuts())
+                    .selectByIds("ms1", "ms2")
+                    .areAllEnabled()
+
+                    .revertToOriginalList()
+                    .selectByIds("ms3")
+                    .areAllDisabled()
+                    .areAllWithDisabledReason(ShortcutInfo.DISABLED_REASON_APP_CHANGED);
         });
 
+        // Make sure the launcher see the correct disabled reason.
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertWith(getShortcutAsLauncher(USER_0))
+                    .forShortcutWithId("ms3", si -> {
+                        assertEquals("string-com.android.test.2-user:0-res:"
+                                        + R.string.shortcut_disabled_message3 + "/en",
+                                si.getDisabledMessage());
+                    });
+        });
+
+
         // Package 2 on user 10 has no shortcuts yet.
         runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
             assertEmpty(mManager.getManifestShortcuts());
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 3220ea9..fcdadac 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -1131,7 +1131,8 @@
         assertEquals(0, si.getRank());
         assertEquals(1, si.getExtras().getInt("k"));
 
-        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags());
+        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_STRINGS_RESOLVED
+                | ShortcutInfo.FLAG_SHADOW , si.getFlags());
         assertNull(si.getBitmapPath()); // No icon.
         assertEquals(0, si.getIconResourceId());
 
@@ -1198,7 +1199,8 @@
         assertEquals(0, si.getRank());
         assertEquals(1, si.getExtras().getInt("k"));
 
-        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags());
+        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_STRINGS_RESOLVED
+                | ShortcutInfo.FLAG_SHADOW , si.getFlags());
         assertNull(si.getBitmapPath()); // No icon.
         assertEquals(0, si.getIconResourceId());
         assertEquals(null, si.getIconResName());
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index d362c3b..27c5eab 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -348,20 +348,17 @@
      */
     @Test
     public void testPinnedStackLocation() {
-        createStackControllerOnStackOnDisplay(
-                WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent);
-        final int initialStackCount = mDisplayContent.getStackCount();
-        // Ensure that the pinned stack was placed at the end
-        assertEquals(initialStackCount - 1,
-                mDisplayContent.getStackPosition(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD));
+        final TaskStack pinnedStack = createStackControllerOnStackOnDisplay(
+                WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
+        // Ensure that the pinned stack is the top stack
+        assertEquals(pinnedStack, mDisplayContent.getPinnedStack());
+        assertEquals(pinnedStack, mDisplayContent.getTopStack());
         // By default, this should try to create a new stack on top
-        createTaskStackOnDisplay(mDisplayContent);
-        final int afterStackCount = mDisplayContent.getStackCount();
-        // Make sure the stack count has increased
-        assertEquals(initialStackCount + 1, afterStackCount);
+        final TaskStack otherStack = createTaskStackOnDisplay(mDisplayContent);
+        // Ensure that the other stack is on the display.
+        assertEquals(mDisplayContent, otherStack.getDisplayContent());
         // Ensure that the pinned stack is still on top
-        assertEquals(afterStackCount - 1,
-                mDisplayContent.getStackPosition(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD));
+        assertEquals(pinnedStack, mDisplayContent.getTopStack());
     }
 
     /**
diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
index 926a606..99eb846 100644
--- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
+++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
@@ -22,6 +22,7 @@
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.Assert.fail;
 
+import static org.junit.Assert.assertNotEquals;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyList;
 import static org.mockito.Matchers.anyString;
@@ -59,9 +60,7 @@
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatcher;
 import org.mockito.ArgumentMatchers;
-import org.mockito.Mockito;
 import org.mockito.hamcrest.MockitoHamcrest;
 
 import java.io.BufferedReader;
@@ -898,11 +897,14 @@
 
         public ShortcutListAsserter areAllEnabled() {
             forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.isEnabled()));
+            areAllWithDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
             return this;
         }
 
         public ShortcutListAsserter areAllDisabled() {
             forAllShortcuts(s -> assertFalse("id=" + s.getId(), s.isEnabled()));
+            forAllShortcuts(s -> assertNotEquals("id=" + s.getId(),
+                    ShortcutInfo.DISABLED_REASON_NOT_DISABLED, s.getDisabledReason()));
             return this;
         }
 
@@ -930,6 +932,16 @@
             return this;
         }
 
+        public ShortcutListAsserter areAllVisibleToPublisher() {
+            forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.isVisibleToPublisher()));
+            return this;
+        }
+
+        public ShortcutListAsserter areAllNotVisibleToPublisher() {
+            forAllShortcuts(s -> assertFalse("id=" + s.getId(), s.isVisibleToPublisher()));
+            return this;
+        }
+
         public ShortcutListAsserter areAllWithKeyFieldsOnly() {
             forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.hasKeyFieldsOnly()));
             return this;
@@ -960,6 +972,17 @@
             return this;
         }
 
+        public ShortcutListAsserter areAllWithDisabledReason(int disabledReason) {
+            forAllShortcuts(s -> assertEquals("id=" + s.getId(),
+                    disabledReason, s.getDisabledReason()));
+            if (disabledReason >= ShortcutInfo.DISABLED_REASON_VERSION_LOWER) {
+                areAllNotVisibleToPublisher();
+            } else {
+                areAllVisibleToPublisher();
+            }
+            return this;
+        }
+
         public ShortcutListAsserter forAllShortcuts(Consumer<ShortcutInfo> sa) {
             boolean found = false;
             for (int i = 0; i < mList.size(); i++) {
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index acc27be..d359b70 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -132,7 +132,9 @@
         mHasMidiFeature = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI);
 
         // initial scan
-        mCardsParser.scan();
+        if (mCardsParser.scan() != AlsaCardsParser.SCANSTATUS_SUCCESS) {
+            Slog.e(TAG, "Error scanning ASLA cards file.");
+        }
     }
 
     public void systemReady() {
@@ -314,7 +316,7 @@
             return null;
         }
 
-        if (!mDevicesParser.scan()) {
+        if (mDevicesParser.scan() != AlsaDevicesParser.SCANSTATUS_SUCCESS) {
             Slog.e(TAG, "Error parsing ALSA devices file.");
             return null;
         }
@@ -530,6 +532,9 @@
     //
     // called by UsbService.dump
     public void dump(IndentingPrintWriter pw) {
+        pw.println("Parsers Scan Status:");
+        pw.println("  Cards Parser: " + mCardsParser.getScanStatus());
+        pw.println("  Devices Parser: " + mDevicesParser.getScanStatus());
         pw.println("USB Audio Devices:");
         for (UsbDevice device : mAudioDevices.keySet()) {
             pw.println("  " + device.getDeviceName() + ": " + mAudioDevices.get(device));
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index c657a1b..095fdc6 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -376,6 +376,8 @@
                 }
             }
         }
+
+        mUsbAlsaManager.dump(pw);
     }
 
     private native void monitorUsbHostBus();
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 689ce95..de980b2f 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -763,6 +763,18 @@
     public static final String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
 
     /**
+     * Some carriers will send call forwarding responses for voicemail in a format that is not 3gpp
+     * compliant, which causes issues during parsing. This causes the
+     * {@link com.android.internal.telephony.CallForwardInfo#number} to contain non-numerical
+     * characters instead of a number.
+     *
+     * If true, we will detect the non-numerical characters and replace them with "Voicemail".
+     * @hide
+     */
+    public static final String KEY_CALL_FORWARDING_MAP_NON_NUMBER_TO_VOICEMAIL_BOOL =
+            "call_forwarding_map_non_number_to_voicemail_bool";
+
+    /**
      * Determines whether conference calls are supported by a carrier.  When {@code true},
      * conference calling is supported, {@code false otherwise}.
      */
@@ -1573,6 +1585,25 @@
     public static final String KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL =
             "show_ims_registration_status_bool";
 
+    /**
+     * The flag to disable the popup dialog which warns the user of data charges.
+     * @hide
+     */
+    public static final String KEY_DISABLE_CHARGE_INDICATION_BOOL =
+            "disable_charge_indication_bool";
+
+    /**
+     * Boolean indicating whether to skip the call forwarding (CF) fail-to-disable dialog.
+     * The logic used to determine whether we succeeded in disabling is carrier specific,
+     * so the dialog may not always be accurate.
+     * {@code false} - show CF fail-to-disable dialog.
+     * {@code true}  - skip showing CF fail-to-disable dialog.
+     *
+     * @hide
+     */
+    public static final String KEY_SKIP_CF_FAIL_TO_DISABLE_DIALOG_BOOL =
+            "skip_cf_fail_to_disable_dialog_bool";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -1703,6 +1734,7 @@
         sDefaults.putInt(KEY_GSM_DTMF_TONE_DELAY_INT, 0);
         sDefaults.putInt(KEY_IMS_DTMF_TONE_DELAY_INT, 0);
         sDefaults.putInt(KEY_CDMA_DTMF_TONE_DELAY_INT, 100);
+        sDefaults.putBoolean(KEY_CALL_FORWARDING_MAP_NON_NUMBER_TO_VOICEMAIL_BOOL, false);
         sDefaults.putInt(KEY_CDMA_3WAYCALL_FLASH_DELAY_INT , 0);
         sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true);
         sDefaults.putBoolean(KEY_SUPPORT_IMS_CONFERENCE_CALL_BOOL, true);
@@ -1726,6 +1758,7 @@
         sDefaults.putString(KEY_CARRIER_NAME_STRING, "");
         sDefaults.putBoolean(KEY_SUPPORT_DIRECT_FDN_DIALING_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL, false);
+        sDefaults.putBoolean(KEY_SKIP_CF_FAIL_TO_DISABLE_DIALOG_BOOL, false);
 
         // MMS defaults
         sDefaults.putBoolean(KEY_MMS_ALIAS_ENABLED_BOOL, false);
@@ -1840,6 +1873,7 @@
         sDefaults.putStringArray(KEY_NON_ROAMING_OPERATOR_STRING_ARRAY, null);
         sDefaults.putStringArray(KEY_ROAMING_OPERATOR_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, false);
+        sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
     }
 
     /**
diff --git a/telephony/java/android/telephony/MbmsDownloadSession.java b/telephony/java/android/telephony/MbmsDownloadSession.java
index 764b7b2..9a9877a 100644
--- a/telephony/java/android/telephony/MbmsDownloadSession.java
+++ b/telephony/java/android/telephony/MbmsDownloadSession.java
@@ -77,8 +77,9 @@
      * Integer extra that Android will attach to the intent supplied via
      * {@link android.telephony.mbms.DownloadRequest.Builder#setAppIntent(Intent)}
      * Indicates the result code of the download. One of
-     * {@link #RESULT_SUCCESSFUL}, {@link #RESULT_EXPIRED}, {@link #RESULT_CANCELLED}, or
-     * {@link #RESULT_IO_ERROR}.
+     * {@link #RESULT_SUCCESSFUL}, {@link #RESULT_EXPIRED}, {@link #RESULT_CANCELLED},
+     * {@link #RESULT_IO_ERROR}, {@link #RESULT_DOWNLOAD_FAILURE}, {@link #RESULT_OUT_OF_STORAGE},
+     * {@link #RESULT_SERVICE_ID_NOT_DEFINED}, or {@link #RESULT_FILE_ROOT_UNREACHABLE}.
      *
      * This extra may also be used by the middleware when it is sending intents to the app.
      */
@@ -142,11 +143,41 @@
 
     /**
      * Indicates that the download will not be completed due to an I/O error incurred while
-     * writing to temp files. This commonly indicates that the device is out of storage space,
-     * but may indicate other conditions as well (such as an SD card being removed).
+     * writing to temp files.
+     *
+     * This is likely a transient error and another {@link DownloadRequest} should be sent to try
+     * the download again.
      */
     public static final int RESULT_IO_ERROR = 4;
-    // TODO - more results!
+
+    /**
+     * Indicates that the Service ID specified in the {@link DownloadRequest} is incorrect due to
+     * the Id being incorrect, stale, expired, or similar.
+     */
+    public static final int RESULT_SERVICE_ID_NOT_DEFINED = 5;
+
+    /**
+     * Indicates that there was an error while processing downloaded files, such as a file repair or
+     * file decoding error and is not due to a file I/O error.
+     *
+     * This is likely a transient error and another {@link DownloadRequest} should be sent to try
+     * the download again.
+     */
+    public static final int RESULT_DOWNLOAD_FAILURE = 6;
+
+    /**
+     * Indicates that the file system is full and the {@link DownloadRequest} can not complete.
+     * Either space must be made on the current file system or the temp file root location must be
+     * changed to a location that is not full to download the temp files.
+     */
+    public static final int RESULT_OUT_OF_STORAGE = 7;
+
+    /**
+     * Indicates that the file root that was set is currently unreachable. This can happen if the
+     * temp files are set to be stored on external storage and the SD card was removed, for example.
+     * The temp file root should be changed before sending another DownloadRequest.
+     */
+    public static final int RESULT_FILE_ROOT_UNREACHABLE = 8;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
diff --git a/telephony/java/android/telephony/NetworkScanRequest.java b/telephony/java/android/telephony/NetworkScanRequest.java
index d2aef20..9674c93 100644
--- a/telephony/java/android/telephony/NetworkScanRequest.java
+++ b/telephony/java/android/telephony/NetworkScanRequest.java
@@ -19,6 +19,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 
 /**
@@ -38,6 +39,20 @@
     public static final int MAX_BANDS = 8;
     /** @hide */
     public static final int MAX_CHANNELS = 32;
+    /** @hide */
+    public static final int MAX_MCC_MNC_LIST_SIZE = 20;
+    /** @hide */
+    public static final int MIN_SEARCH_PERIODICITY_SEC = 5;
+    /** @hide */
+    public static final int MAX_SEARCH_PERIODICITY_SEC = 300;
+    /** @hide */
+    public static final int MIN_SEARCH_MAX_SEC = 60;
+    /** @hide */
+    public static final int MAX_SEARCH_MAX_SEC = 3600;
+    /** @hide */
+    public static final int MIN_INCREMENTAL_PERIODICITY_SEC = 1;
+    /** @hide */
+    public static final int MAX_INCREMENTAL_PERIODICITY_SEC = 10;
 
     /** Performs the scan only once */
     public static final int SCAN_TYPE_ONE_SHOT = 0;
@@ -46,24 +61,84 @@
      *
      * The modem will start new scans periodically, and the interval between two scans is usually
      * multiple minutes.
-     * */
+     */
     public static final int SCAN_TYPE_PERIODIC = 1;
 
     /** Defines the type of the scan. */
     public int scanType;
 
+    /**
+     * Search periodicity (in seconds).
+     * Expected range for the input is [5s - 300s]
+     * This value must be less than or equal to maxSearchTime
+     */
+    public int searchPeriodicity;
+
+    /**
+     * Maximum duration of the periodic search (in seconds).
+     * Expected range for the input is [60s - 3600s]
+     * If the search lasts this long, it will be terminated.
+     */
+    public int maxSearchTime;
+
+    /**
+     * Indicates whether the modem should report incremental
+     * results of the network scan to the client.
+     * FALSE – Incremental results are not reported.
+     * TRUE (default) – Incremental results are reported
+     */
+    public boolean incrementalResults;
+
+    /**
+     * Indicates the periodicity with which the modem should
+     * report incremental results to the client (in seconds).
+     * Expected range for the input is [1s - 10s]
+     * This value must be less than or equal to maxSearchTime
+     */
+    public int incrementalResultsPeriodicity;
+
     /** Describes the radio access technologies with bands or channels that need to be scanned. */
     public RadioAccessSpecifier[] specifiers;
 
     /**
+     * Describes the List of PLMN ids (MCC-MNC)
+     * If any PLMN of this list is found, search should end at that point and
+     * results with all PLMN found till that point should be sent as response.
+     * If list not sent, search to be completed till end and all PLMNs found to be reported.
+     * Max size of array is MAX_MCC_MNC_LIST_SIZE
+     */
+    public ArrayList<String> mccMncs;
+
+    /**
      * Creates a new NetworkScanRequest with scanType and network specifiers
      *
      * @param scanType The type of the scan
      * @param specifiers the radio network with bands / channels to be scanned
+     * @param searchPeriodicity Search periodicity (in seconds)
+     * @param maxSearchTime Maximum duration of the periodic search (in seconds)
+     * @param incrementalResults Indicates whether the modem should report incremental
+     *                           results of the network scan to the client
+     * @param incrementalResultsPeriodicity Indicates the periodicity with which the modem should
+     *                                      report incremental results to the client (in seconds)
+     * @param mccMncs Describes the List of PLMN ids (MCC-MNC)
      */
-    public NetworkScanRequest(int scanType, RadioAccessSpecifier[] specifiers) {
+    public NetworkScanRequest(int scanType, RadioAccessSpecifier[] specifiers,
+                    int searchPeriodicity,
+                    int maxSearchTime,
+                    boolean incrementalResults,
+                    int incrementalResultsPeriodicity,
+                    ArrayList<String> mccMncs) {
         this.scanType = scanType;
         this.specifiers = specifiers;
+        this.searchPeriodicity = searchPeriodicity;
+        this.maxSearchTime = maxSearchTime;
+        this.incrementalResults = incrementalResults;
+        this.incrementalResultsPeriodicity = incrementalResultsPeriodicity;
+        if (mccMncs != null) {
+            this.mccMncs = mccMncs;
+        } else {
+            this.mccMncs = new ArrayList<>();
+        }
     }
 
     @Override
@@ -75,6 +150,11 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(scanType);
         dest.writeParcelableArray(specifiers, flags);
+        dest.writeInt(searchPeriodicity);
+        dest.writeInt(maxSearchTime);
+        dest.writeBoolean(incrementalResults);
+        dest.writeInt(incrementalResultsPeriodicity);
+        dest.writeStringList(mccMncs);
     }
 
     private NetworkScanRequest(Parcel in) {
@@ -82,6 +162,12 @@
         specifiers = (RadioAccessSpecifier[]) in.readParcelableArray(
                 Object.class.getClassLoader(),
                 RadioAccessSpecifier.class);
+        searchPeriodicity = in.readInt();
+        maxSearchTime = in.readInt();
+        incrementalResults = in.readBoolean();
+        incrementalResultsPeriodicity = in.readInt();
+        mccMncs = new ArrayList<>();
+        in.readStringList(mccMncs);
     }
 
     @Override
@@ -99,13 +185,24 @@
         }
 
         return (scanType == nsr.scanType
-                && Arrays.equals(specifiers, nsr.specifiers));
+                && Arrays.equals(specifiers, nsr.specifiers)
+                && searchPeriodicity == nsr.searchPeriodicity
+                && maxSearchTime == nsr.maxSearchTime
+                && incrementalResults == nsr.incrementalResults
+                && incrementalResultsPeriodicity == nsr.incrementalResultsPeriodicity
+                && (((mccMncs != null)
+                && mccMncs.equals(nsr.mccMncs))));
     }
 
     @Override
     public int hashCode () {
         return ((scanType * 31)
-                + (Arrays.hashCode(specifiers)) * 37);
+                + (Arrays.hashCode(specifiers)) * 37
+                + (searchPeriodicity * 41)
+                + (maxSearchTime * 43)
+                + ((incrementalResults == true? 1 : 0) * 47)
+                + (incrementalResultsPeriodicity * 53)
+                + (mccMncs.hashCode() * 59));
     }
 
     public static final Creator<NetworkScanRequest> CREATOR =
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index e448fb2..116e711 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1197,15 +1197,6 @@
         }
     }
 
-    /**
-     * @Deprecated to be removed Q3 2013 use {@link #getVoiceNetworkType}
-     * @hide
-     */
-    public int getNetworkType() {
-        Rlog.e(LOG_TAG, "ServiceState.getNetworkType() DEPRECATED will be removed *******");
-        return rilRadioTechnologyToNetworkType(mRilVoiceRadioTechnology);
-    }
-
     /** @hide */
     public int getDataNetworkType() {
         return rilRadioTechnologyToNetworkType(mRilDataRadioTechnology);
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index 9e02399..c8b4776 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -19,7 +19,6 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.telephony.Rlog;
 import android.util.Log;
 import android.content.res.Resources;
 
@@ -429,6 +428,15 @@
     }
 
     /**
+     * Fix {@link #isGsm} based on the signal strength data.
+     *
+     * @hide
+     */
+    public void fixType() {
+        isGsm = getCdmaRelatedSignalStrength() == SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+    }
+
+    /**
      * @param true - Gsm, Lte phones
      *        false - Cdma phones
      *
@@ -541,30 +549,7 @@
      *     while 4 represents a very strong signal strength.
      */
     public int getLevel() {
-        int level = 0;
-
-        if (isGsm) {
-            level = getLteLevel();
-            if (level == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
-                level = getTdScdmaLevel();
-                if (level == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
-                    level = getGsmLevel();
-                }
-            }
-        } else {
-            int cdmaLevel = getCdmaLevel();
-            int evdoLevel = getEvdoLevel();
-            if (evdoLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
-                /* We don't know evdo, use cdma */
-                level = cdmaLevel;
-            } else if (cdmaLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
-                /* We don't know cdma, use evdo */
-                level = evdoLevel;
-            } else {
-                /* We know both, use the lowest level */
-                level = cdmaLevel < evdoLevel ? cdmaLevel : evdoLevel;
-            }
-        }
+        int level = isGsm ? getGsmRelatedSignalStrength() : getCdmaRelatedSignalStrength();
         if (DBG) log("getLevel=" + level);
         return level;
     }
@@ -1049,6 +1034,36 @@
                 + " " + (isGsm ? "gsm|lte" : "cdma"));
     }
 
+    /** Returns the signal strength related to GSM. */
+    private int getGsmRelatedSignalStrength() {
+        int level = getLteLevel();
+        if (level == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
+            level = getTdScdmaLevel();
+            if (level == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
+                level = getGsmLevel();
+            }
+        }
+        return level;
+    }
+
+    /** Returns the signal strength related to CDMA. */
+    private int getCdmaRelatedSignalStrength() {
+        int level;
+        int cdmaLevel = getCdmaLevel();
+        int evdoLevel = getEvdoLevel();
+        if (evdoLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
+            /* We don't know evdo, use cdma */
+            level = cdmaLevel;
+        } else if (cdmaLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
+            /* We don't know cdma, use evdo */
+            level = evdoLevel;
+        } else {
+            /* We know both, use the lowest level */
+            level = cdmaLevel < evdoLevel ? cdmaLevel : evdoLevel;
+        }
+        return level;
+    }
+
     /**
      * Set SignalStrength based on intent notifier map
      *
diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
index fe27537..9af1eb9 100644
--- a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
+++ b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
@@ -287,7 +287,7 @@
             return;
         }
 
-        List<Uri> tempFiles = intent.getParcelableExtra(VendorUtils.EXTRA_TEMP_LIST);
+        List<Uri> tempFiles = intent.getParcelableArrayListExtra(VendorUtils.EXTRA_TEMP_LIST);
         if (tempFiles == null) {
             return;
         }
@@ -309,7 +309,7 @@
             return;
         }
         int fdCount = intent.getIntExtra(VendorUtils.EXTRA_FD_COUNT, 0);
-        List<Uri> pausedList = intent.getParcelableExtra(VendorUtils.EXTRA_PAUSED_LIST);
+        List<Uri> pausedList = intent.getParcelableArrayListExtra(VendorUtils.EXTRA_PAUSED_LIST);
 
         if (fdCount == 0 && (pausedList == null || pausedList.size() == 0)) {
             Log.i(LOG_TAG, "No temp files actually requested. Ending.");
@@ -492,9 +492,14 @@
         } catch (PackageManager.NameNotFoundException e) {
             throw new RuntimeException("Package manager couldn't find " + context.getPackageName());
         }
+        if (appInfo.metaData == null) {
+            throw new RuntimeException("App must declare the file provider authority as metadata " +
+                    "in the manifest.");
+        }
         String authority = appInfo.metaData.getString(MBMS_FILE_PROVIDER_META_DATA_KEY);
         if (authority == null) {
-            throw new RuntimeException("Must declare the file provider authority as meta data");
+            throw new RuntimeException("App must declare the file provider authority as metadata " +
+                    "in the manifest.");
         }
         return authority;
     }
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
index 2f85a1d..c3b2c48 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
@@ -113,6 +113,10 @@
     @Override
     public final int initialize(final int subscriptionId,
             final IMbmsDownloadSessionCallback callback) throws RemoteException {
+        if (callback == null) {
+            throw new NullPointerException("Callback must not be null");
+        }
+
         final int uid = Binder.getCallingUid();
         callback.asBinder().linkToDeath(new DeathRecipient() {
             @Override
@@ -240,6 +244,13 @@
     public final int registerStateCallback(final DownloadRequest downloadRequest,
             final IDownloadStateCallback callback, int flags) throws RemoteException {
         final int uid = Binder.getCallingUid();
+        if (downloadRequest == null) {
+            throw new NullPointerException("Download request must not be null");
+        }
+        if (callback == null) {
+            throw new NullPointerException("Callback must not be null");
+        }
+
         DeathRecipient deathRecipient = new DeathRecipient() {
             @Override
             public void binderDied() {
@@ -292,6 +303,13 @@
     public final int unregisterStateCallback(
             final DownloadRequest downloadRequest, final IDownloadStateCallback callback)
             throws RemoteException {
+        if (downloadRequest == null) {
+            throw new NullPointerException("Download request must not be null");
+        }
+        if (callback == null) {
+            throw new NullPointerException("Callback must not be null");
+        }
+
         DeathRecipient deathRecipient =
                 mDownloadCallbackDeathRecipients.remove(callback.asBinder());
         if (deathRecipient == null) {
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
index f8f370a..65b726d 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
@@ -65,6 +65,10 @@
     @Override
     public final int initialize(final IMbmsStreamingSessionCallback callback,
             final int subscriptionId) throws RemoteException {
+        if (callback == null) {
+            throw new NullPointerException("Callback must not be null");
+        }
+
         final int uid = Binder.getCallingUid();
         callback.asBinder().linkToDeath(new DeathRecipient() {
             @Override
@@ -152,6 +156,10 @@
     @Override
     public int startStreaming(final int subscriptionId, String serviceId,
             final IStreamingServiceCallback callback) throws RemoteException {
+        if (callback == null) {
+            throw new NullPointerException("Callback must not be null");
+        }
+
         final int uid = Binder.getCallingUid();
         callback.asBinder().linkToDeath(new DeathRecipient() {
             @Override
diff --git a/tests/FeatureSplit/base/Android.mk b/tests/FeatureSplit/base/Android.mk
index 93f6d7a..6da1b38 100644
--- a/tests/FeatureSplit/base/Android.mk
+++ b/tests/FeatureSplit/base/Android.mk
@@ -17,6 +17,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
+LOCAL_USE_AAPT2 := true
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 LOCAL_PACKAGE_NAME := FeatureSplitBase
 LOCAL_EXPORT_PACKAGE_RESOURCES := true
diff --git a/tests/FeatureSplit/feature1/Android.mk b/tests/FeatureSplit/feature1/Android.mk
index e6ba5c2..b3ea97b 100644
--- a/tests/FeatureSplit/feature1/Android.mk
+++ b/tests/FeatureSplit/feature1/Android.mk
@@ -26,6 +26,6 @@
 LOCAL_RES_LIBRARIES := FeatureSplitBase
 
 LOCAL_AAPT_FLAGS += --package-id 0x80
-LOCAL_AAPT_FLAGS += --custom-package com.android.test.split.feature.one
+LOCAL_AAPT_FLAGS += --rename-manifest-package com.android.test.split.feature
 
 include $(BUILD_PACKAGE)
diff --git a/tests/FeatureSplit/feature1/AndroidManifest.xml b/tests/FeatureSplit/feature1/AndroidManifest.xml
index b87361f..4e7d151 100644
--- a/tests/FeatureSplit/feature1/AndroidManifest.xml
+++ b/tests/FeatureSplit/feature1/AndroidManifest.xml
@@ -15,13 +15,13 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.test.split.feature"
+    package="com.android.test.split.feature.one"
     featureSplit="feature1">
 
     <uses-sdk android:minSdkVersion="21" />
 
     <application>
-        <activity android:name=".one.One" android:label="Feature One">
+        <activity android:name=".One" android:label="Feature One">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
diff --git a/tests/FeatureSplit/feature1/res/values/values.xml b/tests/FeatureSplit/feature1/res/values/values.xml
index 10dbd97..0e3e73c 100644
--- a/tests/FeatureSplit/feature1/res/values/values.xml
+++ b/tests/FeatureSplit/feature1/res/values/values.xml
@@ -20,7 +20,7 @@
     <integer name="test_integer2">200</integer>
     <color name="test_color2">#00ff00</color>
     <string-array name="string_array2">
-        <item>@*string/app_title</item>
+        <item>@*com.android.test.split.feature:string/app_title</item>
     </string-array>
 </resources>
 
diff --git a/tests/FeatureSplit/feature2/Android.mk b/tests/FeatureSplit/feature2/Android.mk
index c8e8609..e2fd903 100644
--- a/tests/FeatureSplit/feature2/Android.mk
+++ b/tests/FeatureSplit/feature2/Android.mk
@@ -26,6 +26,6 @@
 LOCAL_RES_LIBRARIES := FeatureSplitBase
 
 LOCAL_AAPT_FLAGS += --package-id 0x81
-LOCAL_AAPT_FLAGS += --custom-package com.android.test.split.feature.two
+LOCAL_AAPT_FLAGS += --rename-manifest-package com.android.test.split.feature
 
 include $(BUILD_PACKAGE)
diff --git a/tests/FeatureSplit/feature2/AndroidManifest.xml b/tests/FeatureSplit/feature2/AndroidManifest.xml
index abd0b5e..bfe6f38 100644
--- a/tests/FeatureSplit/feature2/AndroidManifest.xml
+++ b/tests/FeatureSplit/feature2/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.test.split.feature"
+    package="com.android.test.split.feature.two"
     featureSplit="feature2">
 
     <uses-sdk android:minSdkVersion="21" />
diff --git a/tests/FeatureSplit/feature2/res/values/values.xml b/tests/FeatureSplit/feature2/res/values/values.xml
index af5ed1b..2fa6f90 100644
--- a/tests/FeatureSplit/feature2/res/values/values.xml
+++ b/tests/FeatureSplit/feature2/res/values/values.xml
@@ -18,7 +18,7 @@
     <integer name="test_integer3">300</integer>
     <color name="test_color3">#0000ff</color>
     <string-array name="string_array3">
-        <item>@string/app_title</item>
+        <item>@*com.android.test.split.feature:string/app_title</item>
     </string-array>
 </resources>
 
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
index 25bfa53..047be16 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
@@ -17,6 +17,7 @@
 package android.security.net.config;
 
 import android.app.Activity;
+import android.content.pm.ApplicationInfo;
 import android.os.Build;
 import android.test.ActivityUnitTestCase;
 import android.util.ArraySet;
@@ -227,7 +228,8 @@
     public void testConfigBuilderUsesParents() throws Exception {
         // Check that a builder with a parent uses the parent's values when non is set.
         NetworkSecurityConfig config = new NetworkSecurityConfig.Builder()
-                .setParent(NetworkSecurityConfig.getDefaultBuilder(Build.VERSION_CODES.N, 1))
+                .setParent(NetworkSecurityConfig
+                        .getDefaultBuilder(TestUtils.makeApplicationInfo()))
                 .build();
         assert(!config.getTrustAnchors().isEmpty());
     }
@@ -268,11 +270,22 @@
             // Install the test CA.
             store.installCertificate(TEST_CA_CERT);
             NetworkSecurityConfig preNConfig =
-                    NetworkSecurityConfig.getDefaultBuilder(Build.VERSION_CODES.M, 1).build();
+                    NetworkSecurityConfig
+                    .getDefaultBuilder(TestUtils.makeApplicationInfo(Build.VERSION_CODES.M))
+                    .build();
             NetworkSecurityConfig nConfig =
-                    NetworkSecurityConfig.getDefaultBuilder(Build.VERSION_CODES.N, 1).build();
+                    NetworkSecurityConfig
+                    .getDefaultBuilder(TestUtils.makeApplicationInfo(Build.VERSION_CODES.N))
+                    .build();
+            ApplicationInfo privInfo = TestUtils.makeApplicationInfo(Build.VERSION_CODES.M);
+            privInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+            NetworkSecurityConfig privConfig =
+                    NetworkSecurityConfig
+                    .getDefaultBuilder(privInfo)
+                    .build();
             Set<TrustAnchor> preNAnchors = preNConfig.getTrustAnchors();
             Set<TrustAnchor> nAnchors = nConfig.getTrustAnchors();
+            Set<TrustAnchor> privAnchors = privConfig.getTrustAnchors();
             Set<X509Certificate> preNCerts = new HashSet<X509Certificate>();
             for (TrustAnchor anchor : preNAnchors) {
                 preNCerts.add(anchor.certificate);
@@ -281,8 +294,13 @@
             for (TrustAnchor anchor : nAnchors) {
                 nCerts.add(anchor.certificate);
             }
+            Set<X509Certificate> privCerts = new HashSet<X509Certificate>();
+            for (TrustAnchor anchor : privAnchors) {
+                privCerts.add(anchor.certificate);
+            }
             assertTrue(preNCerts.contains(TEST_CA_CERT));
             assertFalse(nCerts.contains(TEST_CA_CERT));
+            assertFalse(privCerts.contains(TEST_CA_CERT));
         } finally {
             // Delete the user added CA. We don't know the alias so just delete them all.
             for (String alias : store.aliases()) {
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java
index f7590fd..9dec21b 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java
@@ -16,6 +16,8 @@
 
 package android.security.net.config;
 
+import android.content.pm.ApplicationInfo;
+import android.os.Build;
 import java.net.Socket;
 import java.net.URL;
 import javax.net.ssl.HttpsURLConnection;
@@ -77,4 +79,17 @@
         context.init(null, tmf.getTrustManagers(), null);
         return context;
     }
+
+    public static ApplicationInfo makeApplicationInfo() {
+        ApplicationInfo info = new ApplicationInfo();
+        info.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+        info.targetSandboxVersion = 1;
+        return info;
+    }
+
+    public static ApplicationInfo makeApplicationInfo(int targetSdkVersion) {
+        ApplicationInfo info = makeApplicationInfo();
+        info.targetSdkVersion = targetSdkVersion;
+        return info;
+    }
 }
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
index f7066a6..4b7a014 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
@@ -17,6 +17,7 @@
 package android.security.net.config;
 
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.test.AndroidTestCase;
 import android.test.MoreAsserts;
 import android.util.ArraySet;
@@ -44,7 +45,8 @@
     private final static String DEBUG_CA_SUBJ = "O=AOSP, CN=Test debug CA";
 
     public void testEmptyConfigFile() throws Exception {
-        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.empty_config);
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.empty_config,
+                TestUtils.makeApplicationInfo());
         ApplicationConfig appConfig = new ApplicationConfig(source);
         assertFalse(appConfig.hasPerDomainConfigs());
         NetworkSecurityConfig config = appConfig.getConfigForHostname("");
@@ -63,7 +65,8 @@
     }
 
     public void testEmptyAnchors() throws Exception {
-        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.empty_trust);
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.empty_trust,
+                TestUtils.makeApplicationInfo());
         ApplicationConfig appConfig = new ApplicationConfig(source);
         assertFalse(appConfig.hasPerDomainConfigs());
         NetworkSecurityConfig config = appConfig.getConfigForHostname("");
@@ -81,7 +84,8 @@
     }
 
     public void testBasicDomainConfig() throws Exception {
-        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.domain1);
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.domain1,
+                TestUtils.makeApplicationInfo());
         ApplicationConfig appConfig = new ApplicationConfig(source);
         assertTrue(appConfig.hasPerDomainConfigs());
         NetworkSecurityConfig config = appConfig.getConfigForHostname("");
@@ -117,7 +121,8 @@
     }
 
     public void testBasicPinning() throws Exception {
-        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.pins1);
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.pins1,
+                TestUtils.makeApplicationInfo());
         ApplicationConfig appConfig = new ApplicationConfig(source);
         assertTrue(appConfig.hasPerDomainConfigs());
         // Check android.com.
@@ -132,7 +137,8 @@
     }
 
     public void testExpiredPin() throws Exception {
-        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.expired_pin);
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.expired_pin,
+                TestUtils.makeApplicationInfo());
         ApplicationConfig appConfig = new ApplicationConfig(source);
         assertTrue(appConfig.hasPerDomainConfigs());
         // Check android.com.
@@ -146,7 +152,8 @@
     }
 
     public void testOverridesPins() throws Exception {
-        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.override_pins);
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.override_pins,
+                TestUtils.makeApplicationInfo());
         ApplicationConfig appConfig = new ApplicationConfig(source);
         assertTrue(appConfig.hasPerDomainConfigs());
         // Check android.com.
@@ -160,7 +167,8 @@
     }
 
     public void testBadPin() throws Exception {
-        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.bad_pin);
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.bad_pin,
+                TestUtils.makeApplicationInfo());
         ApplicationConfig appConfig = new ApplicationConfig(source);
         assertTrue(appConfig.hasPerDomainConfigs());
         // Check android.com.
@@ -175,7 +183,8 @@
     }
 
     public void testMultipleDomains() throws Exception {
-        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.multiple_domains);
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.multiple_domains,
+                TestUtils.makeApplicationInfo());
         ApplicationConfig appConfig = new ApplicationConfig(source);
         assertTrue(appConfig.hasPerDomainConfigs());
         NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
@@ -196,7 +205,8 @@
     }
 
     public void testMultipleDomainConfigs() throws Exception {
-        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.multiple_configs);
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.multiple_configs,
+                TestUtils.makeApplicationInfo());
         ApplicationConfig appConfig = new ApplicationConfig(source);
         assertTrue(appConfig.hasPerDomainConfigs());
         // Should be two different config objects
@@ -211,7 +221,8 @@
     }
 
     public void testIncludeSubdomains() throws Exception {
-        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.subdomains);
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.subdomains,
+                TestUtils.makeApplicationInfo());
         ApplicationConfig appConfig = new ApplicationConfig(source);
         assertTrue(appConfig.hasPerDomainConfigs());
         // Try connections.
@@ -224,7 +235,8 @@
     }
 
     public void testAttributes() throws Exception {
-        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.attributes);
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.attributes,
+                TestUtils.makeApplicationInfo());
         ApplicationConfig appConfig = new ApplicationConfig(source);
         assertFalse(appConfig.hasPerDomainConfigs());
         NetworkSecurityConfig config = appConfig.getConfigForHostname("");
@@ -233,7 +245,8 @@
     }
 
     public void testResourcePemCertificateSource() throws Exception {
-        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.resource_anchors_pem);
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.resource_anchors_pem,
+                TestUtils.makeApplicationInfo());
         ApplicationConfig appConfig = new ApplicationConfig(source);
         // Check android.com.
         NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
@@ -249,7 +262,8 @@
     }
 
     public void testResourceDerCertificateSource() throws Exception {
-        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.resource_anchors_der);
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.resource_anchors_der,
+                TestUtils.makeApplicationInfo());
         ApplicationConfig appConfig = new ApplicationConfig(source);
         // Check android.com.
         NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
@@ -265,7 +279,8 @@
     }
 
     public void testNestedDomainConfigs() throws Exception {
-        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.nested_domains);
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.nested_domains,
+                TestUtils.makeApplicationInfo());
         ApplicationConfig appConfig = new ApplicationConfig(source);
         assertTrue(appConfig.hasPerDomainConfigs());
         NetworkSecurityConfig parent = appConfig.getConfigForHostname("android.com");
@@ -283,7 +298,8 @@
     }
 
     public void testNestedDomainConfigsOverride() throws Exception {
-        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.nested_domains_override);
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.nested_domains_override,
+                TestUtils.makeApplicationInfo());
         ApplicationConfig appConfig = new ApplicationConfig(source);
         assertTrue(appConfig.hasPerDomainConfigs());
         NetworkSecurityConfig parent = appConfig.getConfigForHostname("android.com");
@@ -294,7 +310,8 @@
     }
 
     public void testDebugOverridesDisabled() throws Exception {
-        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.debug_basic, false);
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.debug_basic,
+                TestUtils.makeApplicationInfo());
         ApplicationConfig appConfig = new ApplicationConfig(source);
         NetworkSecurityConfig config = appConfig.getConfigForHostname("");
         Set<TrustAnchor> anchors = config.getTrustAnchors();
@@ -305,7 +322,9 @@
     }
 
     public void testBasicDebugOverrides() throws Exception {
-        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.debug_basic, true);
+        ApplicationInfo info = TestUtils.makeApplicationInfo();
+        info.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.debug_basic, info);
         ApplicationConfig appConfig = new ApplicationConfig(source);
         NetworkSecurityConfig config = appConfig.getConfigForHostname("");
         Set<TrustAnchor> anchors = config.getTrustAnchors();
@@ -319,7 +338,9 @@
     }
 
     public void testDebugOverridesWithDomain() throws Exception {
-        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.debug_domain, true);
+        ApplicationInfo info = TestUtils.makeApplicationInfo();
+        info.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.debug_domain, info);
         ApplicationConfig appConfig = new ApplicationConfig(source);
         NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
         Set<TrustAnchor> anchors = config.getTrustAnchors();
@@ -337,7 +358,9 @@
     }
 
     public void testDebugInherit() throws Exception {
-        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.debug_domain, true);
+        ApplicationInfo info = TestUtils.makeApplicationInfo();
+        info.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.debug_domain, info);
         ApplicationConfig appConfig = new ApplicationConfig(source);
         NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
         Set<TrustAnchor> anchors = config.getTrustAnchors();
@@ -357,7 +380,8 @@
 
     private void testBadConfig(int configId) throws Exception {
         try {
-            XmlConfigSource source = new XmlConfigSource(getContext(), configId);
+            XmlConfigSource source = new XmlConfigSource(getContext(), configId,
+                    TestUtils.makeApplicationInfo());
             ApplicationConfig appConfig = new ApplicationConfig(source);
             appConfig.getConfigForHostname("android.com");
             fail("Bad config " + getContext().getResources().getResourceName(configId)
@@ -393,7 +417,8 @@
     }
 
     public void testTrustManagerKeystore() throws Exception {
-        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.bad_pin, true);
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.bad_pin,
+                TestUtils.makeApplicationInfo());
         ApplicationConfig appConfig = new ApplicationConfig(source);
         Provider provider = new NetworkSecurityConfigProvider();
         TrustManagerFactory tmf =
@@ -415,7 +440,9 @@
     }
 
     public void testDebugDedup() throws Exception {
-        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.override_dedup, true);
+        ApplicationInfo info = TestUtils.makeApplicationInfo();
+        info.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.override_dedup, info);
         ApplicationConfig appConfig = new ApplicationConfig(source);
         assertTrue(appConfig.hasPerDomainConfigs());
         // Check android.com.
@@ -433,15 +460,18 @@
     }
 
     public void testExtraDebugResource() throws Exception {
+        ApplicationInfo info = TestUtils.makeApplicationInfo();
+        info.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
         XmlConfigSource source =
-                new XmlConfigSource(getContext(), R.xml.extra_debug_resource, true);
+                new XmlConfigSource(getContext(), R.xml.extra_debug_resource, info);
         ApplicationConfig appConfig = new ApplicationConfig(source);
         assertFalse(appConfig.hasPerDomainConfigs());
         NetworkSecurityConfig config = appConfig.getConfigForHostname("");
         MoreAsserts.assertNotEmpty(config.getTrustAnchors());
 
         // Check that the _debug file is ignored if debug is false.
-        source = new XmlConfigSource(getContext(), R.xml.extra_debug_resource, false);
+        source = new XmlConfigSource(getContext(), R.xml.extra_debug_resource,
+                TestUtils.makeApplicationInfo());
         appConfig = new ApplicationConfig(source);
         assertFalse(appConfig.hasPerDomainConfigs());
         config = appConfig.getConfigForHostname("");
@@ -451,12 +481,15 @@
     public void testExtraDebugResourceIgnored() throws Exception {
         // Verify that parsing the extra debug config resource fails only when debugging is true.
         XmlConfigSource source =
-                new XmlConfigSource(getContext(), R.xml.bad_extra_debug_resource, false);
+                new XmlConfigSource(getContext(), R.xml.bad_extra_debug_resource,
+                        TestUtils.makeApplicationInfo());
         ApplicationConfig appConfig = new ApplicationConfig(source);
         // Force parsing the config file.
         appConfig.getConfigForHostname("");
 
-        source = new XmlConfigSource(getContext(), R.xml.bad_extra_debug_resource, true);
+        ApplicationInfo info = TestUtils.makeApplicationInfo();
+        info.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
+        source = new XmlConfigSource(getContext(), R.xml.bad_extra_debug_resource, info);
         appConfig = new ApplicationConfig(source);
         try {
             appConfig.getConfigForHostname("");
@@ -467,7 +500,8 @@
 
     public void testDomainWhitespaceTrimming() throws Exception {
         XmlConfigSource source =
-                new XmlConfigSource(getContext(), R.xml.domain_whitespace, false);
+                new XmlConfigSource(getContext(), R.xml.domain_whitespace,
+                        TestUtils.makeApplicationInfo());
         ApplicationConfig appConfig = new ApplicationConfig(source);
         NetworkSecurityConfig defaultConfig = appConfig.getConfigForHostname("");
         MoreAsserts.assertNotEqual(defaultConfig, appConfig.getConfigForHostname("developer.android.com"));
diff --git a/tests/net/java/android/net/IpSecManagerTest.java b/tests/net/java/android/net/IpSecManagerTest.java
index 9f31d27..ccb0f3b 100644
--- a/tests/net/java/android/net/IpSecManagerTest.java
+++ b/tests/net/java/android/net/IpSecManagerTest.java
@@ -31,19 +31,21 @@
 import static org.mockito.Mockito.when;
 
 import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.system.Os;
-import android.test.AndroidTestCase;
+
 import com.android.server.IpSecService;
+
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
 
 /** Unit tests for {@link IpSecManager}. */
 @SmallTest
-@RunWith(JUnit4.class)
+@RunWith(AndroidJUnit4.class)
 public class IpSecManagerTest {
 
     private static final int TEST_UDP_ENCAP_PORT = 34567;
diff --git a/tests/net/java/android/net/LinkPropertiesTest.java b/tests/net/java/android/net/LinkPropertiesTest.java
new file mode 100644
index 0000000..52da79a
--- /dev/null
+++ b/tests/net/java/android/net/LinkPropertiesTest.java
@@ -0,0 +1,781 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+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 android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.LinkProperties.CompareResult;
+import android.net.LinkProperties.ProvisioningChange;
+import android.net.RouteInfo;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.system.OsConstants;
+import android.util.ArraySet;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LinkPropertiesTest {
+    private static InetAddress ADDRV4 = NetworkUtils.numericToInetAddress("75.208.6.1");
+    private static InetAddress ADDRV6 = NetworkUtils.numericToInetAddress(
+            "2001:0db8:85a3:0000:0000:8a2e:0370:7334");
+    private static InetAddress DNS1 = NetworkUtils.numericToInetAddress("75.208.7.1");
+    private static InetAddress DNS2 = NetworkUtils.numericToInetAddress("69.78.7.1");
+    private static InetAddress DNS6 = NetworkUtils.numericToInetAddress("2001:4860:4860::8888");
+    private static InetAddress GATEWAY1 = NetworkUtils.numericToInetAddress("75.208.8.1");
+    private static InetAddress GATEWAY2 = NetworkUtils.numericToInetAddress("69.78.8.1");
+    private static InetAddress GATEWAY61 = NetworkUtils.numericToInetAddress("fe80::6:0000:613");
+    private static InetAddress GATEWAY62 = NetworkUtils.numericToInetAddress("fe80::6:2222");
+    private static String NAME = "qmi0";
+    private static int MTU = 1500;
+
+    private static LinkAddress LINKADDRV4 = new LinkAddress(ADDRV4, 32);
+    private static LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128);
+    private static LinkAddress LINKADDRV6LINKLOCAL = new LinkAddress("fe80::1/64");
+
+    // TODO: replace all calls to NetworkUtils.numericToInetAddress with calls to this method.
+    private InetAddress Address(String addrString) {
+        return NetworkUtils.numericToInetAddress(addrString);
+    }
+
+    public void assertLinkPropertiesEqual(LinkProperties source, LinkProperties target) {
+        // Check implementation of equals(), element by element.
+        assertTrue(source.isIdenticalInterfaceName(target));
+        assertTrue(target.isIdenticalInterfaceName(source));
+
+        assertTrue(source.isIdenticalAddresses(target));
+        assertTrue(target.isIdenticalAddresses(source));
+
+        assertTrue(source.isIdenticalDnses(target));
+        assertTrue(target.isIdenticalDnses(source));
+
+        assertTrue(source.isIdenticalRoutes(target));
+        assertTrue(target.isIdenticalRoutes(source));
+
+        assertTrue(source.isIdenticalHttpProxy(target));
+        assertTrue(target.isIdenticalHttpProxy(source));
+
+        assertTrue(source.isIdenticalStackedLinks(target));
+        assertTrue(target.isIdenticalStackedLinks(source));
+
+        assertTrue(source.isIdenticalMtu(target));
+        assertTrue(target.isIdenticalMtu(source));
+
+        // Check result of equals().
+        assertTrue(source.equals(target));
+        assertTrue(target.equals(source));
+
+        // Check hashCode.
+        assertEquals(source.hashCode(), target.hashCode());
+    }
+
+    @Test
+    public void testEqualsNull() {
+        LinkProperties source = new LinkProperties();
+        LinkProperties target = new LinkProperties();
+
+        assertFalse(source == target);
+        assertLinkPropertiesEqual(source, target);
+    }
+
+    @Test
+    public void testEqualsSameOrder() throws Exception {
+        LinkProperties source = new LinkProperties();
+        source.setInterfaceName(NAME);
+        // set 2 link addresses
+        source.addLinkAddress(LINKADDRV4);
+        source.addLinkAddress(LINKADDRV6);
+        // set 2 dnses
+        source.addDnsServer(DNS1);
+        source.addDnsServer(DNS2);
+        // set 2 gateways
+        source.addRoute(new RouteInfo(GATEWAY1));
+        source.addRoute(new RouteInfo(GATEWAY2));
+        source.setMtu(MTU);
+
+        LinkProperties target = new LinkProperties();
+
+        // All fields are same
+        target.setInterfaceName(NAME);
+        target.addLinkAddress(LINKADDRV4);
+        target.addLinkAddress(LINKADDRV6);
+        target.addDnsServer(DNS1);
+        target.addDnsServer(DNS2);
+        target.addRoute(new RouteInfo(GATEWAY1));
+        target.addRoute(new RouteInfo(GATEWAY2));
+        target.setMtu(MTU);
+
+        assertLinkPropertiesEqual(source, target);
+
+        target.clear();
+        // change Interface Name
+        target.setInterfaceName("qmi1");
+        target.addLinkAddress(LINKADDRV4);
+        target.addLinkAddress(LINKADDRV6);
+        target.addDnsServer(DNS1);
+        target.addDnsServer(DNS2);
+        target.addRoute(new RouteInfo(GATEWAY1));
+        target.addRoute(new RouteInfo(GATEWAY2));
+        target.setMtu(MTU);
+        assertFalse(source.equals(target));
+
+        target.clear();
+        target.setInterfaceName(NAME);
+        // change link addresses
+        target.addLinkAddress(new LinkAddress(
+                NetworkUtils.numericToInetAddress("75.208.6.2"), 32));
+        target.addLinkAddress(LINKADDRV6);
+        target.addDnsServer(DNS1);
+        target.addDnsServer(DNS2);
+        target.addRoute(new RouteInfo(GATEWAY1));
+        target.addRoute(new RouteInfo(GATEWAY2));
+        target.setMtu(MTU);
+        assertFalse(source.equals(target));
+
+        target.clear();
+        target.setInterfaceName(NAME);
+        target.addLinkAddress(LINKADDRV4);
+        target.addLinkAddress(LINKADDRV6);
+        // change dnses
+        target.addDnsServer(NetworkUtils.numericToInetAddress("75.208.7.2"));
+        target.addDnsServer(DNS2);
+        target.addRoute(new RouteInfo(GATEWAY1));
+        target.addRoute(new RouteInfo(GATEWAY2));
+        target.setMtu(MTU);
+        assertFalse(source.equals(target));
+
+        target.clear();
+        target.setInterfaceName(NAME);
+        target.addLinkAddress(LINKADDRV4);
+        target.addLinkAddress(LINKADDRV6);
+        target.addDnsServer(DNS1);
+        target.addDnsServer(DNS2);
+        // change gateway
+        target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2")));
+        target.addRoute(new RouteInfo(GATEWAY2));
+        target.setMtu(MTU);
+        assertFalse(source.equals(target));
+
+        target.clear();
+        target.setInterfaceName(NAME);
+        target.addLinkAddress(LINKADDRV4);
+        target.addLinkAddress(LINKADDRV6);
+        target.addDnsServer(DNS1);
+        target.addDnsServer(DNS2);
+        target.addRoute(new RouteInfo(GATEWAY1));
+        target.addRoute(new RouteInfo(GATEWAY2));
+        // change mtu
+        target.setMtu(1440);
+        assertFalse(source.equals(target));
+    }
+
+    @Test
+    public void testEqualsDifferentOrder() throws Exception {
+        LinkProperties source = new LinkProperties();
+        source.setInterfaceName(NAME);
+        // set 2 link addresses
+        source.addLinkAddress(LINKADDRV4);
+        source.addLinkAddress(LINKADDRV6);
+        // set 2 dnses
+        source.addDnsServer(DNS1);
+        source.addDnsServer(DNS2);
+        // set 2 gateways
+        source.addRoute(new RouteInfo(GATEWAY1));
+        source.addRoute(new RouteInfo(GATEWAY2));
+        source.setMtu(MTU);
+
+        LinkProperties target = new LinkProperties();
+        // Exchange order
+        target.setInterfaceName(NAME);
+        target.addLinkAddress(LINKADDRV6);
+        target.addLinkAddress(LINKADDRV4);
+        target.addDnsServer(DNS2);
+        target.addDnsServer(DNS1);
+        target.addRoute(new RouteInfo(GATEWAY2));
+        target.addRoute(new RouteInfo(GATEWAY1));
+        target.setMtu(MTU);
+
+        assertLinkPropertiesEqual(source, target);
+    }
+
+    @Test
+    public void testEqualsDuplicated() throws Exception {
+        LinkProperties source = new LinkProperties();
+        // set 3 link addresses, eg, [A, A, B]
+        source.addLinkAddress(LINKADDRV4);
+        source.addLinkAddress(LINKADDRV4);
+        source.addLinkAddress(LINKADDRV6);
+
+        LinkProperties target = new LinkProperties();
+        // set 3 link addresses, eg, [A, B, B]
+        target.addLinkAddress(LINKADDRV4);
+        target.addLinkAddress(LINKADDRV6);
+        target.addLinkAddress(LINKADDRV6);
+
+        assertLinkPropertiesEqual(source, target);
+    }
+
+    private void assertAllRoutesHaveInterface(String iface, LinkProperties lp) {
+        for (RouteInfo r : lp.getRoutes()) {
+            assertEquals(iface, r.getInterface());
+        }
+    }
+
+    @Test
+    public void testRouteInterfaces() {
+        LinkAddress prefix = new LinkAddress(
+            NetworkUtils.numericToInetAddress("2001:db8::"), 32);
+        InetAddress address = ADDRV6;
+
+        // Add a route with no interface to a LinkProperties with no interface. No errors.
+        LinkProperties lp = new LinkProperties();
+        RouteInfo r = new RouteInfo(prefix, address, null);
+        assertTrue(lp.addRoute(r));
+        assertEquals(1, lp.getRoutes().size());
+        assertAllRoutesHaveInterface(null, lp);
+
+        // Adding the same route twice has no effect.
+        assertFalse(lp.addRoute(r));
+        assertEquals(1, lp.getRoutes().size());
+
+        // Add a route with an interface. Expect an exception.
+        r = new RouteInfo(prefix, address, "wlan0");
+        try {
+          lp.addRoute(r);
+          fail("Adding wlan0 route to LP with no interface, expect exception");
+        } catch (IllegalArgumentException expected) {}
+
+        // Change the interface name. All the routes should change their interface name too.
+        lp.setInterfaceName("rmnet0");
+        assertAllRoutesHaveInterface("rmnet0", lp);
+
+        // Now add a route with the wrong interface. This causes an exception too.
+        try {
+          lp.addRoute(r);
+          fail("Adding wlan0 route to rmnet0 LP, expect exception");
+        } catch (IllegalArgumentException expected) {}
+
+        // If the interface name matches, the route is added.
+        r = new RouteInfo(prefix, null, "wlan0");
+        lp.setInterfaceName("wlan0");
+        lp.addRoute(r);
+        assertEquals(2, lp.getRoutes().size());
+        assertAllRoutesHaveInterface("wlan0", lp);
+
+        // Routes with null interfaces are converted to wlan0.
+        r = RouteInfo.makeHostRoute(ADDRV6, null);
+        lp.addRoute(r);
+        assertEquals(3, lp.getRoutes().size());
+        assertAllRoutesHaveInterface("wlan0", lp);
+
+        // Check comparisons work.
+        LinkProperties lp2 = new LinkProperties(lp);
+        assertAllRoutesHaveInterface("wlan0", lp);
+        assertEquals(0, lp.compareAllRoutes(lp2).added.size());
+        assertEquals(0, lp.compareAllRoutes(lp2).removed.size());
+
+        lp2.setInterfaceName("p2p0");
+        assertAllRoutesHaveInterface("p2p0", lp2);
+        assertEquals(3, lp.compareAllRoutes(lp2).added.size());
+        assertEquals(3, lp.compareAllRoutes(lp2).removed.size());
+    }
+
+    @Test
+    public void testStackedInterfaces() {
+        LinkProperties rmnet0 = new LinkProperties();
+        rmnet0.setInterfaceName("rmnet0");
+        rmnet0.addLinkAddress(LINKADDRV6);
+
+        LinkProperties clat4 = new LinkProperties();
+        clat4.setInterfaceName("clat4");
+        clat4.addLinkAddress(LINKADDRV4);
+
+        assertEquals(0, rmnet0.getStackedLinks().size());
+        assertEquals(1, rmnet0.getAddresses().size());
+        assertEquals(1, rmnet0.getLinkAddresses().size());
+        assertEquals(1, rmnet0.getAllAddresses().size());
+        assertEquals(1, rmnet0.getAllLinkAddresses().size());
+
+        rmnet0.addStackedLink(clat4);
+        assertEquals(1, rmnet0.getStackedLinks().size());
+        assertEquals(1, rmnet0.getAddresses().size());
+        assertEquals(1, rmnet0.getLinkAddresses().size());
+        assertEquals(2, rmnet0.getAllAddresses().size());
+        assertEquals(2, rmnet0.getAllLinkAddresses().size());
+
+        rmnet0.addStackedLink(clat4);
+        assertEquals(1, rmnet0.getStackedLinks().size());
+        assertEquals(1, rmnet0.getAddresses().size());
+        assertEquals(1, rmnet0.getLinkAddresses().size());
+        assertEquals(2, rmnet0.getAllAddresses().size());
+        assertEquals(2, rmnet0.getAllLinkAddresses().size());
+
+        assertEquals(0, clat4.getStackedLinks().size());
+
+        // Modify an item in the returned collection to see what happens.
+        for (LinkProperties link : rmnet0.getStackedLinks()) {
+            if (link.getInterfaceName().equals("clat4")) {
+               link.setInterfaceName("newname");
+            }
+        }
+        for (LinkProperties link : rmnet0.getStackedLinks()) {
+            assertFalse("newname".equals(link.getInterfaceName()));
+        }
+
+        assertTrue(rmnet0.removeStackedLink("clat4"));
+        assertEquals(0, rmnet0.getStackedLinks().size());
+        assertEquals(1, rmnet0.getAddresses().size());
+        assertEquals(1, rmnet0.getLinkAddresses().size());
+        assertEquals(1, rmnet0.getAllAddresses().size());
+        assertEquals(1, rmnet0.getAllLinkAddresses().size());
+
+        assertFalse(rmnet0.removeStackedLink("clat4"));
+    }
+
+    private LinkAddress getFirstLinkAddress(LinkProperties lp) {
+        return lp.getLinkAddresses().iterator().next();
+    }
+
+    @Test
+    public void testAddressMethods() {
+        LinkProperties lp = new LinkProperties();
+
+        // No addresses.
+        assertFalse(lp.hasIPv4Address());
+        assertFalse(lp.hasGlobalIPv6Address());
+
+        // Addresses on stacked links don't count.
+        LinkProperties stacked = new LinkProperties();
+        stacked.setInterfaceName("stacked");
+        lp.addStackedLink(stacked);
+        stacked.addLinkAddress(LINKADDRV4);
+        stacked.addLinkAddress(LINKADDRV6);
+        assertTrue(stacked.hasIPv4Address());
+        assertTrue(stacked.hasGlobalIPv6Address());
+        assertFalse(lp.hasIPv4Address());
+        assertFalse(lp.hasGlobalIPv6Address());
+        lp.removeStackedLink("stacked");
+        assertFalse(lp.hasIPv4Address());
+        assertFalse(lp.hasGlobalIPv6Address());
+
+        // Addresses on the base link.
+        // Check the return values of hasIPvXAddress and ensure the add/remove methods return true
+        // iff something changes.
+        assertEquals(0, lp.getLinkAddresses().size());
+        assertTrue(lp.addLinkAddress(LINKADDRV6));
+        assertEquals(1, lp.getLinkAddresses().size());
+        assertFalse(lp.hasIPv4Address());
+        assertTrue(lp.hasGlobalIPv6Address());
+
+        assertTrue(lp.removeLinkAddress(LINKADDRV6));
+        assertEquals(0, lp.getLinkAddresses().size());
+
+        assertTrue(lp.addLinkAddress(LINKADDRV6LINKLOCAL));
+        assertEquals(1, lp.getLinkAddresses().size());
+        assertFalse(lp.hasGlobalIPv6Address());
+
+        assertTrue(lp.addLinkAddress(LINKADDRV4));
+        assertEquals(2, lp.getLinkAddresses().size());
+        assertTrue(lp.hasIPv4Address());
+        assertFalse(lp.hasGlobalIPv6Address());
+
+        assertTrue(lp.addLinkAddress(LINKADDRV6));
+        assertEquals(3, lp.getLinkAddresses().size());
+        assertTrue(lp.hasIPv4Address());
+        assertTrue(lp.hasGlobalIPv6Address());
+
+        assertTrue(lp.removeLinkAddress(LINKADDRV6LINKLOCAL));
+        assertEquals(2, lp.getLinkAddresses().size());
+        assertTrue(lp.hasIPv4Address());
+        assertTrue(lp.hasGlobalIPv6Address());
+
+        // Adding an address twice has no effect.
+        // Removing an address that's not present has no effect.
+        assertFalse(lp.addLinkAddress(LINKADDRV4));
+        assertEquals(2, lp.getLinkAddresses().size());
+        assertTrue(lp.hasIPv4Address());
+        assertTrue(lp.removeLinkAddress(LINKADDRV4));
+        assertEquals(1, lp.getLinkAddresses().size());
+        assertFalse(lp.hasIPv4Address());
+        assertFalse(lp.removeLinkAddress(LINKADDRV4));
+        assertEquals(1, lp.getLinkAddresses().size());
+
+        // Adding an address that's already present but with different properties causes the
+        // existing address to be updated and returns true.
+        // Start with only LINKADDRV6.
+        assertEquals(1, lp.getLinkAddresses().size());
+        assertEquals(LINKADDRV6, getFirstLinkAddress(lp));
+
+        // Create a LinkAddress object for the same address, but with different flags.
+        LinkAddress deprecated = new LinkAddress(ADDRV6, 128,
+                OsConstants.IFA_F_DEPRECATED, OsConstants.RT_SCOPE_UNIVERSE);
+        assertTrue(deprecated.isSameAddressAs(LINKADDRV6));
+        assertFalse(deprecated.equals(LINKADDRV6));
+
+        // Check that adding it updates the existing address instead of adding a new one.
+        assertTrue(lp.addLinkAddress(deprecated));
+        assertEquals(1, lp.getLinkAddresses().size());
+        assertEquals(deprecated, getFirstLinkAddress(lp));
+        assertFalse(LINKADDRV6.equals(getFirstLinkAddress(lp)));
+
+        // Removing LINKADDRV6 removes deprecated, because removing addresses ignores properties.
+        assertTrue(lp.removeLinkAddress(LINKADDRV6));
+        assertEquals(0, lp.getLinkAddresses().size());
+    }
+
+    @Test
+    public void testSetLinkAddresses() {
+        LinkProperties lp = new LinkProperties();
+        lp.addLinkAddress(LINKADDRV4);
+        lp.addLinkAddress(LINKADDRV6);
+
+        LinkProperties lp2 = new LinkProperties();
+        lp2.addLinkAddress(LINKADDRV6);
+
+        assertFalse(lp.equals(lp2));
+
+        lp2.setLinkAddresses(lp.getLinkAddresses());
+        assertTrue(lp.equals(lp));
+    }
+
+    @Test
+    public void testIsProvisioned() {
+        LinkProperties lp4 = new LinkProperties();
+        assertFalse("v4only:empty", lp4.isProvisioned());
+        lp4.addLinkAddress(LINKADDRV4);
+        assertFalse("v4only:addr-only", lp4.isProvisioned());
+        lp4.addDnsServer(DNS1);
+        assertFalse("v4only:addr+dns", lp4.isProvisioned());
+        lp4.addRoute(new RouteInfo(GATEWAY1));
+        assertTrue("v4only:addr+dns+route", lp4.isProvisioned());
+        assertTrue("v4only:addr+dns+route", lp4.isIPv4Provisioned());
+        assertFalse("v4only:addr+dns+route", lp4.isIPv6Provisioned());
+
+        LinkProperties lp6 = new LinkProperties();
+        assertFalse("v6only:empty", lp6.isProvisioned());
+        lp6.addLinkAddress(LINKADDRV6LINKLOCAL);
+        assertFalse("v6only:fe80-only", lp6.isProvisioned());
+        lp6.addDnsServer(DNS6);
+        assertFalse("v6only:fe80+dns", lp6.isProvisioned());
+        lp6.addRoute(new RouteInfo(GATEWAY61));
+        assertFalse("v6only:fe80+dns+route", lp6.isProvisioned());
+        lp6.addLinkAddress(LINKADDRV6);
+        assertTrue("v6only:fe80+global+dns+route", lp6.isIPv6Provisioned());
+        assertTrue("v6only:fe80+global+dns+route", lp6.isProvisioned());
+        lp6.removeLinkAddress(LINKADDRV6LINKLOCAL);
+        assertFalse("v6only:global+dns+route", lp6.isIPv4Provisioned());
+        assertTrue("v6only:global+dns+route", lp6.isIPv6Provisioned());
+        assertTrue("v6only:global+dns+route", lp6.isProvisioned());
+
+        LinkProperties lp46 = new LinkProperties();
+        lp46.addLinkAddress(LINKADDRV4);
+        lp46.addLinkAddress(LINKADDRV6);
+        lp46.addDnsServer(DNS1);
+        lp46.addDnsServer(DNS6);
+        assertFalse("dualstack:missing-routes", lp46.isProvisioned());
+        lp46.addRoute(new RouteInfo(GATEWAY1));
+        assertTrue("dualstack:v4-provisioned", lp46.isIPv4Provisioned());
+        assertFalse("dualstack:v4-provisioned", lp46.isIPv6Provisioned());
+        assertTrue("dualstack:v4-provisioned", lp46.isProvisioned());
+        lp46.addRoute(new RouteInfo(GATEWAY61));
+        assertTrue("dualstack:both-provisioned", lp46.isIPv4Provisioned());
+        assertTrue("dualstack:both-provisioned", lp46.isIPv6Provisioned());
+        assertTrue("dualstack:both-provisioned", lp46.isProvisioned());
+
+        // A link with an IPv6 address and default route, but IPv4 DNS server.
+        LinkProperties mixed = new LinkProperties();
+        mixed.addLinkAddress(LINKADDRV6);
+        mixed.addDnsServer(DNS1);
+        mixed.addRoute(new RouteInfo(GATEWAY61));
+        assertFalse("mixed:addr6+route6+dns4", mixed.isIPv4Provisioned());
+        assertFalse("mixed:addr6+route6+dns4", mixed.isIPv6Provisioned());
+        assertFalse("mixed:addr6+route6+dns4", mixed.isProvisioned());
+    }
+
+    @Test
+    public void testCompareProvisioning() {
+        LinkProperties v4lp = new LinkProperties();
+        v4lp.addLinkAddress(LINKADDRV4);
+        v4lp.addRoute(new RouteInfo(GATEWAY1));
+        v4lp.addDnsServer(DNS1);
+        assertTrue(v4lp.isProvisioned());
+
+        LinkProperties v4r = new LinkProperties(v4lp);
+        v4r.removeDnsServer(DNS1);
+        assertFalse(v4r.isProvisioned());
+
+        assertEquals(ProvisioningChange.STILL_NOT_PROVISIONED,
+                LinkProperties.compareProvisioning(v4r, v4r));
+        assertEquals(ProvisioningChange.LOST_PROVISIONING,
+                LinkProperties.compareProvisioning(v4lp, v4r));
+        assertEquals(ProvisioningChange.GAINED_PROVISIONING,
+                LinkProperties.compareProvisioning(v4r, v4lp));
+        assertEquals(ProvisioningChange.STILL_PROVISIONED,
+                LinkProperties.compareProvisioning(v4lp, v4lp));
+
+        // Check that losing IPv4 provisioning on a dualstack network is
+        // seen as a total loss of provisioning.
+        LinkProperties v6lp = new LinkProperties();
+        v6lp.addLinkAddress(LINKADDRV6);
+        v6lp.addRoute(new RouteInfo(GATEWAY61));
+        v6lp.addDnsServer(DNS6);
+        assertFalse(v6lp.isIPv4Provisioned());
+        assertTrue(v6lp.isIPv6Provisioned());
+        assertTrue(v6lp.isProvisioned());
+
+        LinkProperties v46lp = new LinkProperties(v6lp);
+        v46lp.addLinkAddress(LINKADDRV4);
+        v46lp.addRoute(new RouteInfo(GATEWAY1));
+        v46lp.addDnsServer(DNS1);
+        assertTrue(v46lp.isIPv4Provisioned());
+        assertTrue(v46lp.isIPv6Provisioned());
+        assertTrue(v46lp.isProvisioned());
+
+        assertEquals(ProvisioningChange.STILL_PROVISIONED,
+                LinkProperties.compareProvisioning(v4lp, v46lp));
+        assertEquals(ProvisioningChange.STILL_PROVISIONED,
+                LinkProperties.compareProvisioning(v6lp, v46lp));
+        assertEquals(ProvisioningChange.LOST_PROVISIONING,
+                LinkProperties.compareProvisioning(v46lp, v6lp));
+        assertEquals(ProvisioningChange.LOST_PROVISIONING,
+                LinkProperties.compareProvisioning(v46lp, v4lp));
+
+        // Check that losing and gaining a secondary router does not change
+        // the provisioning status.
+        LinkProperties v6lp2 = new LinkProperties(v6lp);
+        v6lp2.addRoute(new RouteInfo(GATEWAY62));
+        assertTrue(v6lp2.isProvisioned());
+
+        assertEquals(ProvisioningChange.STILL_PROVISIONED,
+                LinkProperties.compareProvisioning(v6lp2, v6lp));
+        assertEquals(ProvisioningChange.STILL_PROVISIONED,
+                LinkProperties.compareProvisioning(v6lp, v6lp2));
+    }
+
+    @Test
+    public void testIsReachable() {
+        final LinkProperties v4lp = new LinkProperties();
+        assertFalse(v4lp.isReachable(DNS1));
+        assertFalse(v4lp.isReachable(DNS2));
+
+        // Add an on-link route, making the on-link DNS server reachable,
+        // but there is still no IPv4 address.
+        assertTrue(v4lp.addRoute(new RouteInfo(
+                new IpPrefix(NetworkUtils.numericToInetAddress("75.208.0.0"), 16))));
+        assertFalse(v4lp.isReachable(DNS1));
+        assertFalse(v4lp.isReachable(DNS2));
+
+        // Adding an IPv4 address (right now, any IPv4 address) means we use
+        // the routes to compute likely reachability.
+        assertTrue(v4lp.addLinkAddress(new LinkAddress(ADDRV4, 16)));
+        assertTrue(v4lp.isReachable(DNS1));
+        assertFalse(v4lp.isReachable(DNS2));
+
+        // Adding a default route makes the off-link DNS server reachable.
+        assertTrue(v4lp.addRoute(new RouteInfo(GATEWAY1)));
+        assertTrue(v4lp.isReachable(DNS1));
+        assertTrue(v4lp.isReachable(DNS2));
+
+        final LinkProperties v6lp = new LinkProperties();
+        final InetAddress kLinkLocalDns = NetworkUtils.numericToInetAddress("fe80::6:1");
+        final InetAddress kLinkLocalDnsWithScope = NetworkUtils.numericToInetAddress("fe80::6:2%43");
+        final InetAddress kOnLinkDns = NetworkUtils.numericToInetAddress("2001:db8:85a3::53");
+        assertFalse(v6lp.isReachable(kLinkLocalDns));
+        assertFalse(v6lp.isReachable(kLinkLocalDnsWithScope));
+        assertFalse(v6lp.isReachable(kOnLinkDns));
+        assertFalse(v6lp.isReachable(DNS6));
+
+        // Add a link-local route, making the link-local DNS servers reachable. Because
+        // we assume the presence of an IPv6 link-local address, link-local DNS servers
+        // are considered reachable, but only those with a non-zero scope identifier.
+        assertTrue(v6lp.addRoute(new RouteInfo(
+                new IpPrefix(NetworkUtils.numericToInetAddress("fe80::"), 64))));
+        assertFalse(v6lp.isReachable(kLinkLocalDns));
+        assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
+        assertFalse(v6lp.isReachable(kOnLinkDns));
+        assertFalse(v6lp.isReachable(DNS6));
+
+        // Add a link-local address--nothing changes.
+        assertTrue(v6lp.addLinkAddress(LINKADDRV6LINKLOCAL));
+        assertFalse(v6lp.isReachable(kLinkLocalDns));
+        assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
+        assertFalse(v6lp.isReachable(kOnLinkDns));
+        assertFalse(v6lp.isReachable(DNS6));
+
+        // Add a global route on link, but no global address yet. DNS servers reachable
+        // via a route that doesn't require a gateway: give them the benefit of the
+        // doubt and hope the link-local source address suffices for communication.
+        assertTrue(v6lp.addRoute(new RouteInfo(
+                new IpPrefix(NetworkUtils.numericToInetAddress("2001:db8:85a3::"), 64))));
+        assertFalse(v6lp.isReachable(kLinkLocalDns));
+        assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
+        assertTrue(v6lp.isReachable(kOnLinkDns));
+        assertFalse(v6lp.isReachable(DNS6));
+
+        // Add a global address; the on-link global address DNS server is (still)
+        // presumed reachable.
+        assertTrue(v6lp.addLinkAddress(new LinkAddress(ADDRV6, 64)));
+        assertFalse(v6lp.isReachable(kLinkLocalDns));
+        assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
+        assertTrue(v6lp.isReachable(kOnLinkDns));
+        assertFalse(v6lp.isReachable(DNS6));
+
+        // Adding a default route makes the off-link DNS server reachable.
+        assertTrue(v6lp.addRoute(new RouteInfo(GATEWAY62)));
+        assertFalse(v6lp.isReachable(kLinkLocalDns));
+        assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
+        assertTrue(v6lp.isReachable(kOnLinkDns));
+        assertTrue(v6lp.isReachable(DNS6));
+
+        // Check isReachable on stacked links. This requires that the source IP address be assigned
+        // on the interface returned by the route lookup.
+        LinkProperties stacked = new LinkProperties();
+
+        // Can't add a stacked link without an interface name.
+        stacked.setInterfaceName("v4-test0");
+        v6lp.addStackedLink(stacked);
+
+        InetAddress stackedAddress = Address("192.0.0.4");
+        LinkAddress stackedLinkAddress = new LinkAddress(stackedAddress, 32);
+        assertFalse(v6lp.isReachable(stackedAddress));
+        stacked.addLinkAddress(stackedLinkAddress);
+        assertFalse(v6lp.isReachable(stackedAddress));
+        stacked.addRoute(new RouteInfo(stackedLinkAddress));
+        assertTrue(stacked.isReachable(stackedAddress));
+        assertTrue(v6lp.isReachable(stackedAddress));
+
+        assertFalse(v6lp.isReachable(DNS1));
+        stacked.addRoute(new RouteInfo((IpPrefix) null, stackedAddress));
+        assertTrue(v6lp.isReachable(DNS1));
+    }
+
+    @Test
+    public void testLinkPropertiesEnsureDirectlyConnectedRoutes() {
+        // IPv4 case: no route added initially
+        LinkProperties rmnet0 = new LinkProperties();
+        rmnet0.setInterfaceName("rmnet0");
+        rmnet0.addLinkAddress(new LinkAddress("10.0.0.2/8"));
+        RouteInfo directRoute0 = new RouteInfo(new IpPrefix("10.0.0.0/8"), null,
+                rmnet0.getInterfaceName());
+
+        // Since no routes is added explicitly, getAllRoutes() should return empty.
+        assertTrue(rmnet0.getAllRoutes().isEmpty());
+        rmnet0.ensureDirectlyConnectedRoutes();
+        // ensureDirectlyConnectedRoutes() should have added the missing local route.
+        assertEqualRoutes(Collections.singletonList(directRoute0), rmnet0.getAllRoutes());
+
+        // IPv4 case: both direct and default routes added initially
+        LinkProperties rmnet1 = new LinkProperties();
+        rmnet1.setInterfaceName("rmnet1");
+        rmnet1.addLinkAddress(new LinkAddress("10.0.0.3/8"));
+        RouteInfo defaultRoute1 = new RouteInfo((IpPrefix) null,
+                NetworkUtils.numericToInetAddress("10.0.0.1"), rmnet1.getInterfaceName());
+        RouteInfo directRoute1 = new RouteInfo(new IpPrefix("10.0.0.0/8"), null,
+                rmnet1.getInterfaceName());
+        rmnet1.addRoute(defaultRoute1);
+        rmnet1.addRoute(directRoute1);
+
+        // Check added routes
+        assertEqualRoutes(Arrays.asList(defaultRoute1, directRoute1), rmnet1.getAllRoutes());
+        // ensureDirectlyConnectedRoutes() shouldn't change the routes since direct connected
+        // route is already part of the configuration.
+        rmnet1.ensureDirectlyConnectedRoutes();
+        assertEqualRoutes(Arrays.asList(defaultRoute1, directRoute1), rmnet1.getAllRoutes());
+
+        // IPv6 case: only default routes added initially
+        LinkProperties rmnet2 = new LinkProperties();
+        rmnet2.setInterfaceName("rmnet2");
+        rmnet2.addLinkAddress(new LinkAddress("fe80::cafe/64"));
+        rmnet2.addLinkAddress(new LinkAddress("2001:db8::2/64"));
+        RouteInfo defaultRoute2 = new RouteInfo((IpPrefix) null,
+                NetworkUtils.numericToInetAddress("2001:db8::1"), rmnet2.getInterfaceName());
+        RouteInfo directRoute2 = new RouteInfo(new IpPrefix("2001:db8::/64"), null,
+                rmnet2.getInterfaceName());
+        RouteInfo linkLocalRoute2 = new RouteInfo(new IpPrefix("fe80::/64"), null,
+                rmnet2.getInterfaceName());
+        rmnet2.addRoute(defaultRoute2);
+
+        assertEqualRoutes(Arrays.asList(defaultRoute2), rmnet2.getAllRoutes());
+        rmnet2.ensureDirectlyConnectedRoutes();
+        assertEqualRoutes(Arrays.asList(defaultRoute2, directRoute2, linkLocalRoute2),
+                rmnet2.getAllRoutes());
+
+        // Corner case: no interface name
+        LinkProperties rmnet3 = new LinkProperties();
+        rmnet3.addLinkAddress(new LinkAddress("192.168.0.2/24"));
+        RouteInfo directRoute3 = new RouteInfo(new IpPrefix("192.168.0.0/24"), null,
+                rmnet3.getInterfaceName());
+
+        assertTrue(rmnet3.getAllRoutes().isEmpty());
+        rmnet3.ensureDirectlyConnectedRoutes();
+        assertEqualRoutes(Collections.singletonList(directRoute3), rmnet3.getAllRoutes());
+
+    }
+
+    @Test
+    public void testCompareResult() {
+        // Either adding or removing items
+        compareResult(Arrays.asList(1, 2, 3, 4), Arrays.asList(1),
+                Arrays.asList(2, 3, 4), new ArrayList<>());
+        compareResult(Arrays.asList(1, 2), Arrays.asList(3, 2, 1, 4),
+                new ArrayList<>(), Arrays.asList(3, 4));
+
+
+        // adding and removing items at the same time
+        compareResult(Arrays.asList(1, 2, 3, 4), Arrays.asList(2, 3, 4, 5),
+                Arrays.asList(1), Arrays.asList(5));
+        compareResult(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6),
+                Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6));
+
+        // null cases
+        compareResult(Arrays.asList(1, 2, 3), null, Arrays.asList(1, 2, 3), new ArrayList<>());
+        compareResult(null, Arrays.asList(3, 2, 1), new ArrayList<>(), Arrays.asList(1, 2, 3));
+        compareResult(null, null, new ArrayList<>(), new ArrayList<>());
+    }
+
+    private void assertEqualRoutes(Collection<RouteInfo> expected, Collection<RouteInfo> actual) {
+        Set<RouteInfo> expectedSet = new ArraySet<>(expected);
+        Set<RouteInfo> actualSet = new ArraySet<>(actual);
+        // Duplicated entries in actual routes are considered failures
+        assertEquals(actual.size(), actualSet.size());
+
+        assertEquals(expectedSet, actualSet);
+    }
+
+    private <T> void compareResult(List<T> oldItems, List<T> newItems, List<T> expectRemoved,
+            List<T> expectAdded) {
+        CompareResult<T> result = new CompareResult<>(oldItems, newItems);
+        assertEquals(new ArraySet<>(expectAdded), new ArraySet<>(result.added));
+        assertEquals(new ArraySet<>(expectRemoved), (new ArraySet<>(result.removed)));
+    }
+}
diff --git a/tests/net/java/android/net/NetworkStatsHistoryTest.java b/tests/net/java/android/net/NetworkStatsHistoryTest.java
index 1c0c14e..301d04d 100644
--- a/tests/net/java/android/net/NetworkStatsHistoryTest.java
+++ b/tests/net/java/android/net/NetworkStatsHistoryTest.java
@@ -32,9 +32,14 @@
 import static android.text.format.DateUtils.SECOND_IN_MILLIS;
 import static android.text.format.DateUtils.WEEK_IN_MILLIS;
 import static android.text.format.DateUtils.YEAR_IN_MILLIS;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.Suppress;
 import android.util.Log;
 
@@ -46,25 +51,31 @@
 import java.io.DataOutputStream;
 import java.util.Random;
 
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
 @SmallTest
-public class NetworkStatsHistoryTest extends AndroidTestCase {
+public class NetworkStatsHistoryTest {
     private static final String TAG = "NetworkStatsHistoryTest";
 
     private static final long TEST_START = 1194220800000L;
 
     private NetworkStatsHistory stats;
 
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
+    @After
+    public void tearDown() throws Exception {
         if (stats != null) {
             assertConsistent(stats);
         }
     }
 
+    @Test
     public void testReadOriginalVersion() throws Exception {
-        final DataInputStream in = new DataInputStream(
-                getContext().getResources().openRawResource(R.raw.history_v1));
+        final Context context = InstrumentationRegistry.getContext();
+        final DataInputStream in =
+                new DataInputStream(context.getResources().openRawResource(R.raw.history_v1));
 
         NetworkStatsHistory.Entry entry = null;
         try {
@@ -88,6 +99,7 @@
         }
     }
 
+    @Test
     public void testRecordSingleBucket() throws Exception {
         final long BUCKET_SIZE = HOUR_IN_MILLIS;
         stats = new NetworkStatsHistory(BUCKET_SIZE);
@@ -100,6 +112,7 @@
         assertValues(stats, 0, SECOND_IN_MILLIS, 1024L, 10L, 2048L, 20L, 2L);
     }
 
+    @Test
     public void testRecordEqualBuckets() throws Exception {
         final long bucketDuration = HOUR_IN_MILLIS;
         stats = new NetworkStatsHistory(bucketDuration);
@@ -114,6 +127,7 @@
         assertValues(stats, 1, HOUR_IN_MILLIS / 2, 512L, 5L, 64L, 1L, 1L);
     }
 
+    @Test
     public void testRecordTouchingBuckets() throws Exception {
         final long BUCKET_SIZE = 15 * MINUTE_IN_MILLIS;
         stats = new NetworkStatsHistory(BUCKET_SIZE);
@@ -134,6 +148,7 @@
         assertValues(stats, 2, 4 * MINUTE_IN_MILLIS, 200L, 400L, 1000L, 2000L, 20L);
     }
 
+    @Test
     public void testRecordGapBuckets() throws Exception {
         final long BUCKET_SIZE = HOUR_IN_MILLIS;
         stats = new NetworkStatsHistory(BUCKET_SIZE);
@@ -165,6 +180,7 @@
         assertValues(stats, 3, SECOND_IN_MILLIS, 64L, 1L, 512L, 8L, 2L);
     }
 
+    @Test
     public void testRecordOverlapBuckets() throws Exception {
         final long BUCKET_SIZE = HOUR_IN_MILLIS;
         stats = new NetworkStatsHistory(BUCKET_SIZE);
@@ -182,6 +198,7 @@
         assertValues(stats, 1, (HOUR_IN_MILLIS / 2), 512L, 5L, 512L, 5L, 5L);
     }
 
+    @Test
     public void testRecordEntireGapIdentical() throws Exception {
         // first, create two separate histories far apart
         final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
@@ -206,6 +223,7 @@
         assertValues(stats, 3, 500L, 250L);
     }
 
+    @Test
     public void testRecordEntireOverlapVaryingBuckets() throws Exception {
         // create history just over hour bucket boundary
         final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
@@ -247,6 +265,7 @@
         assertValues(stats, 3, 150L, 150L);
     }
 
+    @Test
     public void testRemove() throws Exception {
         stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
 
@@ -280,6 +299,7 @@
         assertEquals(0, stats.size());
     }
 
+    @Test
     public void testTotalData() throws Exception {
         final long BUCKET_SIZE = HOUR_IN_MILLIS;
         stats = new NetworkStatsHistory(BUCKET_SIZE);
@@ -304,7 +324,7 @@
 
     }
 
-    @Suppress
+    @Test
     public void testFuzzing() throws Exception {
         try {
             // fuzzing with random events, looking for crashes
@@ -341,6 +361,7 @@
         return value < 0 ? -value : value;
     }
 
+    @Test
     public void testIgnoreFields() throws Exception {
         final NetworkStatsHistory history = new NetworkStatsHistory(
                 MINUTE_IN_MILLIS, 0, FIELD_RX_BYTES | FIELD_TX_BYTES);
@@ -353,6 +374,7 @@
         assertFullValues(history, UNKNOWN, 1026L, UNKNOWN, 2050L, UNKNOWN, UNKNOWN);
     }
 
+    @Test
     public void testIgnoreFieldsRecordIn() throws Exception {
         final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
         final NetworkStatsHistory partial = new NetworkStatsHistory(
@@ -365,6 +387,7 @@
         assertFullValues(partial, UNKNOWN, UNKNOWN, 10L, UNKNOWN, UNKNOWN, 4L);
     }
 
+    @Test
     public void testIgnoreFieldsRecordOut() throws Exception {
         final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
         final NetworkStatsHistory partial = new NetworkStatsHistory(
@@ -377,6 +400,7 @@
         assertFullValues(full, MINUTE_IN_MILLIS, 0L, 10L, 0L, 0L, 4L);
     }
 
+    @Test
     public void testSerialize() throws Exception {
         final NetworkStatsHistory before = new NetworkStatsHistory(MINUTE_IN_MILLIS, 40, FIELD_ALL);
         before.recordData(0, 4 * MINUTE_IN_MILLIS,
@@ -396,6 +420,7 @@
         assertFullValues(after, 5 * MINUTE_IN_MILLIS, 1034L, 30L, 2078L, 60L, 54L);
     }
 
+    @Test
     public void testVarLong() throws Exception {
         assertEquals(0L, performVarLong(0L));
         assertEquals(-1L, performVarLong(-1L));
@@ -409,6 +434,7 @@
         assertEquals(Long.MAX_VALUE - 40, performVarLong(Long.MAX_VALUE - 40));
     }
 
+    @Test
     public void testIndexBeforeAfter() throws Exception {
         final long BUCKET_SIZE = HOUR_IN_MILLIS;
         stats = new NetworkStatsHistory(BUCKET_SIZE);
@@ -451,6 +477,7 @@
         assertIndexBeforeAfter(stats, 4, 4, Long.MAX_VALUE);
     }
 
+    @Test
     public void testIntersects() throws Exception {
         final long BUCKET_SIZE = HOUR_IN_MILLIS;
         stats = new NetworkStatsHistory(BUCKET_SIZE);
@@ -485,6 +512,7 @@
         assertTrue(stats.intersects(Long.MIN_VALUE, TEST_START + 1));
     }
 
+    @Test
     public void testSetValues() throws Exception {
         stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
         stats.recordData(TEST_START, TEST_START + 1,
diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java
index eb85eb4..25289ba 100644
--- a/tests/net/java/android/net/NetworkStatsTest.java
+++ b/tests/net/java/android/net/NetworkStatsTest.java
@@ -30,23 +30,30 @@
 import static android.net.NetworkStats.IFACE_ALL;
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.SmallTest;
 
 import com.google.android.collect.Sets;
 
-import junit.framework.TestCase;
-
 import java.util.HashSet;
 
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(AndroidJUnit4.class)
 @SmallTest
-public class NetworkStatsTest extends TestCase {
+public class NetworkStatsTest {
 
     private static final String TEST_IFACE = "test0";
     private static final String TEST_IFACE2 = "test2";
     private static final int TEST_UID = 1001;
     private static final long TEST_START = 1194220800000L;
 
+    @Test
     public void testFindIndex() throws Exception {
         final NetworkStats stats = new NetworkStats(TEST_START, 5)
                 .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L,
@@ -74,6 +81,7 @@
                 ROAMING_NO));
     }
 
+    @Test
     public void testFindIndexHinted() {
         final NetworkStats stats = new NetworkStats(TEST_START, 3)
                 .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L,
@@ -116,6 +124,7 @@
         }
     }
 
+    @Test
     public void testAddEntryGrow() throws Exception {
         final NetworkStats stats = new NetworkStats(TEST_START, 4);
 
@@ -168,6 +177,7 @@
                 ROAMING_YES, 7L, 70L, 5L, 50L, 11);
     }
 
+    @Test
     public void testCombineExisting() throws Exception {
         final NetworkStats stats = new NetworkStats(TEST_START, 10);
 
@@ -190,6 +200,7 @@
                 256L, 2L, 256L, 2L, 6);
     }
 
+    @Test
     public void testSubtractIdenticalData() throws Exception {
         final NetworkStats before = new NetworkStats(TEST_START, 2)
                 .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
@@ -208,6 +219,7 @@
                 0L, 0L, 0L, 0);
     }
 
+    @Test
     public void testSubtractIdenticalRows() throws Exception {
         final NetworkStats before = new NetworkStats(TEST_START, 2)
                 .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
@@ -226,6 +238,7 @@
                 1L, 4L, 1L, 8);
     }
 
+    @Test
     public void testSubtractNewRows() throws Exception {
         final NetworkStats before = new NetworkStats(TEST_START, 2)
                 .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
@@ -247,6 +260,7 @@
                 1024L, 8L, 1024L, 8L, 20);
     }
 
+    @Test
     public void testSubtractMissingRows() throws Exception {
         final NetworkStats before = new NetworkStats(TEST_START, 2)
                 .addValues(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 1024L, 0L, 0L, 0L, 0)
@@ -264,6 +278,7 @@
         assertEquals(4L, result.getTotalBytes());
     }
 
+    @Test
     public void testTotalBytes() throws Exception {
         final NetworkStats iface = new NetworkStats(TEST_START, 2)
                 .addValues(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 128L, 0L, 0L, 0L, 0L)
@@ -304,6 +319,7 @@
         assertEquals(96L, uidRoaming.getTotalBytes());
     }
 
+    @Test
     public void testGroupedByIfaceEmpty() throws Exception {
         final NetworkStats uidStats = new NetworkStats(TEST_START, 3);
         final NetworkStats grouped = uidStats.groupedByIface();
@@ -312,6 +328,7 @@
         assertEquals(0, grouped.size());
     }
 
+    @Test
     public void testGroupedByIfaceAll() throws Exception {
         final NetworkStats uidStats = new NetworkStats(TEST_START, 3)
                 .addValues(IFACE_ALL, 100, SET_ALL, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L, 0L,
@@ -329,6 +346,7 @@
                 384L, 24L, 0L, 6L, 0L);
     }
 
+    @Test
     public void testGroupedByIface() throws Exception {
         final NetworkStats uidStats = new NetworkStats(TEST_START, 7)
                 .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L,
@@ -357,6 +375,7 @@
                 1024L, 64L, 0L, 0L, 0L);
     }
 
+    @Test
     public void testAddAllValues() {
         final NetworkStats first = new NetworkStats(TEST_START, 5)
                 .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L,
@@ -387,6 +406,7 @@
                 32L, 0L, 0L, 0L, 0L);
     }
 
+    @Test
     public void testGetTotal() {
         final NetworkStats stats = new NetworkStats(TEST_START, 7)
                 .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L,
@@ -415,6 +435,7 @@
         assertValues(stats.getTotal(null, ifaces), 1024L, 64L, 0L, 0L, 0L);
     }
 
+    @Test
     public void testWithoutUid() throws Exception {
         final NetworkStats before = new NetworkStats(TEST_START, 3)
                 .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L)
@@ -433,6 +454,7 @@
                 8L, 0L, 0L, 0L);
     }
 
+    @Test
     public void testClone() throws Exception {
         final NetworkStats original = new NetworkStats(TEST_START, 5)
                 .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L)
@@ -449,6 +471,7 @@
         assertEquals(128L + 512L, clone.getTotalBytes());
     }
 
+    @Test
     public void testAddWhenEmpty() throws Exception {
         final NetworkStats red = new NetworkStats(TEST_START, -1);
         final NetworkStats blue = new NetworkStats(TEST_START, 5)
@@ -459,6 +482,7 @@
         red.combineAllValues(blue);
     }
 
+    @Test
     public void testMigrateTun() throws Exception {
         final int tunUid = 10030;
         final String tunIface = "tun0";
@@ -556,6 +580,7 @@
     // interface by the vpn app before it's sent out of the underlying interface. The VPN app should
     // not be charged for the echoed data but it should still be charged for any extra data it sends
     // via the underlying interface.
+    @Test
     public void testMigrateTun_VpnAsLoopback() {
         final int tunUid = 10030;
         final String tunIface = "tun0";
diff --git a/tests/net/java/android/net/NetworkTest.java b/tests/net/java/android/net/NetworkTest.java
new file mode 100644
index 0000000..bacf986
--- /dev/null
+++ b/tests/net/java/android/net/NetworkTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 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 android.net;
+
+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 android.net.LocalServerSocket;
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
+import android.net.Network;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.Inet6Address;
+import java.net.SocketException;
+import java.util.Objects;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NetworkTest {
+    final Network mNetwork = new Network(99);
+
+    @Test
+    public void testBindSocketOfInvalidFdThrows() throws Exception {
+
+        final FileDescriptor fd = new FileDescriptor();
+        assertFalse(fd.valid());
+
+        try {
+            mNetwork.bindSocket(fd);
+            fail("SocketException not thrown");
+        } catch (SocketException expected) {}
+    }
+
+    @Test
+    public void testBindSocketOfNonSocketFdThrows() throws Exception {
+        final File devNull = new File("/dev/null");
+        assertTrue(devNull.canRead());
+
+        final FileInputStream fis = new FileInputStream(devNull);
+        assertTrue(null != fis.getFD());
+        assertTrue(fis.getFD().valid());
+
+        try {
+            mNetwork.bindSocket(fis.getFD());
+            fail("SocketException not thrown");
+        } catch (SocketException expected) {}
+    }
+
+    @Test
+    public void testBindSocketOfConnectedDatagramSocketThrows() throws Exception {
+        final DatagramSocket mDgramSocket = new DatagramSocket(0, (InetAddress) Inet6Address.ANY);
+        mDgramSocket.connect((InetAddress) Inet6Address.LOOPBACK, 53);
+        assertTrue(mDgramSocket.isConnected());
+
+        try {
+            mNetwork.bindSocket(mDgramSocket);
+            fail("SocketException not thrown");
+        } catch (SocketException expected) {}
+    }
+
+    @Test
+    public void testBindSocketOfLocalSocketThrows() throws Exception {
+        final LocalSocket mLocalClient = new LocalSocket();
+        mLocalClient.bind(new LocalSocketAddress("testClient"));
+        assertTrue(mLocalClient.getFileDescriptor().valid());
+
+        try {
+            mNetwork.bindSocket(mLocalClient.getFileDescriptor());
+            fail("SocketException not thrown");
+        } catch (SocketException expected) {}
+
+        final LocalServerSocket mLocalServer = new LocalServerSocket("testServer");
+        mLocalClient.connect(mLocalServer.getLocalSocketAddress());
+        assertTrue(mLocalClient.isConnected());
+
+        try {
+            mNetwork.bindSocket(mLocalClient.getFileDescriptor());
+            fail("SocketException not thrown");
+        } catch (SocketException expected) {}
+    }
+
+    @Test
+    public void testZeroIsObviousForDebugging() {
+        Network zero = new Network(0);
+        assertEquals(0, zero.hashCode());
+        assertEquals(0, zero.getNetworkHandle());
+        assertEquals("0", zero.toString());
+    }
+
+    @Test
+    public void testGetNetworkHandle() {
+        Network one = new Network(1);
+        Network two = new Network(2);
+        Network three = new Network(3);
+
+        // None of the hashcodes are zero.
+        assertNotEqual(0, one.hashCode());
+        assertNotEqual(0, two.hashCode());
+        assertNotEqual(0, three.hashCode());
+
+        // All the hashcodes are distinct.
+        assertNotEqual(one.hashCode(), two.hashCode());
+        assertNotEqual(one.hashCode(), three.hashCode());
+        assertNotEqual(two.hashCode(), three.hashCode());
+
+        // None of the handles are zero.
+        assertNotEqual(0, one.getNetworkHandle());
+        assertNotEqual(0, two.getNetworkHandle());
+        assertNotEqual(0, three.getNetworkHandle());
+
+        // All the handles are distinct.
+        assertNotEqual(one.getNetworkHandle(), two.getNetworkHandle());
+        assertNotEqual(one.getNetworkHandle(), three.getNetworkHandle());
+        assertNotEqual(two.getNetworkHandle(), three.getNetworkHandle());
+
+        // The handles are not equal to the hashcodes.
+        assertNotEqual(one.hashCode(), one.getNetworkHandle());
+        assertNotEqual(two.hashCode(), two.getNetworkHandle());
+        assertNotEqual(three.hashCode(), three.getNetworkHandle());
+
+        // Adjust as necessary to test an implementation's specific constants.
+        // When running with runtest, "adb logcat -s TestRunner" can be useful.
+        assertEquals(4311403230L, one.getNetworkHandle());
+        assertEquals(8606370526L, two.getNetworkHandle());
+        assertEquals(12901337822L, three.getNetworkHandle());
+    }
+
+    private static <T> void assertNotEqual(T t1, T t2) {
+        assertFalse(Objects.equals(t1, t2));
+    }
+}
diff --git a/tests/net/java/android/net/StaticIpConfigurationTest.java b/tests/net/java/android/net/StaticIpConfigurationTest.java
new file mode 100644
index 0000000..5bb5734
--- /dev/null
+++ b/tests/net/java/android/net/StaticIpConfigurationTest.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import java.net.InetAddress;
+import java.util.HashSet;
+import java.util.Objects;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class StaticIpConfigurationTest {
+
+    private static final String ADDRSTR = "192.0.2.2/25";
+    private static final LinkAddress ADDR = new LinkAddress(ADDRSTR);
+    private static final InetAddress GATEWAY = IpAddress("192.0.2.1");
+    private static final InetAddress OFFLINKGATEWAY = IpAddress("192.0.2.129");
+    private static final InetAddress DNS1 = IpAddress("8.8.8.8");
+    private static final InetAddress DNS2 = IpAddress("8.8.4.4");
+    private static final InetAddress DNS3 = IpAddress("4.2.2.2");
+    private static final String IFACE = "eth0";
+
+    private static InetAddress IpAddress(String addr) {
+        return InetAddress.parseNumericAddress(addr);
+    }
+
+    private void checkEmpty(StaticIpConfiguration s) {
+        assertNull(s.ipAddress);
+        assertNull(s.gateway);
+        assertNull(s.domains);
+        assertEquals(0, s.dnsServers.size());
+    }
+
+    private static <T> void assertNotEquals(T t1, T t2) {
+        assertFalse(Objects.equals(t1, t2));
+    }
+
+    private StaticIpConfiguration makeTestObject() {
+        StaticIpConfiguration s = new StaticIpConfiguration();
+        s.ipAddress = ADDR;
+        s.gateway = GATEWAY;
+        s.dnsServers.add(DNS1);
+        s.dnsServers.add(DNS2);
+        s.dnsServers.add(DNS3);
+        s.domains = "google.com";
+        return s;
+    }
+
+    @Test
+    public void testConstructor() {
+        StaticIpConfiguration s = new StaticIpConfiguration();
+        checkEmpty(s);
+    }
+
+    @Test
+    public void testCopyAndClear() {
+        StaticIpConfiguration empty = new StaticIpConfiguration((StaticIpConfiguration) null);
+        checkEmpty(empty);
+
+        StaticIpConfiguration s1 = makeTestObject();
+        StaticIpConfiguration s2 = new StaticIpConfiguration(s1);
+        assertEquals(s1, s2);
+        s2.clear();
+        assertEquals(empty, s2);
+    }
+
+    @Test
+    public void testHashCodeAndEquals() {
+        HashSet<Integer> hashCodes = new HashSet();
+        hashCodes.add(0);
+
+        StaticIpConfiguration s = new StaticIpConfiguration();
+        // Check that this hash code is nonzero and different from all the ones seen so far.
+        assertTrue(hashCodes.add(s.hashCode()));
+
+        s.ipAddress = ADDR;
+        assertTrue(hashCodes.add(s.hashCode()));
+
+        s.gateway = GATEWAY;
+        assertTrue(hashCodes.add(s.hashCode()));
+
+        s.dnsServers.add(DNS1);
+        assertTrue(hashCodes.add(s.hashCode()));
+
+        s.dnsServers.add(DNS2);
+        assertTrue(hashCodes.add(s.hashCode()));
+
+        s.dnsServers.add(DNS3);
+        assertTrue(hashCodes.add(s.hashCode()));
+
+        s.domains = "example.com";
+        assertTrue(hashCodes.add(s.hashCode()));
+
+        assertFalse(s.equals(null));
+        assertEquals(s, s);
+
+        StaticIpConfiguration s2 = new StaticIpConfiguration(s);
+        assertEquals(s, s2);
+
+        s.ipAddress = new LinkAddress(DNS1, 32);
+        assertNotEquals(s, s2);
+
+        s2 = new StaticIpConfiguration(s);
+        s.domains = "foo";
+        assertNotEquals(s, s2);
+
+        s2 = new StaticIpConfiguration(s);
+        s.gateway = DNS2;
+        assertNotEquals(s, s2);
+
+        s2 = new StaticIpConfiguration(s);
+        s.dnsServers.add(DNS3);
+        assertNotEquals(s, s2);
+    }
+
+    @Test
+    public void testToLinkProperties() {
+        LinkProperties expected = new LinkProperties();
+        expected.setInterfaceName(IFACE);
+
+        StaticIpConfiguration s = new StaticIpConfiguration();
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        final RouteInfo connectedRoute = new RouteInfo(new IpPrefix(ADDRSTR), null, IFACE);
+        s.ipAddress = ADDR;
+        expected.addLinkAddress(ADDR);
+        expected.addRoute(connectedRoute);
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        s.gateway = GATEWAY;
+        RouteInfo defaultRoute = new RouteInfo(new IpPrefix("0.0.0.0/0"), GATEWAY, IFACE);
+        expected.addRoute(defaultRoute);
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        s.gateway = OFFLINKGATEWAY;
+        expected.removeRoute(defaultRoute);
+        defaultRoute = new RouteInfo(new IpPrefix("0.0.0.0/0"), OFFLINKGATEWAY, IFACE);
+        expected.addRoute(defaultRoute);
+
+        RouteInfo gatewayRoute = new RouteInfo(new IpPrefix("192.0.2.129/32"), null, IFACE);
+        expected.addRoute(gatewayRoute);
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        s.dnsServers.add(DNS1);
+        expected.addDnsServer(DNS1);
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        s.dnsServers.add(DNS2);
+        s.dnsServers.add(DNS3);
+        expected.addDnsServer(DNS2);
+        expected.addDnsServer(DNS3);
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        s.domains = "google.com";
+        expected.setDomains("google.com");
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        s.gateway = null;
+        expected.removeRoute(defaultRoute);
+        expected.removeRoute(gatewayRoute);
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        // Without knowing the IP address, we don't have a directly-connected route, so we can't
+        // tell if the gateway is off-link or not and we don't add a host route. This isn't a real
+        // configuration, but we should at least not crash.
+        s.gateway = OFFLINKGATEWAY;
+        s.ipAddress = null;
+        expected.removeLinkAddress(ADDR);
+        expected.removeRoute(connectedRoute);
+        expected.addRoute(defaultRoute);
+        assertEquals(expected, s.toLinkProperties(IFACE));
+    }
+
+    private StaticIpConfiguration passThroughParcel(StaticIpConfiguration s) {
+        Parcel p = Parcel.obtain();
+        StaticIpConfiguration s2 = null;
+        try {
+            s.writeToParcel(p, 0);
+            p.setDataPosition(0);
+            s2 = StaticIpConfiguration.CREATOR.createFromParcel(p);
+        } finally {
+            p.recycle();
+        }
+        assertNotNull(s2);
+        return s2;
+    }
+
+    @Test
+    public void testParceling() {
+        StaticIpConfiguration s = makeTestObject();
+        StaticIpConfiguration s2 = passThroughParcel(s);
+        assertEquals(s, s2);
+    }
+}
diff --git a/tests/net/java/android/net/UidRangeTest.java b/tests/net/java/android/net/UidRangeTest.java
index 0a56e1b..1d1013e 100644
--- a/tests/net/java/android/net/UidRangeTest.java
+++ b/tests/net/java/android/net/UidRangeTest.java
@@ -16,14 +16,20 @@
 
 package android.net;
 
-import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.TestCase;
-
 import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 
-public class UidRangeTest extends TestCase {
+import android.os.Parcel;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.SmallTest;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class UidRangeTest {
 
     static {
         System.loadLibrary("frameworksnettestsjni");
@@ -33,7 +39,7 @@
     private static native int getStart(byte[] inParcel);
     private static native int getStop(byte[] inParcel);
 
-    @SmallTest
+    @Test
     public void testNativeParcelUnparcel() {
         UidRange original = new UidRange(1234, Integer.MAX_VALUE);
 
@@ -45,7 +51,7 @@
         assertArrayEquals(inParcel, outParcel);
     }
 
-    @SmallTest
+    @Test
     public void testIndividualNativeFields() {
         UidRange original = new UidRange(0x11115678, 0x22224321);
         byte[] originalBytes = marshall(original);
@@ -54,14 +60,14 @@
         assertEquals(original.stop, getStop(originalBytes));
     }
 
-    @SmallTest
+    @Test
     public void testSingleItemUidRangeAllowed() {
         new UidRange(123, 123);
         new UidRange(0, 0);
         new UidRange(Integer.MAX_VALUE, Integer.MAX_VALUE);
     }
 
-    @SmallTest
+    @Test
     public void testNegativeUidsDisallowed() {
         try {
             new UidRange(-2, 100);
@@ -76,7 +82,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testStopLessThanStartDisallowed() {
         final int x = 4195000;
         try {
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index 5008a41..99a2ad9 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -16,6 +16,16 @@
 
 package android.net.apf;
 
+import static android.system.OsConstants.*;
+import static com.android.internal.util.BitUtils.bytesToBEInt;
+import static com.android.internal.util.BitUtils.put;
+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.Mockito.atLeastOnce;
+import static org.mockito.Mockito.verify;
+
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.NetworkUtils;
@@ -30,23 +40,22 @@
 import android.os.ConditionVariable;
 import android.os.Parcelable;
 import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.SmallTest;
 import android.system.ErrnoException;
 import android.system.Os;
-import android.test.AndroidTestCase;
 import android.text.format.DateUtils;
-import android.test.suitebuilder.annotation.SmallTest;
-import static android.system.OsConstants.*;
 
 import com.android.frameworks.tests.net.R;
 import com.android.internal.util.HexDump;
-import static com.android.internal.util.BitUtils.bytesToBEInt;
-import static com.android.internal.util.BitUtils.put;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.verify;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -69,14 +78,15 @@
  * Build, install and run with:
  *  runtest frameworks-net -c android.net.apf.ApfTest
  */
-public class ApfTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ApfTest {
     private static final int TIMEOUT_MS = 500;
 
     @Mock IpConnectivityLog mLog;
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
         MockitoAnnotations.initMocks(this);
         // Load up native shared library containing APF interpreter exposed via JNI.
         System.loadLibrary("frameworksnettestsjni");
@@ -161,7 +171,7 @@
      * generating bytecode for that program and running it through the
      * interpreter to verify it functions correctly.
      */
-    @SmallTest
+    @Test
     public void testApfInstructions() throws IllegalInstructionException {
         // Empty program should pass because having the program counter reach the
         // location immediately after the program indicates the packet should be
@@ -569,7 +579,7 @@
      * Generate some BPF programs, translate them to APF, then run APF and BPF programs
      * over packet traces and verify both programs filter out the same packets.
      */
-    @SmallTest
+    @Test
     public void testApfAgainstBpf() throws Exception {
         String[] tcpdump_filters = new String[]{ "udp", "tcp", "icmp", "icmp6", "udp port 53",
                 "arp", "dst 239.255.255.250", "arp or tcp or udp port 53", "net 192.168.1.0/24",
@@ -739,7 +749,7 @@
     private static final byte[] ANOTHER_IPV4_ADDR        = {10, 0, 0, 2};
     private static final byte[] IPV4_ANY_HOST_ADDR       = {0, 0, 0, 0};
 
-    @SmallTest
+    @Test
     public void testApfFilterIPv4() throws Exception {
         MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
         LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
@@ -796,7 +806,7 @@
         apfFilter.shutdown();
     }
 
-    @SmallTest
+    @Test
     public void testApfFilterIPv6() throws Exception {
         final int[] ethTypeBlackList = {};
         MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
@@ -830,7 +840,7 @@
         apfFilter.shutdown();
     }
 
-    @SmallTest
+    @Test
     public void testApfFilterMulticast() throws Exception {
         final byte[] unicastIpv4Addr   = {(byte)192,0,2,63};
         final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255};
@@ -922,7 +932,7 @@
         apfFilter.shutdown();
     }
 
-    @SmallTest
+    @Test
     public void testApfFilter802_3() throws Exception {
         MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
         LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
@@ -973,7 +983,7 @@
         apfFilter.shutdown();
     }
 
-    @SmallTest
+    @Test
     public void testApfFilterEthTypeBL() throws Exception {
         MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
         LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
@@ -1058,7 +1068,7 @@
         assertDrop(program, garpReply());
     }
 
-    @SmallTest
+    @Test
     public void testApfFilterArp() throws Exception {
         final int[] ethTypeBlackList = {};
         MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
@@ -1136,7 +1146,7 @@
 
     // Test that when ApfFilter is shown the given packet, it generates a program to filter it
     // for the given lifetime.
-    private void testRaLifetime(TestApfFilter apfFilter, MockIpManagerCallback ipManagerCallback,
+    private void verifyRaLifetime(TestApfFilter apfFilter, MockIpManagerCallback ipManagerCallback,
             ByteBuffer packet, int lifetime) throws IOException, ErrnoException {
         // Verify new program generated if ApfFilter witnesses RA
         ipManagerCallback.resetApfProgramWait();
@@ -1181,7 +1191,7 @@
         ipManagerCallback.assertNoProgramUpdate();
     }
 
-    @SmallTest
+    @Test
     public void testApfFilterRa() throws Exception {
         MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
         final int[] ethTypeBlackList = {};
@@ -1212,7 +1222,7 @@
         basePacket.put(IPV6_ALL_NODES_ADDRESS);
         assertPass(program, basePacket.array());
 
-        testRaLifetime(apfFilter, ipManagerCallback, basePacket, ROUTER_LIFETIME);
+        verifyRaLifetime(apfFilter, ipManagerCallback, basePacket, ROUTER_LIFETIME);
         verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, -1));
 
         ByteBuffer newFlowLabelPacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
@@ -1247,7 +1257,8 @@
         prefixOptionPacket.putInt(
                 ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET,
                 PREFIX_VALID_LIFETIME);
-        testRaLifetime(apfFilter, ipManagerCallback, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
+        verifyRaLifetime(
+                apfFilter, ipManagerCallback, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
         verifyRaEvent(new RaEvent(
                 ROUTER_LIFETIME, PREFIX_VALID_LIFETIME, PREFIX_PREFERRED_LIFETIME, -1, -1, -1));
 
@@ -1259,7 +1270,7 @@
         rdnssOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
         rdnssOptionPacket.putInt(
                 ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, RDNSS_LIFETIME);
-        testRaLifetime(apfFilter, ipManagerCallback, rdnssOptionPacket, RDNSS_LIFETIME);
+        verifyRaLifetime(apfFilter, ipManagerCallback, rdnssOptionPacket, RDNSS_LIFETIME);
         verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, RDNSS_LIFETIME, -1));
 
         ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap(
@@ -1270,7 +1281,7 @@
         routeInfoOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
         routeInfoOptionPacket.putInt(
                 ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, ROUTE_LIFETIME);
-        testRaLifetime(apfFilter, ipManagerCallback, routeInfoOptionPacket, ROUTE_LIFETIME);
+        verifyRaLifetime(apfFilter, ipManagerCallback, routeInfoOptionPacket, ROUTE_LIFETIME);
         verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, ROUTE_LIFETIME, -1, -1));
 
         ByteBuffer dnsslOptionPacket = ByteBuffer.wrap(
@@ -1281,7 +1292,7 @@
         dnsslOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
         dnsslOptionPacket.putInt(
                 ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, DNSSL_LIFETIME);
-        testRaLifetime(apfFilter, ipManagerCallback, dnsslOptionPacket, ROUTER_LIFETIME);
+        verifyRaLifetime(apfFilter, ipManagerCallback, dnsslOptionPacket, ROUTER_LIFETIME);
         verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, DNSSL_LIFETIME));
 
         // Verify that current program filters all five RAs:
@@ -1301,12 +1312,12 @@
      * copy that resource into the app's data directory and return the path to it.
      */
     private String stageFile(int rawId) throws Exception {
-        File file = new File(getContext().getFilesDir(), "staged_file");
+        File file = new File(InstrumentationRegistry.getContext().getFilesDir(), "staged_file");
         new File(file.getParent()).mkdirs();
         InputStream in = null;
         OutputStream out = null;
         try {
-            in = getContext().getResources().openRawResource(rawId);
+            in = InstrumentationRegistry.getContext().getResources().openRawResource(rawId);
             out = new FileOutputStream(file);
             Streams.copy(in, out);
         } finally {
@@ -1323,7 +1334,7 @@
         buffer.position(original);
     }
 
-    @SmallTest
+    @Test
     public void testRaParsing() throws Exception {
         final int maxRandomPacketSize = 512;
         final Random r = new Random();
@@ -1343,7 +1354,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testRaProcessing() throws Exception {
         final int maxRandomPacketSize = 512;
         final Random r = new Random();
@@ -1383,7 +1394,7 @@
     private native static boolean compareBpfApf(String filter, String pcap_filename,
             byte[] apf_program);
 
-    @SmallTest
+    @Test
     public void testBroadcastAddress() throws Exception {
         assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 0));
         assertEqualsIp("0.0.0.0", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 32));
diff --git a/tests/net/java/android/net/dhcp/DhcpPacketTest.java b/tests/net/java/android/net/dhcp/DhcpPacketTest.java
index d79c312..050183c 100644
--- a/tests/net/java/android/net/dhcp/DhcpPacketTest.java
+++ b/tests/net/java/android/net/dhcp/DhcpPacketTest.java
@@ -16,23 +16,36 @@
 
 package android.net.dhcp;
 
+import static android.net.dhcp.DhcpPacket.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import android.net.DhcpResults;
 import android.net.LinkAddress;
 import android.net.NetworkUtils;
 import android.net.metrics.DhcpErrorEvent;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.SmallTest;
 import android.system.OsConstants;
-import android.test.suitebuilder.annotation.SmallTest;
+
 import com.android.internal.util.HexDump;
+
 import java.net.Inet4Address;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Random;
-import junit.framework.TestCase;
 
-import static android.net.dhcp.DhcpPacket.*;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class DhcpPacketTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DhcpPacketTest {
 
     private static Inet4Address SERVER_ADDR = v4Address("192.0.2.1");
     private static Inet4Address CLIENT_ADDR = v4Address("192.0.2.234");
@@ -46,6 +59,7 @@
         return (Inet4Address) NetworkUtils.numericToInetAddress(addrString);
     }
 
+    @Before
     public void setUp() {
         DhcpPacket.testOverrideVendorId = "android-dhcp-???";
         DhcpPacket.testOverrideHostname = "android-01234567890abcde";
@@ -131,7 +145,7 @@
         assertEquals(expectedVendorInfo, offerPacket.mVendorInfo);
     }
 
-    @SmallTest
+    @Test
     public void testDomainName() throws Exception {
         byte[] nullByte = new byte[] { 0x00 };
         byte[] twoNullBytes = new byte[] { 0x00, 0x00 };
@@ -186,7 +200,7 @@
         assertEquals(leaseTimeMillis, offerPacket.getLeaseTimeMillis());
     }
 
-    @SmallTest
+    @Test
     public void testLeaseTime() throws Exception {
         byte[] noLease = null;
         byte[] tooShortLease = new byte[] { 0x00, 0x00 };
@@ -234,7 +248,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testIpAddress() throws Exception {
         byte[] slash11Netmask = new byte[] { (byte) 0xff, (byte) 0xe0, 0x00, 0x00 };
         byte[] slash24Netmask = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x00 };
@@ -278,11 +292,11 @@
         assertEquals(mtu, dhcpResults.mtu);
     }
 
-    @SmallTest
+    @Test
     public void testOffer1() throws Exception {
-        // TODO: Turn all of these into golden files. This will probably require modifying
-        // Android.mk appropriately, making this into an AndroidTestCase, and adding code to read
-        // the golden files from the test APK's assets via mContext.getAssets().
+        // TODO: Turn all of these into golden files. This will probably require using
+        // android.support.test.InstrumentationRegistry for obtaining a Context object
+        // to read such golden files, along with an appropriate Android.mk.
         final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
             // IP header.
             "451001480000000080118849c0a89003c0a89ff7" +
@@ -311,7 +325,7 @@
                 null, "192.168.144.3", null, 7200, false, 0, dhcpResults);
     }
 
-    @SmallTest
+    @Test
     public void testOffer2() throws Exception {
         final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
             // IP header.
@@ -343,7 +357,7 @@
         assertTrue(dhcpResults.hasMeteredHint());
     }
 
-    @SmallTest
+    @Test
     public void testBadIpPacket() throws Exception {
         final byte[] packet = HexDump.hexStringToByteArray(
             // IP header.
@@ -358,7 +372,7 @@
         fail("Dhcp packet parsing should have failed");
     }
 
-    @SmallTest
+    @Test
     public void testBadDhcpPacket() throws Exception {
         final byte[] packet = HexDump.hexStringToByteArray(
             // IP header.
@@ -377,7 +391,7 @@
         fail("Dhcp packet parsing should have failed");
     }
 
-    @SmallTest
+    @Test
     public void testBadTruncatedOffer() throws Exception {
         final byte[] packet = HexDump.hexStringToByteArray(
             // IP header.
@@ -406,7 +420,7 @@
         fail("Dhcp packet parsing should have failed");
     }
 
-    @SmallTest
+    @Test
     public void testBadOfferWithoutACookie() throws Exception {
         final byte[] packet = HexDump.hexStringToByteArray(
             // IP header.
@@ -437,7 +451,7 @@
         fail("Dhcp packet parsing should have failed");
     }
 
-    @SmallTest
+    @Test
     public void testOfferWithBadCookie() throws Exception {
         final byte[] packet = HexDump.hexStringToByteArray(
             // IP header.
@@ -473,7 +487,7 @@
         assertEquals(Integer.toHexString(expected), Integer.toHexString(got));
     }
 
-    @SmallTest
+    @Test
     public void testTruncatedOfferPackets() throws Exception {
         final byte[] packet = HexDump.hexStringToByteArray(
             // IP header.
@@ -507,7 +521,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testRandomPackets() throws Exception {
         final int maxRandomPacketSize = 512;
         final Random r = new Random();
@@ -547,7 +561,7 @@
                 null, "192.168.144.3", null, 7200, false, expectedMtu, dhcpResults);
     }
 
-    @SmallTest
+    @Test
     public void testMtu() throws Exception {
         final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
             // IP header.
@@ -583,7 +597,7 @@
         checkMtu(packet, 0, mtuBytes(-1));
     }
 
-    @SmallTest
+    @Test
     public void testBadHwaddrLength() throws Exception {
         final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
             // IP header.
@@ -652,7 +666,7 @@
         assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
     }
 
-    @SmallTest
+    @Test
     public void testPadAndOverloadedOptionsOffer() throws Exception {
         // A packet observed in the real world that is interesting for two reasons:
         //
@@ -691,7 +705,7 @@
                 null, "1.1.1.1", null, 43200, false, 0, dhcpResults);
     }
 
-    @SmallTest
+    @Test
     public void testBug2111() throws Exception {
         final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
             // IP header.
@@ -721,7 +735,7 @@
                 "domain123.co.uk", "192.0.2.254", null, 49094, false, 0, dhcpResults);
     }
 
-    @SmallTest
+    @Test
     public void testBug2136() throws Exception {
         final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
             // Ethernet header.
@@ -754,7 +768,7 @@
                 "lancs.ac.uk", "10.32.255.128", null, 7200, false, 0, dhcpResults);
     }
 
-    @SmallTest
+    @Test
     public void testUdpServerAnySourcePort() throws Exception {
         final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
             // Ethernet header.
@@ -789,7 +803,7 @@
                 "wvm.edu", "10.1.105.252", null, 86400, false, 0, dhcpResults);
     }
 
-    @SmallTest
+    @Test
     public void testUdpInvalidDstPort() throws Exception {
         final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
             // Ethernet header.
@@ -821,7 +835,7 @@
         } catch (ParseException expected) {}
     }
 
-    @SmallTest
+    @Test
     public void testMultipleRouters() throws Exception {
         final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
             // Ethernet header.
@@ -854,7 +868,7 @@
                 null, "192.171.189.2", null, 28800, false, 0, dhcpResults);
     }
 
-    @SmallTest
+    @Test
     public void testDiscoverPacket() throws Exception {
         short secs = 7;
         int transactionId = 0xdeadbeef;
diff --git a/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java b/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java
index 5deba27..6647760 100644
--- a/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java
+++ b/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java
@@ -19,20 +19,30 @@
 import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
 import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK;
 import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import android.net.netlink.NetlinkConstants;
 import android.net.netlink.NetlinkErrorMessage;
 import android.net.netlink.NetlinkMessage;
 import android.net.netlink.StructNlMsgErr;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.SmallTest;
 import android.util.Log;
+
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
-import junit.framework.TestCase;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
 import libcore.util.HexEncoding;
 
 
-public class NetlinkErrorMessageTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NetlinkErrorMessageTest {
     private final String TAG = "NetlinkErrorMessageTest";
 
     // Hexadecimal representation of packet capture.
@@ -54,7 +64,7 @@
     public static final byte[] NLM_ERROR_OK =
             HexEncoding.decode(NLM_ERROR_OK_HEX.toCharArray(), false);
 
-    @SmallTest
+    @Test
     public void testParseNlmErrorOk() {
         final ByteBuffer byteBuffer = ByteBuffer.wrap(NLM_ERROR_OK);
         byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
diff --git a/tests/net/java/android/net/netlink/NetlinkSocketTest.java b/tests/net/java/android/net/netlink/NetlinkSocketTest.java
index 78b3b70..bd36bac8 100644
--- a/tests/net/java/android/net/netlink/NetlinkSocketTest.java
+++ b/tests/net/java/android/net/netlink/NetlinkSocketTest.java
@@ -16,25 +16,35 @@
 
 package android.net.netlink;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
 import android.net.netlink.NetlinkSocket;
 import android.net.netlink.RtNetlinkNeighborMessage;
 import android.net.netlink.StructNdMsg;
 import android.net.netlink.StructNlMsgHdr;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.SmallTest;
 import android.system.ErrnoException;
 import android.system.NetlinkSocketAddress;
 import android.system.OsConstants;
 import android.util.Log;
+
 import java.io.InterruptedIOException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
-import junit.framework.TestCase;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
 
 
-public class NetlinkSocketTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NetlinkSocketTest {
     private final String TAG = "NetlinkSocketTest";
 
-    @SmallTest
+    @Test
     public void testBasicWorkingGetNeighborsQuery() throws Exception {
         NetlinkSocket s = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
         assertNotNull(s);
@@ -93,7 +103,7 @@
         s.close();
     }
 
-    @SmallTest
+    @Test
     public void testRepeatedCloseCallsAreQuiet() throws Exception {
         // Create a working NetlinkSocket.
         NetlinkSocket s = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
diff --git a/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java b/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java
index 029758e..c9fd74f 100644
--- a/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java
+++ b/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java
@@ -16,15 +16,19 @@
 
 package android.net.netlink;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
 import android.net.netlink.NetlinkConstants;
 import android.net.netlink.NetlinkMessage;
 import android.net.netlink.RtNetlinkNeighborMessage;
 import android.net.netlink.StructNdMsg;
 import android.net.netlink.StructNlMsgHdr;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.SmallTest;
 import android.system.OsConstants;
 import android.util.Log;
-import libcore.util.HexEncoding;
 
 import java.net.Inet4Address;
 import java.net.InetAddress;
@@ -32,10 +36,15 @@
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.Arrays;
-import junit.framework.TestCase;
 
+import org.junit.runner.RunWith;
+import org.junit.Test;
 
-public class RtNetlinkNeighborMessageTest extends TestCase {
+import libcore.util.HexEncoding;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class RtNetlinkNeighborMessageTest {
     private final String TAG = "RtNetlinkNeighborMessageTest";
 
     // Hexadecimal representation of packet capture.
@@ -136,7 +145,7 @@
     public static final byte[] RTM_GETNEIGH_RESPONSE =
             HexEncoding.decode(RTM_GETNEIGH_RESPONSE_HEX.replaceAll(" ", "").toCharArray(), false);
 
-    @SmallTest
+    @Test
     public void testParseRtmDelNeigh() {
         final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_DELNEIGH);
         byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
@@ -163,7 +172,7 @@
         assertEquals(InetAddress.parseNumericAddress("192.168.159.254"), destination);
     }
 
-    @SmallTest
+    @Test
     public void testParseRtmNewNeigh() {
         final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_NEWNEIGH);
         byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
@@ -190,7 +199,7 @@
         assertEquals(InetAddress.parseNumericAddress("fe80::86c9:b2ff:fe6a:ed4b"), destination);
     }
 
-    @SmallTest
+    @Test
     public void testParseRtmGetNeighResponse() {
         final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_GETNEIGH_RESPONSE);
         byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
@@ -215,7 +224,7 @@
         assertEquals(14, messageCount);
     }
 
-    @SmallTest
+    @Test
     public void testCreateRtmNewNeighMessage() {
         final int seqNo = 2635;
         final int ifIndex = 14;
diff --git a/tests/net/java/android/net/util/BlockingSocketReaderTest.java b/tests/net/java/android/net/util/BlockingSocketReaderTest.java
index 1aad453..29dfa4c 100644
--- a/tests/net/java/android/net/util/BlockingSocketReaderTest.java
+++ b/tests/net/java/android/net/util/BlockingSocketReaderTest.java
@@ -18,15 +18,19 @@
 
 import static android.net.util.BlockingSocketReader.DEFAULT_RECV_BUF_SIZE;
 import static android.system.OsConstants.*;
+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 android.os.Handler;
 import android.os.HandlerThread;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.StructTimeval;
 
-import libcore.io.IoBridge;
-
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -41,15 +45,21 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import junit.framework.TestCase;
+import org.junit.runner.RunWith;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
 
+import libcore.io.IoBridge;
 
 /**
  * Tests for BlockingSocketReader.
  *
  * @hide
  */
-public class BlockingSocketReaderTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class BlockingSocketReaderTest {
     static final InetAddress LOOPBACK6 = Inet6Address.getLoopbackAddress();
     static final StructTimeval TIMEO = StructTimeval.fromMillis(500);
 
@@ -103,7 +113,7 @@
         }
     };
 
-    @Override
+    @Before
     public void setUp() {
         resetLatch();
         mLocalSocket = null;
@@ -115,7 +125,7 @@
         mHandlerThread.start();
     }
 
-    @Override
+    @After
     public void tearDown() throws Exception {
         if (mReceiver != null) {
             mHandlerThread.getThreadHandler().post(() -> { mReceiver.stop(); });
@@ -143,6 +153,7 @@
         sender.close();
     }
 
+    @Test
     public void testBasicWorking() throws Exception {
         final Handler h = mHandlerThread.getThreadHandler();
         mReceiver = new UdpLoopbackReader(h);
@@ -186,6 +197,7 @@
         public FileDescriptor createFd() { return null; }
     }
 
+    @Test
     public void testMinimalRecvBufSize() throws Exception {
         final Handler h = mHandlerThread.getThreadHandler();
 
diff --git a/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java b/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java
index dd679bc..38d3d74 100644
--- a/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java
+++ b/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java
@@ -17,18 +17,25 @@
 package android.net.util;
 
 import static android.net.util.NetworkConstants.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.SmallTest;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
 
 import libcore.util.HexEncoding;
 
-import junit.framework.TestCase;
-
-
 /**
  * Tests for ConnectivityPacketSummary.
  *
  * @hide
  */
-public class ConnectivityPacketSummaryTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ConnectivityPacketSummaryTest {
     private static final byte[] MYHWADDR = {
         asByte(0x80), asByte(0x7a), asByte(0xbf), asByte(0x6f), asByte(0x48), asByte(0xf3)
     };
@@ -39,6 +46,7 @@
         return ConnectivityPacketSummary.summarize(MYHWADDR, bytes);
     }
 
+    @Test
     public void testParseICMPv6DADProbe() {
         final String packet =
                 // Ethernet
@@ -60,6 +68,7 @@
         assertEquals(expected, getSummary(packet));
     }
 
+    @Test
     public void testParseICMPv6RS() {
         final String packet =
                 // Ethernet
@@ -81,6 +90,7 @@
         assertEquals(expected, getSummary(packet));
     }
 
+    @Test
     public void testParseICMPv6RA() {
         final String packet =
                 // Ethernet
@@ -113,6 +123,7 @@
         assertEquals(expected, getSummary(packet));
     }
 
+    @Test
     public void testParseICMPv6NS() {
         final String packet =
                 // Ethernet
@@ -135,6 +146,7 @@
         assertEquals(expected, getSummary(packet));
     }
 
+    @Test
     public void testInvalidICMPv6NDLength() {
         final String packet =
                 // Ethernet
@@ -159,6 +171,7 @@
         assertEquals(expected, getSummary(packet));
     }
 
+    @Test
     public void testParseICMPv6NA() {
         final String packet =
                 // Ethernet
@@ -179,6 +192,7 @@
         assertEquals(expected, getSummary(packet));
     }
 
+    @Test
     public void testParseARPRequest() {
         final String packet =
                 // Ethernet
@@ -197,6 +211,7 @@
         assertEquals(expected, getSummary(packet));
     }
 
+    @Test
     public void testParseARPReply() {
         final String packet =
                 // Ethernet
@@ -217,6 +232,7 @@
         assertEquals(expected, getSummary(packet));
     }
 
+    @Test
     public void testParseDHCPv4Discover() {
         final String packet =
                 // Ethernet
@@ -262,6 +278,7 @@
         assertTrue(getSummary(packet).startsWith(expectedPrefix));
     }
 
+    @Test
     public void testParseDHCPv4Offer() {
         final String packet =
                 // Ethernet
@@ -307,6 +324,7 @@
         assertTrue(getSummary(packet).startsWith(expectedPrefix));
     }
 
+    @Test
     public void testParseDHCPv4Request() {
         final String packet =
                 // Ethernet
@@ -354,6 +372,7 @@
         assertTrue(getSummary(packet).startsWith(expectedPrefix));
     }
 
+    @Test
     public void testParseDHCPv4Ack() {
         final String packet =
                 // Ethernet
diff --git a/tests/net/java/android/net/util/IpUtilsTest.java b/tests/net/java/android/net/util/IpUtilsTest.java
index c2d1608..8903bf9 100644
--- a/tests/net/java/android/net/util/IpUtilsTest.java
+++ b/tests/net/java/android/net/util/IpUtilsTest.java
@@ -16,15 +16,19 @@
 
 package android.net.util;
 
-import android.net.util.IpUtils;
-import android.test.suitebuilder.annotation.SmallTest;
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.SmallTest;
 
 import java.nio.ByteBuffer;
 
-import junit.framework.TestCase;
+import org.junit.runner.RunWith;
+import org.junit.Test;
 
-
-public class IpUtilsTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IpUtilsTest {
 
     private static final int IPV4_HEADER_LENGTH = 20;
     private static final int IPV6_HEADER_LENGTH = 40;
@@ -67,7 +71,7 @@
     //           "hello")
     // print JavaPacketDefinition(str(packet))
 
-    @SmallTest
+    @Test
     public void testIpv6TcpChecksum() throws Exception {
         // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80) /
         //           scapy.TCP(sport=12345, dport=7,
@@ -115,7 +119,7 @@
         assertEquals(0, IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen));
     }
 
-    @SmallTest
+    @Test
     public void testIpv4UdpChecksum() {
         // packet = (scapy.IP(src="192.0.2.1", dst="192.0.2.2", tos=0x40) /
         //           scapy.UDP(sport=32012, dport=4500) /
diff --git a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
index a423c2a..fb2bd79 100644
--- a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
+++ b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
@@ -24,12 +24,15 @@
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
 import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 
 import android.content.res.Resources;
 import android.net.NetworkStats;
 import android.net.TrafficStats;
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
-import android.test.AndroidTestCase;
+import android.support.test.runner.AndroidJUnit4;
 
 import com.android.frameworks.tests.net.R;
 
@@ -42,19 +45,23 @@
 import libcore.io.IoUtils;
 import libcore.io.Streams;
 
+import org.junit.runner.RunWith;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
 /**
  * Tests for {@link NetworkStatsFactory}.
  */
+@RunWith(AndroidJUnit4.class)
 @SmallTest
-public class NetworkStatsFactoryTest extends AndroidTestCase {
+public class NetworkStatsFactoryTest {
     private File mTestProc;
     private NetworkStatsFactory mFactory;
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
-
-        mTestProc = new File(getContext().getFilesDir(), "proc");
+        mTestProc = new File(InstrumentationRegistry.getContext().getFilesDir(), "proc");
         if (mTestProc.exists()) {
             IoUtils.deleteContents(mTestProc);
         }
@@ -62,17 +69,16 @@
         mFactory = new NetworkStatsFactory(mTestProc);
     }
 
-    @Override
+    @After
     public void tearDown() throws Exception {
         mFactory = null;
 
         if (mTestProc.exists()) {
             IoUtils.deleteContents(mTestProc);
         }
-
-        super.tearDown();
     }
 
+    @Test
     public void testNetworkStatsDetail() throws Exception {
         final NetworkStats stats = parseDetailedStats(R.raw.xt_qtaguid_typical);
 
@@ -84,6 +90,7 @@
         assertStatsEntry(stats, "rmnet2", 10001, SET_DEFAULT, 0x0, 1125899906842624L, 984L);
     }
 
+    @Test
     public void testKernelTags() throws Exception {
         assertEquals(0, kernelToTag("0x0000000000000000"));
         assertEquals(0x32, kernelToTag("0x0000003200000000"));
@@ -98,6 +105,7 @@
         assertEquals(TrafficStats.TAG_SYSTEM_DOWNLOAD, kernelToTag("0xffffff0100000000"));
     }
 
+    @Test
     public void testNetworkStatsWithSet() throws Exception {
         final NetworkStats stats = parseDetailedStats(R.raw.xt_qtaguid_typical);
         assertEquals(70, stats.size());
@@ -106,6 +114,7 @@
         assertStatsEntry(stats, "rmnet1", 10021, SET_FOREGROUND, 0x30100000, 742L, 3L, 1265L, 3L);
     }
 
+    @Test
     public void testNetworkStatsSingle() throws Exception {
         stageFile(R.raw.xt_qtaguid_iface_typical, file("net/xt_qtaguid/iface_stat_all"));
 
@@ -116,6 +125,7 @@
         assertStatsEntry(stats, "test2", UID_ALL, SET_ALL, TAG_NONE, 1L, 2L, 3L, 4L);
     }
 
+    @Test
     public void testNetworkStatsXt() throws Exception {
         stageFile(R.raw.xt_qtaguid_iface_fmt_typical, file("net/xt_qtaguid/iface_stat_fmt"));
 
@@ -127,6 +137,7 @@
         assertStatsEntry(stats, "rmnet2", UID_ALL, SET_ALL, TAG_NONE, 4968L, 35L, 3081L, 39L);
     }
 
+    @Test
     public void testDoubleClatAccounting() throws Exception {
         NetworkStatsFactory.noteStackedIface("v4-wlan0", "wlan0");
 
@@ -161,6 +172,7 @@
         NetworkStatsFactory.noteStackedIface("v4-wlan0", null);
     }
 
+    @Test
     public void testDoubleClatAccounting100MBDownload() throws Exception {
         // Downloading 100mb from an ipv4 only destination in a foreground activity
 
@@ -197,7 +209,7 @@
         InputStream in = null;
         OutputStream out = null;
         try {
-            in = getContext().getResources().openRawResource(rawId);
+            in = InstrumentationRegistry.getContext().getResources().openRawResource(rawId);
             out = new FileOutputStream(file);
             Streams.copy(in, out);
         } finally {
@@ -251,5 +263,4 @@
         assertEquals("unexpected txBytes", txBytes, entry.txBytes);
         assertEquals("unexpected txPackets", txPackets, entry.txPackets);
     }
-
 }
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 335e6240..c2cb66d 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -26,8 +26,13 @@
 import static android.net.ConnectivityManager.getNetworkTypeName;
 import static android.net.NetworkCapabilities.*;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
 import static com.android.internal.util.TestUtils.waitForIdleHandler;
-
 import static org.mockito.Mockito.anyBoolean;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.eq;
@@ -87,9 +92,10 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.mock.MockContentResolver;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
@@ -105,7 +111,11 @@
 import com.android.server.net.NetworkPinner;
 import com.android.server.net.NetworkPolicyManagerInternal;
 
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.Spy;
@@ -123,13 +133,16 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Predicate;
 
+
 /**
  * Tests for {@link ConnectivityService}.
  *
  * Build, install and run with:
  *  runtest frameworks-net -c com.android.server.ConnectivityServiceTest
  */
-public class ConnectivityServiceTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ConnectivityServiceTest {
     private static final String TAG = "ConnectivityServiceTest";
 
     private static final int TIMEOUT_MS = 500;
@@ -141,6 +154,7 @@
     private MockNetworkAgent mWiFiNetworkAgent;
     private MockNetworkAgent mCellNetworkAgent;
     private MockNetworkAgent mEthernetNetworkAgent;
+    private Context mContext;
 
     // This class exists to test bindProcessToNetwork and getBoundNetworkForProcess. These methods
     // do not go through ConnectivityService but talk to netd directly, so they don't automatically
@@ -242,7 +256,7 @@
         waitForIdle(TIMEOUT_MS);
     }
 
-    @SmallTest
+    @Test
     public void testWaitForIdle() {
         final int attempts = 50;  // Causes the test to take about 200ms on bullhead-eng.
 
@@ -743,7 +757,8 @@
 
                 // Don't overlap test NetIDs with real NetIDs as binding sockets to real networks
                 // can have odd side-effects, like network validations succeeding.
-                final Network[] networks = ConnectivityManager.from(getContext()).getAllNetworks();
+                Context context = InstrumentationRegistry.getContext();
+                final Network[] networks = ConnectivityManager.from(context).getAllNetworks();
                 boolean overlaps = false;
                 for (Network network : networks) {
                     if (netId == network.netId) {
@@ -814,9 +829,9 @@
         fail("ConditionVariable was blocked for more than " + TIMEOUT_MS + "ms");
     }
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
+        mContext = InstrumentationRegistry.getContext();
 
         // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
         // http://b/25897652 .
@@ -824,7 +839,7 @@
             Looper.prepare();
         }
 
-        mServiceContext = new MockContext(getContext());
+        mServiceContext = new MockContext(InstrumentationRegistry.getContext());
         LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
         LocalServices.addService(
                 NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class));
@@ -835,7 +850,7 @@
                 mock(IpConnectivityLog.class));
 
         mService.systemReady();
-        mCm = new WrappedConnectivityManager(getContext(), mService);
+        mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService);
         mCm.bindProcessToNetwork(null);
 
         // Ensure that the default setting for Captive Portals is used for most tests
@@ -843,6 +858,7 @@
         setMobileDataAlwaysOn(false);
     }
 
+    @After
     public void tearDown() throws Exception {
         setMobileDataAlwaysOn(false);
         if (mCellNetworkAgent != null) {
@@ -857,7 +873,6 @@
             mEthernetNetworkAgent.disconnect();
             mEthernetNetworkAgent = null;
         }
-        super.tearDown();
     }
 
     private static int transportToLegacyType(int transport) {
@@ -931,6 +946,7 @@
         return cv;
     }
 
+    @Test
     public void testNetworkTypes() {
         // Ensure that our mocks for the networkAttributes config variable work as expected. If they
         // don't, then tests that depend on CONNECTIVITY_ACTION broadcasts for these network types
@@ -946,7 +962,7 @@
         assertTrue(mCm.isNetworkSupported(TYPE_ETHERNET));
     }
 
-    @SmallTest
+    @Test
     public void testLingering() throws Exception {
         verifyNoNetwork();
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -987,7 +1003,7 @@
         verifyNoNetwork();
     }
 
-    @SmallTest
+    @Test
     public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception {
         // Test bringing up unvalidated WiFi
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -1022,7 +1038,7 @@
         verifyNoNetwork();
     }
 
-    @SmallTest
+    @Test
     public void testUnvalidatedWifiOutscoresUnvalidatedCellular() throws Exception {
         // Test bringing up unvalidated cellular.
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -1048,7 +1064,7 @@
         verifyNoNetwork();
     }
 
-    @SmallTest
+    @Test
     public void testUnlingeringDoesNotValidate() throws Exception {
         // Test bringing up unvalidated WiFi.
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -1076,7 +1092,7 @@
                 NET_CAPABILITY_VALIDATED));
     }
 
-    @SmallTest
+    @Test
     public void testCellularOutscoresWeakWifi() throws Exception {
         // Test bringing up validated cellular.
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -1102,7 +1118,7 @@
         verifyActiveNetwork(TRANSPORT_WIFI);
     }
 
-    @SmallTest
+    @Test
     public void testReapingNetwork() throws Exception {
         // Test bringing up WiFi without NET_CAPABILITY_INTERNET.
         // Expect it to be torn down immediately because it satisfies no requests.
@@ -1135,7 +1151,7 @@
         waitFor(cv);
     }
 
-    @SmallTest
+    @Test
     public void testCellularFallback() throws Exception {
         // Test bringing up validated cellular.
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -1173,7 +1189,7 @@
         verifyActiveNetwork(TRANSPORT_WIFI);
     }
 
-    @SmallTest
+    @Test
     public void testWiFiFallback() throws Exception {
         // Test bringing up unvalidated WiFi.
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -1387,7 +1403,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testStateChangeNetworkCallbacks() throws Exception {
         final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
         final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
@@ -1477,7 +1493,7 @@
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
     }
 
-    @SmallTest
+    @Test
     public void testMultipleLingering() {
         NetworkRequest request = new NetworkRequest.Builder()
                 .clearCapabilities().addCapability(NET_CAPABILITY_NOT_METERED)
@@ -1705,7 +1721,7 @@
         mCm.unregisterNetworkCallback(trackDefaultCallback);
     }
 
-    @SmallTest
+    @Test
     public void testExplicitlySelected() {
         NetworkRequest request = new NetworkRequest.Builder()
                 .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
@@ -1872,7 +1888,7 @@
         handlerThread.quit();
     }
 
-    @SmallTest
+    @Test
     public void testNetworkFactoryRequests() throws Exception {
         tryNetworkFactoryRequests(NET_CAPABILITY_MMS);
         tryNetworkFactoryRequests(NET_CAPABILITY_SUPL);
@@ -1892,7 +1908,7 @@
         // Skipping VALIDATED and CAPTIVE_PORTAL as they're disallowed.
     }
 
-    @SmallTest
+    @Test
     public void testNoMutableNetworkRequests() throws Exception {
         PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent("a"), 0);
         NetworkRequest request1 = new NetworkRequest.Builder()
@@ -1909,7 +1925,7 @@
         assertException(() -> { mCm.requestNetwork(request2, pendingIntent); }, expected);
     }
 
-    @SmallTest
+    @Test
     public void testMMSonWiFi() throws Exception {
         // Test bringing up cellular without MMS NetworkRequest gets reaped
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -1948,7 +1964,7 @@
         verifyActiveNetwork(TRANSPORT_WIFI);
     }
 
-    @SmallTest
+    @Test
     public void testMMSonCell() throws Exception {
         // Test bringing up cellular without MMS
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -1977,7 +1993,7 @@
         verifyActiveNetwork(TRANSPORT_CELLULAR);
     }
 
-    @SmallTest
+    @Test
     public void testCaptivePortal() {
         final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
         final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
@@ -2028,7 +2044,7 @@
         validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
     }
 
-    @SmallTest
+    @Test
     public void testCaptivePortalApp() {
         final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
         final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
@@ -2074,7 +2090,7 @@
         mCm.unregisterNetworkCallback(captivePortalCallback);
     }
 
-    @SmallTest
+    @Test
     public void testAvoidOrIgnoreCaptivePortals() {
         final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
         final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
@@ -2119,7 +2135,7 @@
         return new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI);
     }
 
-    @SmallTest
+    @Test
     public void testNetworkSpecifier() {
         NetworkRequest rEmpty1 = newWifiRequestBuilder().build();
         NetworkRequest rEmpty2 = newWifiRequestBuilder().setNetworkSpecifier((String) null).build();
@@ -2180,7 +2196,7 @@
         assertNoCallbacks(cEmpty1, cEmpty2, cEmpty3, cFoo, cBar);
     }
 
-    @SmallTest
+    @Test
     public void testInvalidNetworkSpecifier() {
         try {
             NetworkRequest.Builder builder = new NetworkRequest.Builder();
@@ -2241,7 +2257,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testNetworkSpecifierUidSpoofSecurityException() {
         class UidAwareNetworkSpecifier extends NetworkSpecifier implements Parcelable {
             @Override
@@ -2275,7 +2291,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testRegisterDefaultNetworkCallback() throws Exception {
         final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
@@ -2324,7 +2340,7 @@
         defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
     }
 
-    @SmallTest
+    @Test
     public void testAdditionalStateCallbacks() throws Exception {
         // File a network request for mobile.
         final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
@@ -2385,7 +2401,7 @@
         return nc.hasCapability(NET_CAPABILITY_FOREGROUND);
     }
 
-    @SmallTest
+    @Test
     public void testBackgroundNetworks() throws Exception {
         // Create a background request. We can't do this ourselves because ConnectivityService
         // doesn't have an API for it. So just turn on mobile data always on.
@@ -2554,7 +2570,7 @@
         return false;
     }
 
-    @SmallTest
+    @Test
     public void testMobileDataAlwaysOn() throws Exception {
         final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
         final NetworkRequest cellRequest = new NetworkRequest.Builder()
@@ -2619,7 +2635,7 @@
         handlerThread.quit();
     }
 
-    @SmallTest
+    @Test
     public void testAvoidBadWifiSetting() throws Exception {
         final ContentResolver cr = mServiceContext.getContentResolver();
         final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
@@ -2657,7 +2673,7 @@
         assertTrue(tracker.shouldNotifyWifiUnvalidated());
     }
 
-    @SmallTest
+    @Test
     public void testAvoidBadWifi() throws Exception {
         final ContentResolver cr = mServiceContext.getContentResolver();
         final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
@@ -2784,7 +2800,7 @@
         mCm.unregisterNetworkCallback(defaultCallback);
     }
 
-    @SmallTest
+    @Test
     public void testMeteredMultipathPreferenceSetting() throws Exception {
         final ContentResolver cr = mServiceContext.getContentResolver();
         final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
@@ -2808,7 +2824,7 @@
      * Validate that a satisfied network request does not trigger onUnavailable() once the
      * time-out period expires.
      */
-    @SmallTest
+    @Test
     public void testSatisfiedNetworkRequestDoesNotTriggerOnUnavailable() {
         NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
                 NetworkCapabilities.TRANSPORT_WIFI).build();
@@ -2828,7 +2844,7 @@
      * Validate that a satisfied network request followed by a disconnected (lost) network does
      * not trigger onUnavailable() once the time-out period expires.
      */
-    @SmallTest
+    @Test
     public void testSatisfiedThenLostNetworkRequestDoesNotTriggerOnUnavailable() {
         NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
                 NetworkCapabilities.TRANSPORT_WIFI).build();
@@ -2852,7 +2868,7 @@
      * callback is called when time-out expires. Then validate that if network request is
      * (somehow) satisfied - the callback isn't called later.
      */
-    @SmallTest
+    @Test
     public void testTimedoutNetworkRequest() {
         NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
                 NetworkCapabilities.TRANSPORT_WIFI).build();
@@ -2873,7 +2889,7 @@
      * Validate that when a network request is unregistered (cancelled), no posterior event can
      * trigger the callback.
      */
-    @SmallTest
+    @Test
     public void testNoCallbackAfterUnregisteredNetworkRequest() {
         NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
                 NetworkCapabilities.TRANSPORT_WIFI).build();
@@ -2981,7 +2997,7 @@
         return mWiFiNetworkAgent.getNetwork();
     }
 
-    @SmallTest
+    @Test
     public void testPacketKeepalives() throws Exception {
         InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
         InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
@@ -3105,7 +3121,7 @@
         callback3.expectStopped();
     }
 
-    @SmallTest
+    @Test
     public void testGetCaptivePortalServerUrl() throws Exception {
         String url = mCm.getCaptivePortalServerUrl();
         assertEquals("http://connectivitycheck.gstatic.com/generate_204", url);
@@ -3150,7 +3166,7 @@
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
     }
 
-    @SmallTest
+    @Test
     public void testNetworkPinner() {
         NetworkRequest wifiRequest = new NetworkRequest.Builder()
                 .addTransportType(TRANSPORT_WIFI)
@@ -3210,7 +3226,7 @@
         assertPinnedToWifiWithCellDefault();
     }
 
-    @SmallTest
+    @Test
     public void testNetworkCallbackMaximum() {
         final int MAX_REQUESTS = 100;
         final int CALLBACKS = 90;
@@ -3280,12 +3296,14 @@
             mCm.requestNetwork(networkRequest, networkCallback);
             mCm.unregisterNetworkCallback(networkCallback);
         }
+        waitForIdle();
 
         for (int i = 0; i < MAX_REQUESTS; i++) {
             NetworkCallback networkCallback = new NetworkCallback();
             mCm.registerNetworkCallback(networkRequest, networkCallback);
             mCm.unregisterNetworkCallback(networkCallback);
         }
+        waitForIdle();
 
         for (int i = 0; i < MAX_REQUESTS; i++) {
             PendingIntent pendingIntent =
@@ -3293,6 +3311,7 @@
             mCm.requestNetwork(networkRequest, pendingIntent);
             mCm.unregisterNetworkCallback(pendingIntent);
         }
+        waitForIdle();
 
         for (int i = 0; i < MAX_REQUESTS; i++) {
             PendingIntent pendingIntent =
@@ -3302,7 +3321,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testNetworkInfoOfTypeNone() {
         ConditionVariable broadcastCV = waitForConnectivityBroadcasts(1);
 
@@ -3342,7 +3361,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testDeprecatedAndUnsupportedOperations() throws Exception {
         final int TYPE_NONE = ConnectivityManager.TYPE_NONE;
         assertNull(mCm.getNetworkInfo(TYPE_NONE));
@@ -3363,7 +3382,7 @@
         assertException(() -> { mCm.requestRouteToHostAddress(TYPE_NONE, null); }, unsupported);
     }
 
-    @SmallTest
+    @Test
     public void testLinkPropertiesEnsuresDirectlyConnectedRoutes() {
         final NetworkRequest networkRequest = new NetworkRequest.Builder()
                 .addTransportType(TRANSPORT_WIFI).build();
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 9057a10..b4b8094 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -17,10 +17,12 @@
 package com.android.server;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNull;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -37,7 +39,6 @@
 import android.os.Binder;
 import android.os.ParcelFileDescriptor;
 import android.support.test.filters.SmallTest;
-import android.system.OsConstants;
 
 import java.net.Socket;
 import java.util.Arrays;
@@ -53,8 +54,8 @@
 @RunWith(Parameterized.class)
 public class IpSecServiceParameterizedTest {
 
-    private static final int DROID_SPI = 0xD1201D;
-    private static final int DROID_SPI2 = DROID_SPI + 1;
+    private static final int TEST_SPI_OUT = 0xD1201D;
+    private static final int TEST_SPI_IN = TEST_SPI_OUT + 1;
 
     private final String mRemoteAddr;
 
@@ -81,6 +82,16 @@
     IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
     IpSecService mIpSecService;
 
+    private static final IpSecAlgorithm AUTH_ALGO =
+            new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4);
+    private static final IpSecAlgorithm CRYPT_ALGO =
+            new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
+    private static final IpSecAlgorithm AEAD_ALGO =
+            new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, CRYPT_KEY, CRYPT_KEY.length * 4);
+
+    private static final int[] DIRECTIONS =
+            new int[] {IpSecTransform.DIRECTION_IN, IpSecTransform.DIRECTION_OUT};
+
     public IpSecServiceParameterizedTest(String remoteAddr) {
         mRemoteAddr = remoteAddr;
     }
@@ -103,14 +114,14 @@
                         eq(IpSecTransform.DIRECTION_OUT),
                         anyString(),
                         eq(mRemoteAddr),
-                        eq(DROID_SPI)))
-                .thenReturn(DROID_SPI);
+                        eq(TEST_SPI_OUT)))
+                .thenReturn(TEST_SPI_OUT);
 
         IpSecSpiResponse spiResp =
                 mIpSecService.reserveSecurityParameterIndex(
-                        IpSecTransform.DIRECTION_OUT, mRemoteAddr, DROID_SPI, new Binder());
+                        IpSecTransform.DIRECTION_OUT, mRemoteAddr, TEST_SPI_OUT, new Binder());
         assertEquals(IpSecManager.Status.OK, spiResp.status);
-        assertEquals(DROID_SPI, spiResp.spi);
+        assertEquals(TEST_SPI_OUT, spiResp.spi);
     }
 
     @Test
@@ -120,56 +131,60 @@
                         eq(IpSecTransform.DIRECTION_OUT),
                         anyString(),
                         eq(mRemoteAddr),
-                        eq(DROID_SPI)))
-                .thenReturn(DROID_SPI);
+                        eq(TEST_SPI_OUT)))
+                .thenReturn(TEST_SPI_OUT);
 
         IpSecSpiResponse spiResp =
                 mIpSecService.reserveSecurityParameterIndex(
-                        IpSecTransform.DIRECTION_OUT, mRemoteAddr, DROID_SPI, new Binder());
+                        IpSecTransform.DIRECTION_OUT, mRemoteAddr, TEST_SPI_OUT, new Binder());
 
         mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId);
 
         verify(mMockNetd)
                 .ipSecDeleteSecurityAssociation(
-                        eq(spiResp.resourceId), anyInt(), anyString(), anyString(), eq(DROID_SPI));
+                        eq(spiResp.resourceId),
+                        anyInt(),
+                        anyString(),
+                        anyString(),
+                        eq(TEST_SPI_OUT));
     }
 
-    IpSecConfig buildIpSecConfig() throws Exception {
-        IpSecManager ipSecManager = new IpSecManager(mIpSecService);
-
-        // Mocking the netd to allocate SPI
+    private int getNewSpiResourceId(int direction, String remoteAddress, int returnSpi)
+            throws Exception {
         when(mMockNetd.ipSecAllocateSpi(anyInt(), anyInt(), anyString(), anyString(), anyInt()))
-                .thenReturn(DROID_SPI)
-                .thenReturn(DROID_SPI2);
+                .thenReturn(returnSpi);
 
-        IpSecAlgorithm encryptAlgo = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
-        IpSecAlgorithm authAlgo =
-                new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 8);
+        IpSecSpiResponse spi =
+                mIpSecService.reserveSecurityParameterIndex(
+                        direction,
+                        NetworkUtils.numericToInetAddress(remoteAddress).getHostAddress(),
+                        IpSecManager.INVALID_SECURITY_PARAMETER_INDEX,
+                        new Binder());
+        return spi.resourceId;
+    }
 
-        /** Allocate and add SPI records in the IpSecService through IpSecManager interface. */
-        IpSecManager.SecurityParameterIndex outSpi =
-                ipSecManager.reserveSecurityParameterIndex(
-                        IpSecTransform.DIRECTION_OUT,
-                        NetworkUtils.numericToInetAddress(mRemoteAddr));
-        IpSecManager.SecurityParameterIndex inSpi =
-                ipSecManager.reserveSecurityParameterIndex(
-                        IpSecTransform.DIRECTION_IN,
-                        NetworkUtils.numericToInetAddress(mRemoteAddr));
-
-        IpSecConfig config = new IpSecConfig();
-        config.setSpiResourceId(IpSecTransform.DIRECTION_IN, inSpi.getResourceId());
-        config.setSpiResourceId(IpSecTransform.DIRECTION_OUT, outSpi.getResourceId());
-        config.setEncryption(IpSecTransform.DIRECTION_OUT, encryptAlgo);
-        config.setAuthentication(IpSecTransform.DIRECTION_OUT, authAlgo);
-        config.setEncryption(IpSecTransform.DIRECTION_IN, encryptAlgo);
-        config.setAuthentication(IpSecTransform.DIRECTION_IN, authAlgo);
+    private void addDefaultSpisAndRemoteAddrToIpSecConfig(IpSecConfig config) throws Exception {
+        config.setSpiResourceId(
+                IpSecTransform.DIRECTION_OUT,
+                getNewSpiResourceId(IpSecTransform.DIRECTION_OUT, mRemoteAddr, TEST_SPI_OUT));
+        config.setSpiResourceId(
+                IpSecTransform.DIRECTION_IN,
+                getNewSpiResourceId(IpSecTransform.DIRECTION_IN, mRemoteAddr, TEST_SPI_IN));
         config.setRemoteAddress(mRemoteAddr);
-        return config;
+    }
+
+    private void addAuthAndCryptToIpSecConfig(IpSecConfig config) throws Exception {
+        for (int direction : DIRECTIONS) {
+            config.setEncryption(direction, CRYPT_ALGO);
+            config.setAuthentication(direction, AUTH_ALGO);
+        }
     }
 
     @Test
     public void testCreateTransportModeTransform() throws Exception {
-        IpSecConfig ipSecConfig = buildIpSecConfig();
+        IpSecConfig ipSecConfig = new IpSecConfig();
+        addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
+        addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
                 mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
@@ -183,13 +198,72 @@
                         anyString(),
                         anyString(),
                         anyLong(),
-                        eq(DROID_SPI),
+                        eq(TEST_SPI_OUT),
                         eq(IpSecAlgorithm.AUTH_HMAC_SHA256),
                         eq(AUTH_KEY),
                         anyInt(),
                         eq(IpSecAlgorithm.CRYPT_AES_CBC),
                         eq(CRYPT_KEY),
                         anyInt(),
+                        eq(""),
+                        isNull(),
+                        eq(0),
+                        anyInt(),
+                        anyInt(),
+                        anyInt());
+        verify(mMockNetd)
+                .ipSecAddSecurityAssociation(
+                        eq(createTransformResp.resourceId),
+                        anyInt(),
+                        eq(IpSecTransform.DIRECTION_IN),
+                        anyString(),
+                        anyString(),
+                        anyLong(),
+                        eq(TEST_SPI_IN),
+                        eq(IpSecAlgorithm.AUTH_HMAC_SHA256),
+                        eq(AUTH_KEY),
+                        anyInt(),
+                        eq(IpSecAlgorithm.CRYPT_AES_CBC),
+                        eq(CRYPT_KEY),
+                        anyInt(),
+                        eq(""),
+                        isNull(),
+                        eq(0),
+                        anyInt(),
+                        anyInt(),
+                        anyInt());
+    }
+
+    @Test
+    public void testCreateTransportModeTransformAead() throws Exception {
+        IpSecConfig ipSecConfig = new IpSecConfig();
+        addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
+
+        ipSecConfig.setAuthenticatedEncryption(IpSecTransform.DIRECTION_OUT, AEAD_ALGO);
+        ipSecConfig.setAuthenticatedEncryption(IpSecTransform.DIRECTION_IN, AEAD_ALGO);
+
+        IpSecTransformResponse createTransformResp =
+                mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
+        assertEquals(IpSecManager.Status.OK, createTransformResp.status);
+
+        verify(mMockNetd)
+                .ipSecAddSecurityAssociation(
+                        eq(createTransformResp.resourceId),
+                        anyInt(),
+                        eq(IpSecTransform.DIRECTION_OUT),
+                        anyString(),
+                        anyString(),
+                        anyLong(),
+                        eq(TEST_SPI_OUT),
+                        eq(""),
+                        isNull(),
+                        eq(0),
+                        eq(""),
+                        isNull(),
+                        eq(0),
+                        eq(IpSecAlgorithm.AUTH_CRYPT_AES_GCM),
+                        eq(CRYPT_KEY),
+                        anyInt(),
                         anyInt(),
                         anyInt(),
                         anyInt());
@@ -201,11 +275,14 @@
                         anyString(),
                         anyString(),
                         anyLong(),
-                        eq(DROID_SPI2),
-                        eq(IpSecAlgorithm.AUTH_HMAC_SHA256),
-                        eq(AUTH_KEY),
-                        anyInt(),
-                        eq(IpSecAlgorithm.CRYPT_AES_CBC),
+                        eq(TEST_SPI_IN),
+                        eq(""),
+                        isNull(),
+                        eq(0),
+                        eq(""),
+                        isNull(),
+                        eq(0),
+                        eq(IpSecAlgorithm.AUTH_CRYPT_AES_GCM),
                         eq(CRYPT_KEY),
                         anyInt(),
                         anyInt(),
@@ -214,8 +291,68 @@
     }
 
     @Test
+    public void testCreateInvalidConfigAeadWithAuth() throws Exception {
+        IpSecConfig ipSecConfig = new IpSecConfig();
+        addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
+
+        for (int direction : DIRECTIONS) {
+            ipSecConfig.setAuthentication(direction, AUTH_ALGO);
+            ipSecConfig.setAuthenticatedEncryption(direction, AEAD_ALGO);
+        }
+
+        try {
+            mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
+            fail(
+                    "IpSecService should have thrown an error on authentication being"
+                            + " enabled with authenticated encryption");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    @Test
+    public void testCreateInvalidConfigAeadWithCrypt() throws Exception {
+        IpSecConfig ipSecConfig = new IpSecConfig();
+        addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
+
+        for (int direction : DIRECTIONS) {
+            ipSecConfig.setEncryption(direction, CRYPT_ALGO);
+            ipSecConfig.setAuthenticatedEncryption(direction, AEAD_ALGO);
+        }
+
+        try {
+            mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
+            fail(
+                    "IpSecService should have thrown an error on encryption being"
+                            + " enabled with authenticated encryption");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    @Test
+    public void testCreateInvalidConfigAeadWithAuthAndCrypt() throws Exception {
+        IpSecConfig ipSecConfig = new IpSecConfig();
+        addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
+
+        for (int direction : DIRECTIONS) {
+            ipSecConfig.setAuthentication(direction, AUTH_ALGO);
+            ipSecConfig.setEncryption(direction, CRYPT_ALGO);
+            ipSecConfig.setAuthenticatedEncryption(direction, AEAD_ALGO);
+        }
+
+        try {
+            mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
+            fail(
+                    "IpSecService should have thrown an error on authentication and encryption being"
+                            + " enabled with authenticated encryption");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    @Test
     public void testDeleteTransportModeTransform() throws Exception {
-        IpSecConfig ipSecConfig = buildIpSecConfig();
+        IpSecConfig ipSecConfig = new IpSecConfig();
+        addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
+        addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
                 mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
@@ -227,19 +364,21 @@
                         eq(IpSecTransform.DIRECTION_OUT),
                         anyString(),
                         anyString(),
-                        eq(DROID_SPI));
+                        eq(TEST_SPI_OUT));
         verify(mMockNetd)
                 .ipSecDeleteSecurityAssociation(
                         eq(createTransformResp.resourceId),
                         eq(IpSecTransform.DIRECTION_IN),
                         anyString(),
                         anyString(),
-                        eq(DROID_SPI2));
+                        eq(TEST_SPI_IN));
     }
 
     @Test
     public void testApplyTransportModeTransform() throws Exception {
-        IpSecConfig ipSecConfig = buildIpSecConfig();
+        IpSecConfig ipSecConfig = new IpSecConfig();
+        addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
+        addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
                 mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
@@ -255,7 +394,7 @@
                         eq(IpSecTransform.DIRECTION_OUT),
                         anyString(),
                         anyString(),
-                        eq(DROID_SPI));
+                        eq(TEST_SPI_OUT));
         verify(mMockNetd)
                 .ipSecApplyTransportModeTransform(
                         eq(pfd.getFileDescriptor()),
@@ -263,7 +402,7 @@
                         eq(IpSecTransform.DIRECTION_IN),
                         anyString(),
                         anyString(),
-                        eq(DROID_SPI2));
+                        eq(TEST_SPI_IN));
     }
 
     @Test
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index efc58cc..83ee361 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -36,6 +36,7 @@
 import android.os.Binder;
 import android.os.ParcelFileDescriptor;
 import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.system.ErrnoException;
 import android.system.Os;
 
@@ -48,11 +49,10 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
 
 /** Unit tests for {@link IpSecService}. */
 @SmallTest
-@RunWith(JUnit4.class)
+@RunWith(AndroidJUnit4.class)
 public class IpSecServiceTest {
 
     private static final int DROID_SPI = 0xD1201D;
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 77956be..354cf2f 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -16,24 +16,8 @@
 
 package com.android.server.connectivity;
 
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkMisc;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.text.format.DateUtils;
-import com.android.internal.R;
-import com.android.server.ConnectivityService;
-import com.android.server.connectivity.NetworkNotificationManager;
-import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
-import junit.framework.TestCase;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyBoolean;
 import static org.mockito.Mockito.anyInt;
@@ -44,7 +28,32 @@
 import static org.mockito.Mockito.when;
 import static org.mockito.Mockito.reset;
 
-public class LingerMonitorTest extends TestCase {
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.net.NetworkMisc;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.SmallTest;
+import android.text.format.DateUtils;
+
+import com.android.internal.R;
+import com.android.server.ConnectivityService;
+import com.android.server.connectivity.NetworkNotificationManager;
+import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
+
+import org.junit.runner.RunWith;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LingerMonitorTest {
     static final String CELLULAR = "CELLULAR";
     static final String WIFI     = "WIFI";
 
@@ -62,6 +71,7 @@
     @Mock NetworkNotificationManager mNotifier;
     @Mock Resources mResources;
 
+    @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         when(mCtx.getResources()).thenReturn(mResources);
@@ -71,7 +81,7 @@
         mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, HIGH_RATE_LIMIT);
     }
 
-    @SmallTest
+    @Test
     public void testTransitions() {
         setNotificationSwitch(transition(WIFI, CELLULAR));
         NetworkAgentInfo nai1 = wifiNai(100);
@@ -81,7 +91,7 @@
         assertFalse(mMonitor.isNotificationEnabled(nai2, nai1));
     }
 
-    @SmallTest
+    @Test
     public void testNotificationOnLinger() {
         setNotificationSwitch(transition(WIFI, CELLULAR));
         setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
@@ -92,7 +102,7 @@
         verifyNotification(from, to);
     }
 
-    @SmallTest
+    @Test
     public void testToastOnLinger() {
         setNotificationSwitch(transition(WIFI, CELLULAR));
         setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
@@ -103,7 +113,7 @@
         verifyToast(from, to);
     }
 
-    @SmallTest
+    @Test
     public void testNotificationClearedAfterDisconnect() {
         setNotificationSwitch(transition(WIFI, CELLULAR));
         setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
@@ -117,7 +127,7 @@
         verify(mNotifier, times(1)).clearNotification(100);
     }
 
-    @SmallTest
+    @Test
     public void testNotificationClearedAfterSwitchingBack() {
         setNotificationSwitch(transition(WIFI, CELLULAR));
         setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
@@ -131,7 +141,7 @@
         verify(mNotifier, times(1)).clearNotification(100);
     }
 
-    @SmallTest
+    @Test
     public void testUniqueToast() {
         setNotificationSwitch(transition(WIFI, CELLULAR));
         setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
@@ -149,7 +159,7 @@
         verifyNoNotifications();
     }
 
-    @SmallTest
+    @Test
     public void testMultipleNotifications() {
         setNotificationSwitch(transition(WIFI, CELLULAR));
         setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
@@ -168,7 +178,7 @@
         verifyNotification(wifi2, cell);
     }
 
-    @SmallTest
+    @Test
     public void testRateLimiting() throws InterruptedException {
         mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, LOW_RATE_LIMIT);
 
@@ -194,7 +204,7 @@
         verifyNoNotifications();
     }
 
-    @SmallTest
+    @Test
     public void testDailyLimiting() throws InterruptedException {
         mMonitor = new TestableLingerMonitor(mCtx, mNotifier, LOW_DAILY_LIMIT, HIGH_RATE_LIMIT);
 
@@ -221,7 +231,7 @@
         verifyNoNotifications();
     }
 
-    @SmallTest
+    @Test
     public void testUniqueNotification() {
         setNotificationSwitch(transition(WIFI, CELLULAR));
         setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
@@ -238,7 +248,7 @@
         verifyNotification(from, to);
     }
 
-    @SmallTest
+    @Test
     public void testIgnoreNeverValidatedNetworks() {
         setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
         setNotificationSwitch(transition(WIFI, CELLULAR));
@@ -250,7 +260,7 @@
         verifyNoNotifications();
     }
 
-    @SmallTest
+    @Test
     public void testIgnoreCurrentlyValidatedNetworks() {
         setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
         setNotificationSwitch(transition(WIFI, CELLULAR));
@@ -262,7 +272,7 @@
         verifyNoNotifications();
     }
 
-    @SmallTest
+    @Test
     public void testNoNotificationType() {
         setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
         setNotificationSwitch();
@@ -273,7 +283,7 @@
         verifyNoNotifications();
     }
 
-    @SmallTest
+    @Test
     public void testNoTransitionToNotify() {
         setNotificationType(LingerMonitor.NOTIFY_TYPE_NONE);
         setNotificationSwitch(transition(WIFI, CELLULAR));
@@ -284,7 +294,7 @@
         verifyNoNotifications();
     }
 
-    @SmallTest
+    @Test
     public void testDifferentTransitionToNotify() {
         setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
         setNotificationSwitch(transition(CELLULAR, WIFI));
diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index 911347c..125fe725 100644
--- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -34,20 +34,29 @@
 import android.content.res.Resources;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.SmallTest;
 import android.telephony.TelephonyManager;
-import android.test.suitebuilder.annotation.SmallTest;
+
 import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import junit.framework.TestCase;
+
+import org.junit.runner.RunWith;
+import org.junit.Before;
+import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
-public class NetworkNotificationManagerTest extends TestCase {
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NetworkNotificationManagerTest {
 
     static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities();
     static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities();
@@ -71,6 +80,7 @@
 
     NetworkNotificationManager mManager;
 
+    @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mCaptor = ArgumentCaptor.forClass(Notification.class);
@@ -87,7 +97,7 @@
         mManager = new NetworkNotificationManager(mCtx, mTelephonyManager, mNotificationManager);
     }
 
-    @SmallTest
+    @Test
     public void testNotificationsShownAndCleared() {
         final int NETWORK_ID_BASE = 100;
         List<NotificationType> types = Arrays.asList(NotificationType.values());
@@ -117,7 +127,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testNoInternetNotificationsNotShownForCellular() {
         mManager.showNotification(100, NO_INTERNET, mCellNai, mWifiNai, null, false);
         mManager.showNotification(101, LOST_INTERNET, mCellNai, mWifiNai, null, false);
@@ -131,7 +141,7 @@
         verify(mNotificationManager, times(1)).notifyAsUser(eq(tag), eq(eventId), any(), any());
     }
 
-    @SmallTest
+    @Test
     public void testNotificationsNotShownIfNoInternetCapability() {
         mWifiNai.networkCapabilities = new NetworkCapabilities();
         mWifiNai.networkCapabilities .addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
@@ -142,7 +152,7 @@
         verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any());
     }
 
-    @SmallTest
+    @Test
     public void testDuplicatedNotificationsNoInternetThenSignIn() {
         final int id = 101;
         final String tag = NetworkNotificationManager.tagFor(id);
@@ -164,7 +174,7 @@
         verify(mNotificationManager, times(1)).cancelAsUser(eq(tag), eq(SIGN_IN.eventId), any());
     }
 
-    @SmallTest
+    @Test
     public void testDuplicatedNotificationsSignInThenNoInternet() {
         final int id = 101;
         final String tag = NetworkNotificationManager.tagFor(id);
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 4f18da7..fe396c3 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -20,6 +20,9 @@
 import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
 import static android.content.pm.UserInfo.FLAG_PRIMARY;
 import static android.content.pm.UserInfo.FLAG_RESTRICTED;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.AdditionalMatchers.*;
 import static org.mockito.Mockito.*;
 
@@ -42,14 +45,17 @@
 import android.os.Looper;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.SmallTest;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
 import com.android.internal.R;
 import com.android.internal.net.VpnConfig;
 
+import org.junit.runner.RunWith;
+import org.junit.Before;
+import org.junit.Test;
 import org.mockito.Answers;
 import org.mockito.InOrder;
 import org.mockito.Mock;
@@ -61,13 +67,16 @@
 import java.util.Map;
 import java.util.Set;
 
+
 /**
  * Tests for {@link Vpn}.
  *
  * Build, install and run with:
- *  runtest --path java/com/android/server/connectivity/VpnTest.java
+ *  runtest frameworks-net -c com.android.server.connectivity.VpnTest
  */
-public class VpnTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VpnTest {
     private static final String TAG = "VpnTest";
 
     // Mock users
@@ -106,7 +115,7 @@
     @Mock private NotificationManager mNotificationManager;
     @Mock private Vpn.SystemServices mSystemServices;
 
-    @Override
+    @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
@@ -130,7 +139,7 @@
         doNothing().when(mNetService).registerObserver(any());
     }
 
-    @SmallTest
+    @Test
     public void testRestrictedProfilesAreAddedToVpn() {
         setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
 
@@ -144,7 +153,7 @@
         })), ranges);
     }
 
-    @SmallTest
+    @Test
     public void testManagedProfilesAreNotAddedToVpn() {
         setMockedUsers(primaryUser, managedProfileA);
 
@@ -157,7 +166,7 @@
         })), ranges);
     }
 
-    @SmallTest
+    @Test
     public void testAddUserToVpnOnlyAddsOneUser() {
         setMockedUsers(primaryUser, restrictedProfileA, managedProfileA);
 
@@ -170,7 +179,7 @@
         })), ranges);
     }
 
-    @SmallTest
+    @Test
     public void testUidWhiteAndBlacklist() throws Exception {
         final Vpn vpn = createVpn(primaryUser.id);
         final UidRange user = UidRange.createForUser(primaryUser.id);
@@ -195,7 +204,7 @@
         })), disallow);
     }
 
-    @SmallTest
+    @Test
     public void testLockdownChangingPackage() throws Exception {
         final Vpn vpn = createVpn(primaryUser.id);
         final UidRange user = UidRange.createForUser(primaryUser.id);
@@ -230,7 +239,7 @@
         assertUnblocked(vpn, user.start + PKG_UIDS[3]);
     }
 
-    @SmallTest
+    @Test
     public void testLockdownAddingAProfile() throws Exception {
         final Vpn vpn = createVpn(primaryUser.id);
         setMockedUsers(primaryUser);
@@ -270,7 +279,7 @@
         }));
     }
 
-    @SmallTest
+    @Test
     public void testLockdownRuleRepeatability() throws Exception {
         final Vpn vpn = createVpn(primaryUser.id);
 
@@ -293,7 +302,7 @@
         verify(mNetService, times(2)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class));
     }
 
-    @SmallTest
+    @Test
     public void testLockdownRuleReversibility() throws Exception {
         final Vpn vpn = createVpn(primaryUser.id);
 
@@ -322,7 +331,7 @@
         order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
     }
 
-    @SmallTest
+    @Test
     public void testIsAlwaysOnPackageSupported() throws Exception {
         final Vpn vpn = createVpn(primaryUser.id);
 
@@ -356,7 +365,7 @@
         assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
     }
 
-    @SmallTest
+    @Test
     public void testNotificationShownForAlwaysOnApp() {
         final UserHandle userHandle = UserHandle.of(primaryUser.id);
         final Vpn vpn = createVpn(primaryUser.id);
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index 9c10264..dbaf8e6 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -26,6 +26,9 @@
 import static android.os.Process.myUid;
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
 
 import static com.android.server.net.NetworkStatsCollection.multiplySafe;
 
@@ -37,11 +40,12 @@
 import android.net.NetworkTemplate;
 import android.os.Process;
 import android.os.UserHandle;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.telephony.SubscriptionPlan;
 import android.telephony.TelephonyManager;
-import android.test.AndroidTestCase;
 import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.text.format.DateUtils;
 import android.util.RecurrenceRule;
 
@@ -64,11 +68,17 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Tests for {@link NetworkStatsCollection}.
  */
+@RunWith(AndroidJUnit4.class)
 @SmallTest
-public class NetworkStatsCollectionTest extends AndroidTestCase {
+public class NetworkStatsCollectionTest {
 
     private static final String TEST_FILE = "test.bin";
     private static final String TEST_IMSI = "310260000000000";
@@ -79,18 +89,15 @@
 
     private static Clock sOriginalClock;
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
         sOriginalClock = RecurrenceRule.sClock;
-
         // ignore any device overlay while testing
         NetworkTemplate.forceAllNetworkTypes();
     }
 
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
+    @After
+    public void tearDown() throws Exception {
         RecurrenceRule.sClock = sOriginalClock;
     }
 
@@ -98,8 +105,10 @@
         RecurrenceRule.sClock = Clock.fixed(instant, ZoneId.systemDefault());
     }
 
+    @Test
     public void testReadLegacyNetwork() throws Exception {
-        final File testFile = new File(getContext().getFilesDir(), TEST_FILE);
+        final File testFile =
+                new File(InstrumentationRegistry.getContext().getFilesDir(), TEST_FILE);
         stageFile(R.raw.netstats_v1, testFile);
 
         final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
@@ -124,8 +133,10 @@
                 636016770L, 709306L, 88038768L, 518836L, NetworkStatsAccess.Level.DEVICE);
     }
 
+    @Test
     public void testReadLegacyUid() throws Exception {
-        final File testFile = new File(getContext().getFilesDir(), TEST_FILE);
+        final File testFile =
+                new File(InstrumentationRegistry.getContext().getFilesDir(), TEST_FILE);
         stageFile(R.raw.netstats_uid_v4, testFile);
 
         final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
@@ -150,8 +161,10 @@
                 637076152L, 711413L, 88343717L, 521022L, NetworkStatsAccess.Level.DEVICE);
     }
 
+    @Test
     public void testReadLegacyUidTags() throws Exception {
-        final File testFile = new File(getContext().getFilesDir(), TEST_FILE);
+        final File testFile =
+                new File(InstrumentationRegistry.getContext().getFilesDir(), TEST_FILE);
         stageFile(R.raw.netstats_uid_v4, testFile);
 
         final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
@@ -176,6 +189,7 @@
                 77017831L, 100995L, 35436758L, 92344L);
     }
 
+    @Test
     public void testStartEndAtomicBuckets() throws Exception {
         final NetworkStatsCollection collection = new NetworkStatsCollection(HOUR_IN_MILLIS);
 
@@ -190,6 +204,7 @@
         assertEquals(2 * HOUR_IN_MILLIS, collection.getEndMillis());
     }
 
+    @Test
     public void testAccessLevels() throws Exception {
         final NetworkStatsCollection collection = new NetworkStatsCollection(HOUR_IN_MILLIS);
         final NetworkStats.Entry entry = new NetworkStats.Entry();
@@ -250,8 +265,10 @@
                 0, NetworkStatsAccess.Level.DEVICE);
     }
 
+    @Test
     public void testAugmentPlan() throws Exception {
-        final File testFile = new File(getContext().getFilesDir(), TEST_FILE);
+        final File testFile =
+                new File(InstrumentationRegistry.getContext().getFilesDir(), TEST_FILE);
         stageFile(R.raw.netstats_v1, testFile);
 
         final NetworkStatsCollection emptyCollection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
@@ -439,6 +456,7 @@
         }
     }
 
+    @Test
     public void testAugmentPlanGigantic() throws Exception {
         // We're in the future, but not that far off
         setClock(Instant.parse("2012-06-01T00:00:00.00Z"));
@@ -461,6 +479,7 @@
         assertEquals(4_939_212_386L, getHistory(large, plan, TIME_A, TIME_C).getTotalBytes());
     }
 
+    @Test
     public void testRounding() throws Exception {
         final NetworkStatsCollection coll = new NetworkStatsCollection(HOUR_IN_MILLIS);
 
@@ -482,6 +501,7 @@
         assertEquals(TIME_A - HOUR_IN_MILLIS, coll.roundDown(TIME_A - 1));
     }
 
+    @Test
     public void testMultiplySafe() {
         assertEquals(25, multiplySafe(50, 1, 2));
         assertEquals(100, multiplySafe(50, 2, 1));
@@ -510,7 +530,7 @@
         InputStream in = null;
         OutputStream out = null;
         try {
-            in = getContext().getResources().openRawResource(rawId);
+            in = InstrumentationRegistry.getContext().getResources().openRawResource(rawId);
             out = new FileOutputStream(file);
             Streams.copy(in, out);
         } finally {
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 814a626..7f1bc5b 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -85,8 +85,8 @@
 import android.os.PowerManager;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.SmallTest;
 import android.telephony.TelephonyManager;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 import android.util.TrustedTime;
 
@@ -201,7 +201,6 @@
               ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
         verify(mNetManager).registerObserver(networkObserver.capture());
         mNetworkObserver = networkObserver.getValue();
-
     }
 
     @After
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 5e85802..cb87737 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -739,12 +739,8 @@
 
     AssetManager assets;
     int32_t assetsCookie;
-    if (!assets.addAssetPath(String8(filename), &assetsCookie)) {
-        fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n");
-        return 1;
-    }
 
-    // Now add any dependencies passed in.
+    // Add any dependencies passed in.
     for (size_t i = 0; i < bundle->getPackageIncludes().size(); i++) {
       const String8& assetPath = bundle->getPackageIncludes()[i];
       if (!assets.addAssetPath(assetPath, NULL)) {
@@ -753,6 +749,11 @@
       }
     }
 
+    if (!assets.addAssetPath(String8(filename), &assetsCookie)) {
+        fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n");
+        return 1;
+    }
+
     // Make a dummy config for retrieving resources...  we need to supply
     // non-default values for some configs so that we can retrieve resources
     // in the app that don't have a default.  The most important of these is
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 52b93a9..669afe1 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -4847,6 +4847,7 @@
     const String16 animatedVector16("animated-vector");
     const String16 pathInterpolator16("pathInterpolator");
     const String16 objectAnimator16("objectAnimator");
+    const String16 gradient16("gradient");
 
     const int minSdk = getMinSdkVersion(bundle);
     if (minSdk >= SDK_LOLLIPOP_MR1) {
@@ -4874,7 +4875,8 @@
         if (bundle->getNoVersionVectors() && (node->getElementName() == vector16 ||
                     node->getElementName() == animatedVector16 ||
                     node->getElementName() == objectAnimator16 ||
-                    node->getElementName() == pathInterpolator16)) {
+                    node->getElementName() == pathInterpolator16 ||
+                    node->getElementName() == gradient16)) {
             // We were told not to version vector tags, so skip the children here.
             continue;
         }
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index ff51d51..058504d 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -84,17 +84,18 @@
         "filter/AbiFilter.cpp",
         "filter/ConfigFilter.cpp",
         "format/Archive.cpp",
+        "format/Container.cpp",
         "format/binary/BinaryResourceParser.cpp",
         "format/binary/ResChunkPullParser.cpp",
         "format/binary/TableFlattener.cpp",
         "format/binary/XmlFlattener.cpp",
         "format/proto/ProtoDeserialize.cpp",
         "format/proto/ProtoSerialize.cpp",
-        "io/BigBufferStreams.cpp",
+        "io/BigBufferStream.cpp",
         "io/File.cpp",
-        "io/FileInputStream.cpp",
+        "io/FileStream.cpp",
         "io/FileSystem.cpp",
-        "io/StringInputStream.cpp",
+        "io/StringStream.cpp",
         "io/Util.cpp",
         "io/ZipArchive.cpp",
         "link/AutoVersioner.cpp",
@@ -167,7 +168,7 @@
         "test/Builders.cpp",
         "test/Common.cpp",
         "**/*_test.cpp",
-    ],
+    ] + toolSources,
     static_libs: [
         "libaapt2",
         "libgmock",
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 1555d6126..61c304b 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -35,11 +35,11 @@
 
 namespace {
 
-class PrintVisitor : public DescendingValueVisitor {
+class PrintVisitor : public ConstValueVisitor {
  public:
-  using DescendingValueVisitor::Visit;
+  using ConstValueVisitor::Visit;
 
-  void Visit(Attribute* attr) override {
+  void Visit(const Attribute* attr) override {
     std::cout << "(attr) type=";
     attr->PrintMask(&std::cout);
     static constexpr uint32_t kMask =
@@ -55,7 +55,7 @@
     }
   }
 
-  void Visit(Style* style) override {
+  void Visit(const Style* style) override {
     std::cout << "(style)";
     if (style->parent) {
       const Reference& parent_ref = style->parent.value();
@@ -90,15 +90,15 @@
     }
   }
 
-  void Visit(Array* array) override {
+  void Visit(const Array* array) override {
     array->Print(&std::cout);
   }
 
-  void Visit(Plural* plural) override {
+  void Visit(const Plural* plural) override {
     plural->Print(&std::cout);
   }
 
-  void Visit(Styleable* styleable) override {
+  void Visit(const Styleable* styleable) override {
     std::cout << "(styleable)";
     for (const auto& attr : styleable->entries) {
       std::cout << "\n        ";
@@ -116,17 +116,17 @@
     }
   }
 
-  void VisitItem(Item* item) override {
+  void VisitItem(const Item* item) override {
     item->Print(&std::cout);
   }
 };
 
 }  // namespace
 
-void Debug::PrintTable(ResourceTable* table, const DebugPrintTableOptions& options) {
+void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options) {
   PrintVisitor visitor;
 
-  for (auto& package : table->packages) {
+  for (const auto& package : table.packages) {
     std::cout << "Package name=" << package->name;
     if (package->id) {
       std::cout << " id=" << std::hex << (int)package->id.value() << std::dec;
@@ -261,11 +261,11 @@
 
 namespace {
 
-class XmlPrinter : public xml::Visitor {
+class XmlPrinter : public xml::ConstVisitor {
  public:
-  using xml::Visitor::Visit;
+  using xml::ConstVisitor::Visit;
 
-  void Visit(xml::Element* el) override {
+  void Visit(const xml::Element* el) override {
     const size_t previous_size = prefix_.size();
 
     for (const xml::NamespaceDecl& decl : el->namespace_decls) {
@@ -301,11 +301,11 @@
     }
 
     prefix_ += "  ";
-    xml::Visitor::Visit(el);
+    xml::ConstVisitor::Visit(el);
     prefix_.resize(previous_size);
   }
 
-  void Visit(xml::Text* text) override {
+  void Visit(const xml::Text* text) override {
     std::cerr << prefix_ << "T: '" << text->text << "'\n";
   }
 
@@ -315,9 +315,9 @@
 
 }  // namespace
 
-void Debug::DumpXml(xml::XmlResource* doc) {
+void Debug::DumpXml(const xml::XmlResource& doc) {
   XmlPrinter printer;
-  doc->root->Accept(&printer);
+  doc.root->Accept(&printer);
 }
 
 }  // namespace aapt
diff --git a/tools/aapt2/Debug.h b/tools/aapt2/Debug.h
index e2456c7..296d04b 100644
--- a/tools/aapt2/Debug.h
+++ b/tools/aapt2/Debug.h
@@ -31,13 +31,11 @@
 };
 
 struct Debug {
-  static void PrintTable(ResourceTable* table,
-                         const DebugPrintTableOptions& options = {});
+  static void PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options = {});
   static void PrintStyleGraph(ResourceTable* table,
                               const ResourceName& target_style);
   static void DumpHex(const void* data, size_t len);
-  static void DumpXml(xml::XmlResource* doc);
-  static std::string ToString(xml::XmlResource* doc);
+  static void DumpXml(const xml::XmlResource& doc);
 };
 
 }  // namespace aapt
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index c1815c8..ae32ee9 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -21,7 +21,7 @@
 #include "format/Archive.h"
 #include "format/binary/TableFlattener.h"
 #include "format/binary/XmlFlattener.h"
-#include "io/BigBufferInputStream.h"
+#include "io/BigBufferStream.h"
 #include "io/Util.h"
 #include "xml/XmlDom.h"
 
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index cbcc8fb8..87b9867 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -157,12 +157,22 @@
 };
 
 struct ResourceFile {
+  enum class Type {
+    kUnknown,
+    kPng,
+    kBinaryXml,
+    kProtoXml,
+  };
+
   // Name
   ResourceName name;
 
   // Configuration
   ConfigDescription config;
 
+  // Type
+  Type type;
+
   // Source
   Source source;
 
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index f08b03e..9a5cd3e 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -22,7 +22,7 @@
 #include "ResourceTable.h"
 #include "ResourceUtils.h"
 #include "ResourceValues.h"
-#include "io/StringInputStream.h"
+#include "io/StringStream.h"
 #include "test/Test.h"
 #include "xml/XmlPullParser.h"
 
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 6fac6e9..24187d9 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -704,8 +704,15 @@
       } else {
         if (type != ResourceType::kString && util::StartsWith(str, "res/")) {
           // This must be a FileReference.
-          return util::make_unique<FileReference>(dst_pool->MakeRef(
-              str, StringPool::Context(StringPool::Context::kHighPriority, config)));
+          std::unique_ptr<FileReference> file_ref =
+              util::make_unique<FileReference>(dst_pool->MakeRef(
+                  str, StringPool::Context(StringPool::Context::kHighPriority, config)));
+          if (util::EndsWith(*file_ref->path, ".xml")) {
+            file_ref->type = ResourceFile::Type::kBinaryXml;
+          } else if (util::EndsWith(*file_ref->path, ".png")) {
+            file_ref->type = ResourceFile::Type::kPng;
+          }
+          return std::move(file_ref);
         }
 
         // There are no styles associated with this string, so treat it as a simple string.
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index e013729..082fd86 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -65,7 +65,7 @@
 }
 
 RawString* RawString::Clone(StringPool* new_pool) const {
-  RawString* rs = new RawString(new_pool->MakeRef(*value));
+  RawString* rs = new RawString(new_pool->MakeRef(value));
   rs->comment_ = comment_;
   rs->source_ = source_;
   return rs;
@@ -207,7 +207,7 @@
 }
 
 String* String::Clone(StringPool* new_pool) const {
-  String* str = new String(new_pool->MakeRef(*value));
+  String* str = new String(new_pool->MakeRef(value));
   str->comment_ = comment_;
   str->source_ = source_;
   str->untranslatable_sections = untranslatable_sections;
@@ -290,8 +290,9 @@
 }
 
 FileReference* FileReference::Clone(StringPool* new_pool) const {
-  FileReference* fr = new FileReference(new_pool->MakeRef(*path));
+  FileReference* fr = new FileReference(new_pool->MakeRef(path));
   fr->file = file;
+  fr->type = type;
   fr->comment_ = comment_;
   fr->source_ = source_;
   return fr;
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index 742765d..fd242a1 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -249,6 +249,10 @@
   // This field is NOT persisted in any format. It is transient.
   io::IFile* file = nullptr;
 
+  // FileType of the file pointed to by `file`. This is used to know how to inflate the file,
+  // or if to inflate at all (just copy).
+  ResourceFile::Type type = ResourceFile::Type::kUnknown;
+
   FileReference() = default;
   explicit FileReference(const StringPool::Ref& path);
 
diff --git a/tools/aapt2/ResourceValues_test.cpp b/tools/aapt2/ResourceValues_test.cpp
index 10f9b55..a80a9dc 100644
--- a/tools/aapt2/ResourceValues_test.cpp
+++ b/tools/aapt2/ResourceValues_test.cpp
@@ -18,6 +18,10 @@
 
 #include "test/Test.h"
 
+using ::testing::Eq;
+using ::testing::SizeIs;
+using ::testing::StrEq;
+
 namespace aapt {
 
 TEST(ResourceValuesTest, PluralEquals) {
@@ -148,6 +152,22 @@
   EXPECT_TRUE(a->Equals(b.get()));
 }
 
+TEST(ResourcesValuesTest, StringClones) {
+  StringPool pool_a;
+  StringPool pool_b;
+
+  String str_a(pool_a.MakeRef("hello", StringPool::Context(test::ParseConfigOrDie("en"))));
+
+  ASSERT_THAT(pool_a, SizeIs(1u));
+  EXPECT_THAT(pool_a.strings()[0]->context.config, Eq(test::ParseConfigOrDie("en")));
+  EXPECT_THAT(pool_a.strings()[0]->value, StrEq("hello"));
+
+  std::unique_ptr<String> str_b(str_a.Clone(&pool_b));
+  ASSERT_THAT(pool_b, SizeIs(1u));
+  EXPECT_THAT(pool_b.strings()[0]->context.config, Eq(test::ParseConfigOrDie("en")));
+  EXPECT_THAT(pool_b.strings()[0]->value, StrEq("hello"));
+}
+
 TEST(ResourceValuesTest, StyleMerges) {
   StringPool pool_a;
   StringPool pool_b;
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index 174b7f6..7e7c86d 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -269,8 +269,19 @@
 
 // A value that is a reference to an external entity, like an XML file or a PNG.
 message FileReference {
+  enum Type {
+    UNKNOWN = 0;
+    PNG = 1;
+    BINARY_XML = 2;
+    PROTO_XML = 3;
+  }
+
   // Path to a file within the APK (typically res/type-config/entry.ext).
   string path = 1;
+
+  // The type of file this path points to. For UAM bundle, this cannot be
+  // BINARY_XML.
+  Type type = 2;
 }
 
 // A value that represents a primitive data type (float, int, boolean, etc.).
diff --git a/tools/aapt2/ResourcesInternal.proto b/tools/aapt2/ResourcesInternal.proto
index 0b0a252..520b242 100644
--- a/tools/aapt2/ResourcesInternal.proto
+++ b/tools/aapt2/ResourcesInternal.proto
@@ -41,13 +41,13 @@
   // The configuration for which the resource is defined.
   aapt.pb.Configuration config = 2;
 
+  // The type of the file.
+  aapt.pb.FileReference.Type type = 3;
+
   // The filesystem path to where the source file originated.
   // Mainly used to display helpful error messages.
-  string source_path = 3;
+  string source_path = 4;
 
   // Any symbols this file auto-generates/exports (eg. @+id/foo in an XML file).
-  repeated Symbol exported_symbol = 4;
-
-  // If this is a compiled XML file, this is the root node.
-  aapt.pb.XmlNode xml_root = 5;
+  repeated Symbol exported_symbol = 5;
 }
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
index 041cb4f..8ebde75 100644
--- a/tools/aapt2/SdkConstants.cpp
+++ b/tools/aapt2/SdkConstants.cpp
@@ -25,8 +25,8 @@
 
 namespace aapt {
 
-static const char* sDevelopmentSdkCodeName = "O";
-static ApiVersion sDevelopmentSdkLevel = 26;
+static const char* sDevelopmentSdkCodeName = "P";
+static ApiVersion sDevelopmentSdkLevel = 28;
 
 static const std::vector<std::pair<uint16_t, ApiVersion>> sAttrIdMap = {
     {0x021c, 1},
@@ -53,6 +53,7 @@
     {0x0527, SDK_NOUGAT},
     {0x0530, SDK_NOUGAT_MR1},
     {0x0568, SDK_O},
+    {0x056d, SDK_O_MR1},
 };
 
 static bool less_entry_id(const std::pair<uint16_t, ApiVersion>& p, uint16_t entryId) {
@@ -70,680 +71,6 @@
   return iter->second;
 }
 
-static const std::unordered_map<std::string, ApiVersion> sAttrMap = {
-    {"marqueeRepeatLimit", 2},
-    {"windowNoDisplay", 3},
-    {"backgroundDimEnabled", 3},
-    {"inputType", 3},
-    {"isDefault", 3},
-    {"windowDisablePreview", 3},
-    {"privateImeOptions", 3},
-    {"editorExtras", 3},
-    {"settingsActivity", 3},
-    {"fastScrollEnabled", 3},
-    {"reqTouchScreen", 3},
-    {"reqKeyboardType", 3},
-    {"reqHardKeyboard", 3},
-    {"reqNavigation", 3},
-    {"windowSoftInputMode", 3},
-    {"imeFullscreenBackground", 3},
-    {"noHistory", 3},
-    {"headerDividersEnabled", 3},
-    {"footerDividersEnabled", 3},
-    {"candidatesTextStyleSpans", 3},
-    {"smoothScrollbar", 3},
-    {"reqFiveWayNav", 3},
-    {"keyBackground", 3},
-    {"keyTextSize", 3},
-    {"labelTextSize", 3},
-    {"keyTextColor", 3},
-    {"keyPreviewLayout", 3},
-    {"keyPreviewOffset", 3},
-    {"keyPreviewHeight", 3},
-    {"verticalCorrection", 3},
-    {"popupLayout", 3},
-    {"state_long_pressable", 3},
-    {"keyWidth", 3},
-    {"keyHeight", 3},
-    {"horizontalGap", 3},
-    {"verticalGap", 3},
-    {"rowEdgeFlags", 3},
-    {"codes", 3},
-    {"popupKeyboard", 3},
-    {"popupCharacters", 3},
-    {"keyEdgeFlags", 3},
-    {"isModifier", 3},
-    {"isSticky", 3},
-    {"isRepeatable", 3},
-    {"iconPreview", 3},
-    {"keyOutputText", 3},
-    {"keyLabel", 3},
-    {"keyIcon", 3},
-    {"keyboardMode", 3},
-    {"isScrollContainer", 3},
-    {"fillEnabled", 3},
-    {"updatePeriodMillis", 3},
-    {"initialLayout", 3},
-    {"voiceSearchMode", 3},
-    {"voiceLanguageModel", 3},
-    {"voicePromptText", 3},
-    {"voiceLanguage", 3},
-    {"voiceMaxResults", 3},
-    {"bottomOffset", 3},
-    {"topOffset", 3},
-    {"allowSingleTap", 3},
-    {"handle", 3},
-    {"content", 3},
-    {"animateOnClick", 3},
-    {"configure", 3},
-    {"hapticFeedbackEnabled", 3},
-    {"innerRadius", 3},
-    {"thickness", 3},
-    {"sharedUserLabel", 3},
-    {"dropDownWidth", 3},
-    {"dropDownAnchor", 3},
-    {"imeOptions", 3},
-    {"imeActionLabel", 3},
-    {"imeActionId", 3},
-    {"imeExtractEnterAnimation", 3},
-    {"imeExtractExitAnimation", 3},
-    {"tension", 4},
-    {"extraTension", 4},
-    {"anyDensity", 4},
-    {"searchSuggestThreshold", 4},
-    {"includeInGlobalSearch", 4},
-    {"onClick", 4},
-    {"targetSdkVersion", 4},
-    {"maxSdkVersion", 4},
-    {"testOnly", 4},
-    {"contentDescription", 4},
-    {"gestureStrokeWidth", 4},
-    {"gestureColor", 4},
-    {"uncertainGestureColor", 4},
-    {"fadeOffset", 4},
-    {"fadeDuration", 4},
-    {"gestureStrokeType", 4},
-    {"gestureStrokeLengthThreshold", 4},
-    {"gestureStrokeSquarenessThreshold", 4},
-    {"gestureStrokeAngleThreshold", 4},
-    {"eventsInterceptionEnabled", 4},
-    {"fadeEnabled", 4},
-    {"backupAgent", 4},
-    {"allowBackup", 4},
-    {"glEsVersion", 4},
-    {"queryAfterZeroResults", 4},
-    {"dropDownHeight", 4},
-    {"smallScreens", 4},
-    {"normalScreens", 4},
-    {"largeScreens", 4},
-    {"progressBarStyleInverse", 4},
-    {"progressBarStyleSmallInverse", 4},
-    {"progressBarStyleLargeInverse", 4},
-    {"searchSettingsDescription", 4},
-    {"textColorPrimaryInverseDisableOnly", 4},
-    {"autoUrlDetect", 4},
-    {"resizeable", 4},
-    {"required", 5},
-    {"accountType", 5},
-    {"contentAuthority", 5},
-    {"userVisible", 5},
-    {"windowShowWallpaper", 5},
-    {"wallpaperOpenEnterAnimation", 5},
-    {"wallpaperOpenExitAnimation", 5},
-    {"wallpaperCloseEnterAnimation", 5},
-    {"wallpaperCloseExitAnimation", 5},
-    {"wallpaperIntraOpenEnterAnimation", 5},
-    {"wallpaperIntraOpenExitAnimation", 5},
-    {"wallpaperIntraCloseEnterAnimation", 5},
-    {"wallpaperIntraCloseExitAnimation", 5},
-    {"supportsUploading", 5},
-    {"killAfterRestore", 5},
-    {"restoreNeedsApplication", 5},
-    {"smallIcon", 5},
-    {"accountPreferences", 5},
-    {"textAppearanceSearchResultSubtitle", 5},
-    {"textAppearanceSearchResultTitle", 5},
-    {"summaryColumn", 5},
-    {"detailColumn", 5},
-    {"detailSocialSummary", 5},
-    {"thumbnail", 5},
-    {"detachWallpaper", 5},
-    {"finishOnCloseSystemDialogs", 5},
-    {"scrollbarFadeDuration", 5},
-    {"scrollbarDefaultDelayBeforeFade", 5},
-    {"fadeScrollbars", 5},
-    {"colorBackgroundCacheHint", 5},
-    {"dropDownHorizontalOffset", 5},
-    {"dropDownVerticalOffset", 5},
-    {"quickContactBadgeStyleWindowSmall", 6},
-    {"quickContactBadgeStyleWindowMedium", 6},
-    {"quickContactBadgeStyleWindowLarge", 6},
-    {"quickContactBadgeStyleSmallWindowSmall", 6},
-    {"quickContactBadgeStyleSmallWindowMedium", 6},
-    {"quickContactBadgeStyleSmallWindowLarge", 6},
-    {"author", 7},
-    {"autoStart", 7},
-    {"expandableListViewWhiteStyle", 8},
-    {"installLocation", 8},
-    {"vmSafeMode", 8},
-    {"webTextViewStyle", 8},
-    {"restoreAnyVersion", 8},
-    {"tabStripLeft", 8},
-    {"tabStripRight", 8},
-    {"tabStripEnabled", 8},
-    {"logo", 9},
-    {"xlargeScreens", 9},
-    {"immersive", 9},
-    {"overScrollMode", 9},
-    {"overScrollHeader", 9},
-    {"overScrollFooter", 9},
-    {"filterTouchesWhenObscured", 9},
-    {"textSelectHandleLeft", 9},
-    {"textSelectHandleRight", 9},
-    {"textSelectHandle", 9},
-    {"textSelectHandleWindowStyle", 9},
-    {"popupAnimationStyle", 9},
-    {"screenSize", 9},
-    {"screenDensity", 9},
-    {"allContactsName", 11},
-    {"windowActionBar", 11},
-    {"actionBarStyle", 11},
-    {"navigationMode", 11},
-    {"displayOptions", 11},
-    {"subtitle", 11},
-    {"customNavigationLayout", 11},
-    {"hardwareAccelerated", 11},
-    {"measureWithLargestChild", 11},
-    {"animateFirstView", 11},
-    {"dropDownSpinnerStyle", 11},
-    {"actionDropDownStyle", 11},
-    {"actionButtonStyle", 11},
-    {"showAsAction", 11},
-    {"previewImage", 11},
-    {"actionModeBackground", 11},
-    {"actionModeCloseDrawable", 11},
-    {"windowActionModeOverlay", 11},
-    {"valueFrom", 11},
-    {"valueTo", 11},
-    {"valueType", 11},
-    {"propertyName", 11},
-    {"ordering", 11},
-    {"fragment", 11},
-    {"windowActionBarOverlay", 11},
-    {"fragmentOpenEnterAnimation", 11},
-    {"fragmentOpenExitAnimation", 11},
-    {"fragmentCloseEnterAnimation", 11},
-    {"fragmentCloseExitAnimation", 11},
-    {"fragmentFadeEnterAnimation", 11},
-    {"fragmentFadeExitAnimation", 11},
-    {"actionBarSize", 11},
-    {"imeSubtypeLocale", 11},
-    {"imeSubtypeMode", 11},
-    {"imeSubtypeExtraValue", 11},
-    {"splitMotionEvents", 11},
-    {"listChoiceBackgroundIndicator", 11},
-    {"spinnerMode", 11},
-    {"animateLayoutChanges", 11},
-    {"actionBarTabStyle", 11},
-    {"actionBarTabBarStyle", 11},
-    {"actionBarTabTextStyle", 11},
-    {"actionOverflowButtonStyle", 11},
-    {"actionModeCloseButtonStyle", 11},
-    {"titleTextStyle", 11},
-    {"subtitleTextStyle", 11},
-    {"iconifiedByDefault", 11},
-    {"actionLayout", 11},
-    {"actionViewClass", 11},
-    {"activatedBackgroundIndicator", 11},
-    {"state_activated", 11},
-    {"listPopupWindowStyle", 11},
-    {"popupMenuStyle", 11},
-    {"textAppearanceLargePopupMen", 11},
-    {"textAppearanceSmallPopupMen", 11},
-    {"breadCrumbTitle", 11},
-    {"breadCrumbShortTitle", 11},
-    {"listDividerAlertDialog", 11},
-    {"textColorAlertDialogListItem", 11},
-    {"loopViews", 11},
-    {"dialogTheme", 11},
-    {"alertDialogTheme", 11},
-    {"dividerVertical", 11},
-    {"homeAsUpIndicator", 11},
-    {"enterFadeDuration", 11},
-    {"exitFadeDuration", 11},
-    {"selectableItemBackground", 11},
-    {"autoAdvanceViewId", 11},
-    {"useIntrinsicSizeAsMinimum", 11},
-    {"actionModeCutDrawable", 11},
-    {"actionModeCopyDrawable", 11},
-    {"actionModePasteDrawable", 11},
-    {"textEditPasteWindowLayout", 11},
-    {"textEditNoPasteWindowLayout", 11},
-    {"textIsSelectable", 11},
-    {"windowEnableSplitTouch", 11},
-    {"indeterminateProgressStyle", 11},
-    {"progressBarPadding", 11},
-    {"animationResolution", 11},
-    {"state_accelerated", 11},
-    {"baseline", 11},
-    {"homeLayout", 11},
-    {"opacity", 11},
-    {"alpha", 11},
-    {"transformPivotX", 11},
-    {"transformPivotY", 11},
-    {"translationX", 11},
-    {"translationY", 11},
-    {"scaleX", 11},
-    {"scaleY", 11},
-    {"rotation", 11},
-    {"rotationX", 11},
-    {"rotationY", 11},
-    {"showDividers", 11},
-    {"dividerPadding", 11},
-    {"borderlessButtonStyle", 11},
-    {"dividerHorizontal", 11},
-    {"itemPadding", 11},
-    {"buttonBarStyle", 11},
-    {"buttonBarButtonStyle", 11},
-    {"segmentedButtonStyle", 11},
-    {"staticWallpaperPreview", 11},
-    {"allowParallelSyncs", 11},
-    {"isAlwaysSyncable", 11},
-    {"verticalScrollbarPosition", 11},
-    {"fastScrollAlwaysVisible", 11},
-    {"fastScrollThumbDrawable", 11},
-    {"fastScrollPreviewBackgroundLeft", 11},
-    {"fastScrollPreviewBackgroundRight", 11},
-    {"fastScrollTrackDrawable", 11},
-    {"fastScrollOverlayPosition", 11},
-    {"customTokens", 11},
-    {"nextFocusForward", 11},
-    {"firstDayOfWeek", 11},
-    {"showWeekNumber", 11},
-    {"minDate", 11},
-    {"maxDate", 11},
-    {"shownWeekCount", 11},
-    {"selectedWeekBackgroundColor", 11},
-    {"focusedMonthDateColor", 11},
-    {"unfocusedMonthDateColor", 11},
-    {"weekNumberColor", 11},
-    {"weekSeparatorLineColor", 11},
-    {"selectedDateVerticalBar", 11},
-    {"weekDayTextAppearance", 11},
-    {"dateTextAppearance", 11},
-    {"solidColor", 11},
-    {"spinnersShown", 11},
-    {"calendarViewShown", 11},
-    {"state_multiline", 11},
-    {"detailsElementBackground", 11},
-    {"textColorHighlightInverse", 11},
-    {"textColorLinkInverse", 11},
-    {"editTextColor", 11},
-    {"editTextBackground", 11},
-    {"horizontalScrollViewStyle", 11},
-    {"layerType", 11},
-    {"alertDialogIcon", 11},
-    {"windowMinWidthMajor", 11},
-    {"windowMinWidthMinor", 11},
-    {"queryHint", 11},
-    {"fastScrollTextColor", 11},
-    {"largeHeap", 11},
-    {"windowCloseOnTouchOutside", 11},
-    {"datePickerStyle", 11},
-    {"calendarViewStyle", 11},
-    {"textEditSidePasteWindowLayout", 11},
-    {"textEditSideNoPasteWindowLayout", 11},
-    {"actionMenuTextAppearance", 11},
-    {"actionMenuTextColor", 11},
-    {"textCursorDrawable", 12},
-    {"resizeMode", 12},
-    {"requiresSmallestWidthDp", 12},
-    {"compatibleWidthLimitDp", 12},
-    {"largestWidthLimitDp", 12},
-    {"state_hovered", 13},
-    {"state_drag_can_accept", 13},
-    {"state_drag_hovered", 13},
-    {"stopWithTask", 13},
-    {"switchTextOn", 13},
-    {"switchTextOff", 13},
-    {"switchPreferenceStyle", 13},
-    {"switchTextAppearance", 13},
-    {"track", 13},
-    {"switchMinWidth", 13},
-    {"switchPadding", 13},
-    {"thumbTextPadding", 13},
-    {"textSuggestionsWindowStyle", 13},
-    {"textEditSuggestionItemLayout", 13},
-    {"rowCount", 13},
-    {"rowOrderPreserved", 13},
-    {"columnCount", 13},
-    {"columnOrderPreserved", 13},
-    {"useDefaultMargins", 13},
-    {"alignmentMode", 13},
-    {"layout_row", 13},
-    {"layout_rowSpan", 13},
-    {"layout_columnSpan", 13},
-    {"actionModeSelectAllDrawable", 13},
-    {"isAuxiliary", 13},
-    {"accessibilityEventTypes", 13},
-    {"packageNames", 13},
-    {"accessibilityFeedbackType", 13},
-    {"notificationTimeout", 13},
-    {"accessibilityFlags", 13},
-    {"canRetrieveWindowContent", 13},
-    {"listPreferredItemHeightLarge", 13},
-    {"listPreferredItemHeightSmall", 13},
-    {"actionBarSplitStyle", 13},
-    {"actionProviderClass", 13},
-    {"backgroundStacked", 13},
-    {"backgroundSplit", 13},
-    {"textAllCaps", 13},
-    {"colorPressedHighlight", 13},
-    {"colorLongPressedHighlight", 13},
-    {"colorFocusedHighlight", 13},
-    {"colorActivatedHighlight", 13},
-    {"colorMultiSelectHighlight", 13},
-    {"drawableStart", 13},
-    {"drawableEnd", 13},
-    {"actionModeStyle", 13},
-    {"minResizeWidth", 13},
-    {"minResizeHeight", 13},
-    {"actionBarWidgetTheme", 13},
-    {"uiOptions", 13},
-    {"subtypeLocale", 13},
-    {"subtypeExtraValue", 13},
-    {"actionBarDivider", 13},
-    {"actionBarItemBackground", 13},
-    {"actionModeSplitBackground", 13},
-    {"textAppearanceListItem", 13},
-    {"textAppearanceListItemSmall", 13},
-    {"targetDescriptions", 13},
-    {"directionDescriptions", 13},
-    {"overridesImplicitlyEnabledSubtype", 13},
-    {"listPreferredItemPaddingLeft", 13},
-    {"listPreferredItemPaddingRight", 13},
-    {"requiresFadingEdge", 13},
-    {"publicKey", 13},
-    {"parentActivityName", 16},
-    {"isolatedProcess", 16},
-    {"importantForAccessibility", 16},
-    {"keyboardLayout", 16},
-    {"fontFamily", 16},
-    {"mediaRouteButtonStyle", 16},
-    {"mediaRouteTypes", 16},
-    {"supportsRtl", 17},
-    {"textDirection", 17},
-    {"textAlignment", 17},
-    {"layoutDirection", 17},
-    {"paddingStart", 17},
-    {"paddingEnd", 17},
-    {"layout_marginStart", 17},
-    {"layout_marginEnd", 17},
-    {"layout_toStartOf", 17},
-    {"layout_toEndOf", 17},
-    {"layout_alignStart", 17},
-    {"layout_alignEnd", 17},
-    {"layout_alignParentStart", 17},
-    {"layout_alignParentEnd", 17},
-    {"listPreferredItemPaddingStart", 17},
-    {"listPreferredItemPaddingEnd", 17},
-    {"singleUser", 17},
-    {"presentationTheme", 17},
-    {"subtypeId", 17},
-    {"initialKeyguardLayout", 17},
-    {"widgetCategory", 17},
-    {"permissionGroupFlags", 17},
-    {"labelFor", 17},
-    {"permissionFlags", 17},
-    {"checkedTextViewStyle", 17},
-    {"showOnLockScreen", 17},
-    {"format12Hour", 17},
-    {"format24Hour", 17},
-    {"timeZone", 17},
-    {"mipMap", 18},
-    {"mirrorForRtl", 18},
-    {"windowOverscan", 18},
-    {"requiredForAllUsers", 18},
-    {"indicatorStart", 18},
-    {"indicatorEnd", 18},
-    {"childIndicatorStart", 18},
-    {"childIndicatorEnd", 18},
-    {"restrictedAccountType", 18},
-    {"requiredAccountType", 18},
-    {"canRequestTouchExplorationMode", 18},
-    {"canRequestEnhancedWebAccessibility", 18},
-    {"canRequestFilterKeyEvents", 18},
-    {"layoutMode", 18},
-    {"keySet", 19},
-    {"targetId", 19},
-    {"fromScene", 19},
-    {"toScene", 19},
-    {"transition", 19},
-    {"transitionOrdering", 19},
-    {"fadingMode", 19},
-    {"startDelay", 19},
-    {"ssp", 19},
-    {"sspPrefix", 19},
-    {"sspPattern", 19},
-    {"addPrintersActivity", 19},
-    {"vendor", 19},
-    {"category", 19},
-    {"isAsciiCapable", 19},
-    {"autoMirrored", 19},
-    {"supportsSwitchingToNextInputMethod", 19},
-    {"requireDeviceUnlock", 19},
-    {"apduServiceBanner", 19},
-    {"accessibilityLiveRegion", 19},
-    {"windowTranslucentStatus", 19},
-    {"windowTranslucentNavigation", 19},
-    {"advancedPrintOptionsActivity", 19},
-    {"banner", 20},
-    {"windowSwipeToDismiss", 20},
-    {"isGame", 20},
-    {"allowEmbedded", 20},
-    {"setupActivity", 20},
-    {"fastScrollStyle", 21},
-    {"windowContentTransitions", 21},
-    {"windowContentTransitionManager", 21},
-    {"translationZ", 21},
-    {"tintMode", 21},
-    {"controlX1", 21},
-    {"controlY1", 21},
-    {"controlX2", 21},
-    {"controlY2", 21},
-    {"transitionName", 21},
-    {"transitionGroup", 21},
-    {"viewportWidth", 21},
-    {"viewportHeight", 21},
-    {"fillColor", 21},
-    {"pathData", 21},
-    {"strokeColor", 21},
-    {"strokeWidth", 21},
-    {"trimPathStart", 21},
-    {"trimPathEnd", 21},
-    {"trimPathOffset", 21},
-    {"strokeLineCap", 21},
-    {"strokeLineJoin", 21},
-    {"strokeMiterLimit", 21},
-    {"colorControlNormal", 21},
-    {"colorControlActivated", 21},
-    {"colorButtonNormal", 21},
-    {"colorControlHighlight", 21},
-    {"persistableMode", 21},
-    {"titleTextAppearance", 21},
-    {"subtitleTextAppearance", 21},
-    {"slideEdge", 21},
-    {"actionBarTheme", 21},
-    {"textAppearanceListItemSecondary", 21},
-    {"colorPrimary", 21},
-    {"colorPrimaryDark", 21},
-    {"colorAccent", 21},
-    {"nestedScrollingEnabled", 21},
-    {"windowEnterTransition", 21},
-    {"windowExitTransition", 21},
-    {"windowSharedElementEnterTransition", 21},
-    {"windowSharedElementExitTransition", 21},
-    {"windowAllowReturnTransitionOverlap", 21},
-    {"windowAllowEnterTransitionOverlap", 21},
-    {"sessionService", 21},
-    {"stackViewStyle", 21},
-    {"switchStyle", 21},
-    {"elevation", 21},
-    {"excludeId", 21},
-    {"excludeClass", 21},
-    {"hideOnContentScroll", 21},
-    {"actionOverflowMenuStyle", 21},
-    {"documentLaunchMode", 21},
-    {"maxRecents", 21},
-    {"autoRemoveFromRecents", 21},
-    {"stateListAnimator", 21},
-    {"toId", 21},
-    {"fromId", 21},
-    {"reversible", 21},
-    {"splitTrack", 21},
-    {"targetName", 21},
-    {"excludeName", 21},
-    {"matchOrder", 21},
-    {"windowDrawsSystemBarBackgrounds", 21},
-    {"statusBarColor", 21},
-    {"navigationBarColor", 21},
-    {"contentInsetStart", 21},
-    {"contentInsetEnd", 21},
-    {"contentInsetLeft", 21},
-    {"contentInsetRight", 21},
-    {"paddingMode", 21},
-    {"layout_rowWeight", 21},
-    {"layout_columnWeight", 21},
-    {"translateX", 21},
-    {"translateY", 21},
-    {"selectableItemBackgroundBorderless", 21},
-    {"elegantTextHeight", 21},
-    {"searchKeyphraseId", 21},
-    {"searchKeyphrase", 21},
-    {"searchKeyphraseSupportedLocales", 21},
-    {"windowTransitionBackgroundFadeDuration", 21},
-    {"overlapAnchor", 21},
-    {"progressTint", 21},
-    {"progressTintMode", 21},
-    {"progressBackgroundTint", 21},
-    {"progressBackgroundTintMode", 21},
-    {"secondaryProgressTint", 21},
-    {"secondaryProgressTintMode", 21},
-    {"indeterminateTint", 21},
-    {"indeterminateTintMode", 21},
-    {"backgroundTint", 21},
-    {"backgroundTintMode", 21},
-    {"foregroundTint", 21},
-    {"foregroundTintMode", 21},
-    {"buttonTint", 21},
-    {"buttonTintMode", 21},
-    {"thumbTint", 21},
-    {"thumbTintMode", 21},
-    {"fullBackupOnly", 21},
-    {"propertyXName", 21},
-    {"propertyYName", 21},
-    {"relinquishTaskIdentity", 21},
-    {"tileModeX", 21},
-    {"tileModeY", 21},
-    {"actionModeShareDrawable", 21},
-    {"actionModeFindDrawable", 21},
-    {"actionModeWebSearchDrawable", 21},
-    {"transitionVisibilityMode", 21},
-    {"minimumHorizontalAngle", 21},
-    {"minimumVerticalAngle", 21},
-    {"maximumAngle", 21},
-    {"searchViewStyle", 21},
-    {"closeIcon", 21},
-    {"goIcon", 21},
-    {"searchIcon", 21},
-    {"voiceIcon", 21},
-    {"commitIcon", 21},
-    {"suggestionRowLayout", 21},
-    {"queryBackground", 21},
-    {"submitBackground", 21},
-    {"buttonBarPositiveButtonStyle", 21},
-    {"buttonBarNeutralButtonStyle", 21},
-    {"buttonBarNegativeButtonStyle", 21},
-    {"popupElevation", 21},
-    {"actionBarPopupTheme", 21},
-    {"multiArch", 21},
-    {"touchscreenBlocksFocus", 21},
-    {"windowElevation", 21},
-    {"launchTaskBehindTargetAnimation", 21},
-    {"launchTaskBehindSourceAnimation", 21},
-    {"restrictionType", 21},
-    {"dayOfWeekBackground", 21},
-    {"dayOfWeekTextAppearance", 21},
-    {"headerMonthTextAppearance", 21},
-    {"headerDayOfMonthTextAppearance", 21},
-    {"headerYearTextAppearance", 21},
-    {"yearListItemTextAppearance", 21},
-    {"yearListSelectorColor", 21},
-    {"calendarTextColor", 21},
-    {"recognitionService", 21},
-    {"timePickerStyle", 21},
-    {"timePickerDialogTheme", 21},
-    {"headerTimeTextAppearance", 21},
-    {"headerAmPmTextAppearance", 21},
-    {"numbersTextColor", 21},
-    {"numbersBackgroundColor", 21},
-    {"numbersSelectorColor", 21},
-    {"amPmTextColor", 21},
-    {"amPmBackgroundColor", 21},
-    {"searchKeyphraseRecognitionFlags", 21},
-    {"checkMarkTint", 21},
-    {"checkMarkTintMode", 21},
-    {"popupTheme", 21},
-    {"toolbarStyle", 21},
-    {"windowClipToOutline", 21},
-    {"datePickerDialogTheme", 21},
-    {"showText", 21},
-    {"windowReturnTransition", 21},
-    {"windowReenterTransition", 21},
-    {"windowSharedElementReturnTransition", 21},
-    {"windowSharedElementReenterTransition", 21},
-    {"resumeWhilePausing", 21},
-    {"datePickerMode", 21},
-    {"timePickerMode", 21},
-    {"inset", 21},
-    {"letterSpacing", 21},
-    {"fontFeatureSettings", 21},
-    {"outlineProvider", 21},
-    {"contentAgeHint", 21},
-    {"country", 21},
-    {"windowSharedElementsUseOverlay", 21},
-    {"reparent", 21},
-    {"reparentWithOverlay", 21},
-    {"ambientShadowAlpha", 21},
-    {"spotShadowAlpha", 21},
-    {"navigationIcon", 21},
-    {"navigationContentDescription", 21},
-    {"fragmentExitTransition", 21},
-    {"fragmentEnterTransition", 21},
-    {"fragmentSharedElementEnterTransition", 21},
-    {"fragmentReturnTransition", 21},
-    {"fragmentSharedElementReturnTransition", 21},
-    {"fragmentReenterTransition", 21},
-    {"fragmentAllowEnterTransitionOverlap", 21},
-    {"fragmentAllowReturnTransitionOverlap", 21},
-    {"patternPathData", 21},
-    {"strokeAlpha", 21},
-    {"fillAlpha", 21},
-    {"windowActivityTransitions", 21},
-    {"colorEdgeEffect", 21}};
-
-ApiVersion FindAttributeSdkLevel(const ResourceName& name) {
-  if (name.package != "android" && name.type != ResourceType::kAttr) {
-    return 0;
-  }
-
-  auto iter = sAttrMap.find(name.entry);
-  if (iter != sAttrMap.end()) {
-    return iter->second;
-  }
-  return SDK_LOLLIPOP_MR1;
-}
-
 std::pair<StringPiece, ApiVersion> GetDevelopmentSdkCodeNameAndVersion() {
   return std::make_pair(StringPiece(sDevelopmentSdkCodeName), sDevelopmentSdkLevel);
 }
diff --git a/tools/aapt2/SdkConstants.h b/tools/aapt2/SdkConstants.h
index 13584c0..5b7be3b 100644
--- a/tools/aapt2/SdkConstants.h
+++ b/tools/aapt2/SdkConstants.h
@@ -57,7 +57,6 @@
 };
 
 ApiVersion FindAttributeSdkLevel(const ResourceId& id);
-ApiVersion FindAttributeSdkLevel(const ResourceName& name);
 std::pair<android::StringPiece, ApiVersion> GetDevelopmentSdkCodeNameAndVersion();
 
 }  // namespace aapt
diff --git a/tools/aapt2/StringPool.cpp b/tools/aapt2/StringPool.cpp
index 705b1ab..3a1a18c 100644
--- a/tools/aapt2/StringPool.cpp
+++ b/tools/aapt2/StringPool.cpp
@@ -191,6 +191,13 @@
   return Ref(borrow);
 }
 
+StringPool::Ref StringPool::MakeRef(const Ref& ref) {
+  if (ref.entry_->pool_ == this) {
+    return ref;
+  }
+  return MakeRef(ref.entry_->value, ref.entry_->context);
+}
+
 StringPool::StyleRef StringPool::MakeRef(const StyleString& str) {
   return MakeRef(str, Context{});
 }
diff --git a/tools/aapt2/StringPool.h b/tools/aapt2/StringPool.h
index 8350d0d..3c1f3dc 100644
--- a/tools/aapt2/StringPool.h
+++ b/tools/aapt2/StringPool.h
@@ -49,6 +49,8 @@
 // Otherwise, the style data array would have to be sparse and take up more space.
 class StringPool {
  public:
+  using size_type = size_t;
+
   class Context {
    public:
     enum : uint32_t {
@@ -165,6 +167,9 @@
   // when sorting the string pool. Returns a reference to the string in the pool.
   Ref MakeRef(const android::StringPiece& str, const Context& context);
 
+  // Adds a string from another string pool. Returns a reference to the string in the string pool.
+  Ref MakeRef(const Ref& ref);
+
   // Adds a style to the string pool and returns a reference to it.
   StyleRef MakeRef(const StyleString& str);
 
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index a5e6aefd1..53910af 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -36,10 +36,11 @@
 #include "compile/PseudolocaleGenerator.h"
 #include "compile/XmlIdCollector.h"
 #include "format/Archive.h"
-#include "format/binary/XmlFlattener.h"
+#include "format/Container.h"
 #include "format/proto/ProtoSerialize.h"
-#include "io/BigBufferOutputStream.h"
-#include "io/FileInputStream.h"
+#include "io/BigBufferStream.h"
+#include "io/FileStream.h"
+#include "io/StringStream.h"
 #include "io/Util.h"
 #include "util/Files.h"
 #include "util/Maybe.h"
@@ -49,6 +50,7 @@
 
 using ::aapt::io::FileInputStream;
 using ::android::StringPiece;
+using ::android::base::SystemErrorCodeToString;
 using ::google::protobuf::io::CopyingOutputStreamAdaptor;
 
 namespace aapt {
@@ -116,7 +118,7 @@
   bool verbose = false;
 };
 
-static std::string BuildIntermediateFilename(const ResourcePathData& data) {
+static std::string BuildIntermediateContainerFilename(const ResourcePathData& data) {
   std::stringstream name;
   name << data.resource_dir;
   if (!data.config_str.empty()) {
@@ -141,7 +143,7 @@
   std::unique_ptr<DIR, decltype(closedir)*> d(opendir(root_dir.data()), closedir);
   if (!d) {
     context->GetDiagnostics()->Error(DiagMessage(root_dir) << "failed to open directory: "
-                                     << android::base::SystemErrorCodeToString(errno));
+                                                           << SystemErrorCodeToString(errno));
     return false;
   }
 
@@ -160,7 +162,7 @@
     std::unique_ptr<DIR, decltype(closedir)*> subdir(opendir(prefix_path.data()), closedir);
     if (!subdir) {
       context->GetDiagnostics()->Error(DiagMessage(prefix_path) << "failed to open directory: "
-                                       << android::base::SystemErrorCodeToString(errno));
+                                                                << SystemErrorCodeToString(errno));
       return false;
     }
 
@@ -241,16 +243,15 @@
     return false;
   }
 
-  // Make sure CopyingOutputStreamAdaptor is deleted before we call
-  // writer->FinishEntry().
+  // Make sure CopyingOutputStreamAdaptor is deleted before we call writer->FinishEntry().
   {
-    // Wrap our IArchiveWriter with an adaptor that implements the
-    // ZeroCopyOutputStream interface.
+    // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream interface.
     CopyingOutputStreamAdaptor copying_adaptor(writer);
+    ContainerWriter container_writer(&copying_adaptor, 1u);
 
     pb::ResourceTable pb_table;
     SerializeTableToPb(table, &pb_table);
-    if (!pb_table.SerializeToZeroCopyStream(&copying_adaptor)) {
+    if (!container_writer.AddResTableEntry(pb_table)) {
       context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to write");
       return false;
     }
@@ -263,46 +264,8 @@
   return true;
 }
 
-static bool WriteHeaderAndBufferToWriter(const StringPiece& output_path, const ResourceFile& file,
-                                         const BigBuffer& buffer, IArchiveWriter* writer,
-                                         IDiagnostics* diag) {
-  // Start the entry so we can write the header.
-  if (!writer->StartEntry(output_path, 0)) {
-    diag->Error(DiagMessage(output_path) << "failed to open file");
-    return false;
-  }
-
-  // Make sure CopyingOutputStreamAdaptor is deleted before we call
-  // writer->FinishEntry().
-  {
-    // Wrap our IArchiveWriter with an adaptor that implements the
-    // ZeroCopyOutputStream interface.
-    CopyingOutputStreamAdaptor copying_adaptor(writer);
-    CompiledFileOutputStream output_stream(&copying_adaptor);
-
-    // Number of CompiledFiles.
-    output_stream.WriteLittleEndian32(1);
-
-    pb::internal::CompiledFile pb_compiled_file;
-    SerializeCompiledFileToPb(file, &pb_compiled_file);
-    output_stream.WriteCompiledFile(pb_compiled_file);
-    output_stream.WriteData(buffer);
-
-    if (output_stream.HadError()) {
-      diag->Error(DiagMessage(output_path) << "failed to write data");
-      return false;
-    }
-  }
-
-  if (!writer->FinishEntry()) {
-    diag->Error(DiagMessage(output_path) << "failed to finish writing data");
-    return false;
-  }
-  return true;
-}
-
-static bool WriteHeaderAndMmapToWriter(const StringPiece& output_path, const ResourceFile& file,
-                                       const android::FileMap& map, IArchiveWriter* writer,
+static bool WriteHeaderAndDataToWriter(const StringPiece& output_path, const ResourceFile& file,
+                                       io::KnownSizeInputStream* in, IArchiveWriter* writer,
                                        IDiagnostics* diag) {
   // Start the entry so we can write the header.
   if (!writer->StartEntry(output_path, 0)) {
@@ -310,24 +273,17 @@
     return false;
   }
 
-  // Make sure CopyingOutputStreamAdaptor is deleted before we call
-  // writer->FinishEntry().
+  // Make sure CopyingOutputStreamAdaptor is deleted before we call writer->FinishEntry().
   {
-    // Wrap our IArchiveWriter with an adaptor that implements the
-    // ZeroCopyOutputStream interface.
+    // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream interface.
     CopyingOutputStreamAdaptor copying_adaptor(writer);
-    CompiledFileOutputStream output_stream(&copying_adaptor);
-
-    // Number of CompiledFiles.
-    output_stream.WriteLittleEndian32(1);
+    ContainerWriter container_writer(&copying_adaptor, 1u);
 
     pb::internal::CompiledFile pb_compiled_file;
     SerializeCompiledFileToPb(file, &pb_compiled_file);
-    output_stream.WriteCompiledFile(pb_compiled_file);
-    output_stream.WriteData(map.getDataPtr(), map.getDataLength());
 
-    if (output_stream.HadError()) {
-      diag->Error(DiagMessage(output_path) << "failed to write data");
+    if (!container_writer.AddResFileEntry(pb_compiled_file, in)) {
+      diag->Error(DiagMessage(output_path) << "failed to write entry data");
       return false;
     }
   }
@@ -339,23 +295,19 @@
   return true;
 }
 
-static bool FlattenXmlToOutStream(IAaptContext* context, const StringPiece& output_path,
-                                  xml::XmlResource* xmlres, CompiledFileOutputStream* out) {
-  BigBuffer buffer(1024);
-  XmlFlattenerOptions xml_flattener_options;
-  xml_flattener_options.keep_raw_values = true;
-  XmlFlattener flattener(&buffer, xml_flattener_options);
-  if (!flattener.Consume(context, xmlres)) {
-    return false;
-  }
-
+static bool FlattenXmlToOutStream(const StringPiece& output_path, const xml::XmlResource& xmlres,
+                                  ContainerWriter* container_writer, IDiagnostics* diag) {
   pb::internal::CompiledFile pb_compiled_file;
-  SerializeCompiledFileToPb(xmlres->file, &pb_compiled_file);
-  out->WriteCompiledFile(pb_compiled_file);
-  out->WriteData(buffer);
+  SerializeCompiledFileToPb(xmlres.file, &pb_compiled_file);
 
-  if (out->HadError()) {
-    context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to write XML data");
+  pb::XmlNode pb_xml_node;
+  SerializeXmlToPb(*xmlres.root, &pb_xml_node);
+
+  std::string serialized_xml = pb_xml_node.SerializeAsString();
+  io::StringInputStream serialized_in(serialized_xml);
+
+  if (!container_writer->AddResFileEntry(pb_compiled_file, &serialized_in)) {
+    diag->Error(DiagMessage(output_path) << "failed to write entry data");
     return false;
   }
   return true;
@@ -404,6 +356,7 @@
   xmlres->file.name = ResourceName({}, *ParseResourceType(path_data.resource_dir), path_data.name);
   xmlres->file.config = path_data.config;
   xmlres->file.source = path_data.source;
+  xmlres->file.type = ResourceFile::Type::kProtoXml;
 
   // Collect IDs that are defined here.
   XmlIdCollector collector;
@@ -423,24 +376,23 @@
     return false;
   }
 
+  std::vector<std::unique_ptr<xml::XmlResource>>& inline_documents =
+      inline_xml_format_parser.GetExtractedInlineXmlDocuments();
+
   // Make sure CopyingOutputStreamAdaptor is deleted before we call writer->FinishEntry().
   {
     // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream interface.
     CopyingOutputStreamAdaptor copying_adaptor(writer);
-    CompiledFileOutputStream output_stream(&copying_adaptor);
+    ContainerWriter container_writer(&copying_adaptor, 1u + inline_documents.size());
 
-    std::vector<std::unique_ptr<xml::XmlResource>>& inline_documents =
-        inline_xml_format_parser.GetExtractedInlineXmlDocuments();
-
-    // Number of CompiledFiles.
-    output_stream.WriteLittleEndian32(1 + inline_documents.size());
-
-    if (!FlattenXmlToOutStream(context, output_path, xmlres.get(), &output_stream)) {
+    if (!FlattenXmlToOutStream(output_path, *xmlres, &container_writer,
+                               context->GetDiagnostics())) {
       return false;
     }
 
-    for (auto& inline_xml_doc : inline_documents) {
-      if (!FlattenXmlToOutStream(context, output_path, inline_xml_doc.get(), &output_stream)) {
+    for (const std::unique_ptr<xml::XmlResource>& inline_xml_doc : inline_documents) {
+      if (!FlattenXmlToOutStream(output_path, *inline_xml_doc, &container_writer,
+                                 context->GetDiagnostics())) {
         return false;
       }
     }
@@ -465,6 +417,7 @@
   res_file.name = ResourceName({}, *ParseResourceType(path_data.resource_dir), path_data.name);
   res_file.config = path_data.config;
   res_file.source = path_data.source;
+  res_file.type = ResourceFile::Type::kPng;
 
   {
     std::string content;
@@ -472,7 +425,7 @@
                                          true /*follow_symlinks*/)) {
       context->GetDiagnostics()->Error(DiagMessage(path_data.source)
                                        << "failed to open file: "
-                                       << android::base::SystemErrorCodeToString(errno));
+                                       << SystemErrorCodeToString(errno));
       return false;
     }
 
@@ -556,8 +509,9 @@
     }
   }
 
-  if (!WriteHeaderAndBufferToWriter(output_path, res_file, buffer, writer,
-                                    context->GetDiagnostics())) {
+  io::BigBufferInputStream buffer_in(&buffer);
+  if (!WriteHeaderAndDataToWriter(output_path, res_file, &buffer_in, writer,
+                                  context->GetDiagnostics())) {
     return false;
   }
   return true;
@@ -575,6 +529,7 @@
   res_file.name = ResourceName({}, *ParseResourceType(path_data.resource_dir), path_data.name);
   res_file.config = path_data.config;
   res_file.source = path_data.source;
+  res_file.type = ResourceFile::Type::kUnknown;
 
   std::string error_str;
   Maybe<android::FileMap> f = file::MmapPath(path_data.source.path, &error_str);
@@ -584,7 +539,8 @@
     return false;
   }
 
-  if (!WriteHeaderAndMmapToWriter(output_path, res_file, f.value(), writer,
+  io::MmappedData mmapped_in(std::move(f.value()));
+  if (!WriteHeaderAndDataToWriter(output_path, res_file, &mmapped_in, writer,
                                   context->GetDiagnostics())) {
     return false;
   }
@@ -614,7 +570,7 @@
   }
 
   NameMangler* GetNameMangler() override {
-    abort();
+    UNIMPLEMENTED(FATAL) << "No name mangling should be needed in compile phase";
     return nullptr;
   }
 
@@ -628,7 +584,7 @@
   }
 
   SymbolTable* GetExternalSymbols() override {
-    abort();
+    UNIMPLEMENTED(FATAL) << "No symbols should be needed in compile phase";
     return nullptr;
   }
 
@@ -637,14 +593,13 @@
   }
 
  private:
+  DISALLOW_COPY_AND_ASSIGN(CompileContext);
+
   IDiagnostics* diagnostics_;
   bool verbose_ = false;
 };
 
-/**
- * Entry point for compilation phase. Parses arguments and dispatches to the
- * correct steps.
- */
+// Entry point for compilation phase. Parses arguments and dispatches to the correct steps.
 int Compile(const std::vector<StringPiece>& args, IDiagnostics* diagnostics) {
   CompileContext context(diagnostics);
   CompileOptions options;
@@ -717,50 +672,34 @@
       continue;
     }
 
+    // Determine how to compile the file based on its type.
+    auto compile_func = &CompileFile;
     if (path_data.resource_dir == "values") {
-      // Overwrite the extension.
+      compile_func = &CompileTable;
+      // We use a different extension (not necessary anymore, but avoids altering the existing
+      // build system logic).
       path_data.extension = "arsc";
-
-      const std::string output_filename = BuildIntermediateFilename(path_data);
-      if (!CompileTable(&context, options, path_data, archive_writer.get(), output_filename)) {
-        error = true;
-      }
-
-    } else {
-      const std::string output_filename = BuildIntermediateFilename(path_data);
-      if (const ResourceType* type = ParseResourceType(path_data.resource_dir)) {
-        if (*type != ResourceType::kRaw) {
-          if (path_data.extension == "xml") {
-            if (!CompileXml(&context, options, path_data, archive_writer.get(), output_filename)) {
-              error = true;
-            }
-          } else if (!options.no_png_crunch &&
-                     (path_data.extension == "png" || path_data.extension == "9.png")) {
-            if (!CompilePng(&context, options, path_data, archive_writer.get(), output_filename)) {
-              error = true;
-            }
-          } else {
-            if (!CompileFile(&context, options, path_data, archive_writer.get(), output_filename)) {
-              error = true;
-            }
-          }
-        } else {
-          if (!CompileFile(&context, options, path_data, archive_writer.get(), output_filename)) {
-            error = true;
-          }
+    } else if (const ResourceType* type = ParseResourceType(path_data.resource_dir)) {
+      if (*type != ResourceType::kRaw) {
+        if (path_data.extension == "xml") {
+          compile_func = &CompileXml;
+        } else if (!options.no_png_crunch &&
+                   (path_data.extension == "png" || path_data.extension == "9.png")) {
+          compile_func = &CompilePng;
         }
-      } else {
-        context.GetDiagnostics()->Error(DiagMessage() << "invalid file path '" << path_data.source
-                                                      << "'");
-        error = true;
       }
+    } else {
+      context.GetDiagnostics()->Error(DiagMessage()
+                                      << "invalid file path '" << path_data.source << "'");
+      error = true;
+      continue;
     }
-  }
 
-  if (error) {
-    return 1;
+    // Compile the file.
+    const std::string out_path = BuildIntermediateContainerFilename(path_data);
+    error |= !compile_func(&context, options, path_data, archive_writer.get(), out_path);
   }
-  return 0;
+  return error ? 1 : 0;
 }
 
 }  // namespace aapt
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index 44032f6..090c3fb 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -21,8 +21,10 @@
 #include "Debug.h"
 #include "Diagnostics.h"
 #include "Flags.h"
+#include "format/Container.h"
 #include "format/binary/BinaryResourceParser.h"
 #include "format/proto/ProtoDeserialize.h"
+#include "io/FileStream.h"
 #include "io/ZipArchive.h"
 #include "process/IResourceTableConsumer.h"
 #include "util/Files.h"
@@ -31,42 +33,51 @@
 
 namespace aapt {
 
-bool DumpCompiledFile(const pb::internal::CompiledFile& pb_file, const void* data, size_t len,
-                      const Source& source, IAaptContext* context) {
-  ResourceFile file;
-  std::string error;
-  if (!DeserializeCompiledFileFromPb(pb_file, &file, &error)) {
-    context->GetDiagnostics()->Warn(DiagMessage(source)
-                                    << "failed to read compiled file: " << error);
-    return false;
+static const char* ResourceFileTypeToString(const ResourceFile::Type& type) {
+  switch (type) {
+    case ResourceFile::Type::kPng:
+      return "PNG";
+    case ResourceFile::Type::kBinaryXml:
+      return "BINARY_XML";
+    case ResourceFile::Type::kProtoXml:
+      return "PROTO_XML";
+    default:
+      break;
   }
-
-  std::cout << "Resource: " << file.name << "\n"
-            << "Config:   " << file.config << "\n"
-            << "Source:   " << file.source << "\n";
-  return true;
+  return "UNKNOWN";
 }
 
-bool TryDumpFile(IAaptContext* context, const std::string& file_path) {
+static void DumpCompiledFile(const ResourceFile& file, const Source& source, off64_t offset,
+                             size_t len) {
+  std::cout << "Resource: " << file.name << "\n"
+            << "Config:   " << file.config << "\n"
+            << "Source:   " << file.source << "\n"
+            << "Type:     " << ResourceFileTypeToString(file.type) << "\n"
+            << "DataOff:  " << offset << "\n"
+            << "DataLen:  " << len << "\n";
+}
+
+static bool TryDumpFile(IAaptContext* context, const std::string& file_path) {
+  DebugPrintTableOptions print_options;
+  print_options.show_sources = true;
+
   std::string err;
   std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(file_path, &err);
   if (zip) {
     ResourceTable table;
-    if (io::IFile* file = zip->FindFile("resources.arsc.flat")) {
+    if (io::IFile* file = zip->FindFile("resources.pb")) {
       std::unique_ptr<io::IData> data = file->OpenAsData();
       if (data == nullptr) {
-        context->GetDiagnostics()->Error(DiagMessage(file_path)
-                                         << "failed to open resources.arsc.flat");
+        context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.pb");
         return false;
       }
 
       pb::ResourceTable pb_table;
       if (!pb_table.ParseFromArray(data->data(), data->size())) {
-        context->GetDiagnostics()->Error(DiagMessage(file_path) << "invalid resources.arsc.flat");
+        context->GetDiagnostics()->Error(DiagMessage(file_path) << "invalid resources.pb");
         return false;
       }
 
-      ResourceTable table;
       if (!DeserializeTableFromPb(pb_table, &table, &err)) {
         context->GetDiagnostics()->Error(DiagMessage(file_path)
                                          << "failed to parse table: " << err);
@@ -85,62 +96,72 @@
       }
     }
 
-    DebugPrintTableOptions options;
-    options.show_sources = true;
-    Debug::PrintTable(&table, options);
+    Debug::PrintTable(table, print_options);
     return true;
   }
 
   err.clear();
 
-  Maybe<android::FileMap> file = file::MmapPath(file_path, &err);
-  if (!file) {
-    context->GetDiagnostics()->Error(DiagMessage(file_path) << err);
+  io::FileInputStream input(file_path);
+  if (input.HadError()) {
+    context->GetDiagnostics()->Error(DiagMessage(file_path)
+                                     << "failed to open file: " << input.GetError());
     return false;
   }
 
-  android::FileMap* file_map = &file.value();
-
-  // Check to see if this is a loose ResourceTable.
-  pb::ResourceTable pb_table;
-  if (pb_table.ParseFromArray(file_map->getDataPtr(), file_map->getDataLength())) {
-    ResourceTable table;
-    if (DeserializeTableFromPb(pb_table, &table, &err)) {
-      DebugPrintTableOptions options;
-      options.show_sources = true;
-      Debug::PrintTable(&table, options);
-      return true;
-    }
-  }
-
   // Try as a compiled file.
-  CompiledFileInputStream input(file_map->getDataPtr(), file_map->getDataLength());
-  uint32_t num_files = 0;
-  if (!input.ReadLittleEndian32(&num_files)) {
+  ContainerReader reader(&input);
+  if (reader.HadError()) {
+    context->GetDiagnostics()->Error(DiagMessage(file_path)
+                                     << "failed to read container: " << reader.GetError());
     return false;
   }
 
-  for (uint32_t i = 0; i < num_files; i++) {
-    pb::internal::CompiledFile compiled_file;
-    if (!input.ReadCompiledFile(&compiled_file)) {
-      context->GetDiagnostics()->Warn(DiagMessage() << "failed to read compiled file");
-      return false;
-    }
+  ContainerReaderEntry* entry;
+  while ((entry = reader.Next()) != nullptr) {
+    if (entry->Type() == ContainerEntryType::kResTable) {
+      pb::ResourceTable pb_table;
+      if (!entry->GetResTable(&pb_table)) {
+        context->GetDiagnostics()->Error(DiagMessage(file_path)
+                                         << "failed to parse proto table: " << entry->GetError());
+        continue;
+      }
 
-    uint64_t offset, len;
-    if (!input.ReadDataMetaData(&offset, &len)) {
-      context->GetDiagnostics()->Warn(DiagMessage() << "failed to read meta data");
-      return false;
-    }
+      ResourceTable table;
+      err.clear();
+      if (!DeserializeTableFromPb(pb_table, &table, &err)) {
+        context->GetDiagnostics()->Error(DiagMessage(file_path)
+                                         << "failed to parse table: " << err);
+        continue;
+      }
 
-    const void* data = static_cast<const uint8_t*>(file_map->getDataPtr()) + offset;
-    if (!DumpCompiledFile(compiled_file, data, len, Source(file_path), context)) {
-      return false;
+      Debug::PrintTable(table, print_options);
+    } else if (entry->Type() == ContainerEntryType::kResFile) {
+      pb::internal::CompiledFile pb_compiled_file;
+      off64_t offset;
+      size_t length;
+      if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &length)) {
+        context->GetDiagnostics()->Error(
+            DiagMessage(file_path) << "failed to parse compiled proto file: " << entry->GetError());
+        continue;
+      }
+
+      ResourceFile file;
+      std::string error;
+      if (!DeserializeCompiledFileFromPb(pb_compiled_file, &file, &error)) {
+        context->GetDiagnostics()->Warn(DiagMessage(file_path)
+                                        << "failed to parse compiled file: " << error);
+        continue;
+      }
+
+      DumpCompiledFile(file, Source(file_path), offset, length);
     }
   }
   return true;
 }
 
+namespace {
+
 class DumpContext : public IAaptContext {
  public:
   PackageType GetPackageType() override {
@@ -153,7 +174,7 @@
   }
 
   NameMangler* GetNameMangler() override {
-    abort();
+    UNIMPLEMENTED(FATAL);
     return nullptr;
   }
 
@@ -167,7 +188,7 @@
   }
 
   SymbolTable* GetExternalSymbols() override {
-    abort();
+    UNIMPLEMENTED(FATAL);
     return nullptr;
   }
 
@@ -188,9 +209,9 @@
   bool verbose_ = false;
 };
 
-/**
- * Entry point for dump command.
- */
+}  // namespace
+
+// Entry point for dump command.
 int Dump(const std::vector<StringPiece>& args) {
   bool verbose = false;
   Flags flags = Flags().OptionalSwitch("-v", "increase verbosity of output", &verbose);
@@ -206,7 +227,6 @@
       return 1;
     }
   }
-
   return 0;
 }
 
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 88e0f69..55a4c43 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -25,7 +25,6 @@
 #include "android-base/file.h"
 #include "android-base/stringprintf.h"
 #include "androidfw/StringPiece.h"
-#include "google/protobuf/io/coded_stream.h"
 
 #include "AppInfo.h"
 #include "Debug.h"
@@ -39,13 +38,14 @@
 #include "compile/IdAssigner.h"
 #include "filter/ConfigFilter.h"
 #include "format/Archive.h"
+#include "format/Container.h"
 #include "format/binary/BinaryResourceParser.h"
 #include "format/binary/TableFlattener.h"
 #include "format/binary/XmlFlattener.h"
 #include "format/proto/ProtoDeserialize.h"
 #include "format/proto/ProtoSerialize.h"
-#include "io/BigBufferInputStream.h"
-#include "io/FileInputStream.h"
+#include "io/BigBufferStream.h"
+#include "io/FileStream.h"
 #include "io/FileSystem.h"
 #include "io/Util.h"
 #include "io/ZipArchive.h"
@@ -71,6 +71,14 @@
 
 namespace aapt {
 
+constexpr static const char kApkResourceTablePath[] = "resources.arsc";
+constexpr static const char kProtoResourceTablePath[] = "resources.pb";
+
+enum class OutputFormat {
+  kApk,
+  kProto,
+};
+
 struct LinkOptions {
   std::string output_path;
   std::string manifest_path;
@@ -79,6 +87,7 @@
   std::vector<std::string> assets_dirs;
   bool output_to_directory = false;
   bool auto_add_overlay = false;
+  OutputFormat output_format = OutputFormat::kApk;
 
   // Java/Proguard options.
   Maybe<std::string> generate_java_class_path;
@@ -253,25 +262,39 @@
   IAaptContext* context_;
 };
 
-static bool FlattenXml(IAaptContext* context, xml::XmlResource* xml_res, const StringPiece& path,
-                       bool keep_raw_values, IArchiveWriter* writer) {
-  BigBuffer buffer(1024);
-  XmlFlattenerOptions options = {};
-  options.keep_raw_values = keep_raw_values;
-  XmlFlattener flattener(&buffer, options);
-  if (!flattener.Consume(context, xml_res)) {
-    return false;
-  }
-
+static bool FlattenXml(IAaptContext* context, const xml::XmlResource& xml_res,
+                       const StringPiece& path, bool keep_raw_values, bool utf16,
+                       OutputFormat format, IArchiveWriter* writer) {
   if (context->IsVerbose()) {
     context->GetDiagnostics()->Note(DiagMessage(path) << "writing to archive (keep_raw_values="
                                                       << (keep_raw_values ? "true" : "false")
                                                       << ")");
   }
 
-  io::BigBufferInputStream input_stream(&buffer);
-  return io::CopyInputStreamToArchive(context, &input_stream, path.to_string(),
-                                      ArchiveEntry::kCompress, writer);
+  switch (format) {
+    case OutputFormat::kApk: {
+      BigBuffer buffer(1024);
+      XmlFlattenerOptions options = {};
+      options.keep_raw_values = keep_raw_values;
+      options.use_utf16 = utf16;
+      XmlFlattener flattener(&buffer, options);
+      if (!flattener.Consume(context, &xml_res)) {
+        return false;
+      }
+
+      io::BigBufferInputStream input_stream(&buffer);
+      return io::CopyInputStreamToArchive(context, &input_stream, path.to_string(),
+                                          ArchiveEntry::kCompress, writer);
+    } break;
+
+    case OutputFormat::kProto: {
+      pb::XmlNode pb_node;
+      SerializeXmlResourceToPb(xml_res, &pb_node);
+      return io::CopyProtoToArchive(context, &pb_node, path.to_string(), ArchiveEntry::kCompress,
+                                    writer);
+    } break;
+  }
+  return false;
 }
 
 static std::unique_ptr<ResourceTable> LoadTableFromPb(const Source& source, const void* data,
@@ -309,6 +332,7 @@
   bool keep_raw_values = false;
   bool do_not_compress_anything = false;
   bool update_proguard_spec = false;
+  OutputFormat output_format = OutputFormat::kApk;
   std::unordered_set<std::string> extensions_to_not_compress;
 };
 
@@ -446,7 +470,7 @@
 
 static bool IsVectorElement(const std::string& name) {
   return name == "vector" || name == "animated-vector" || name == "pathInterpolator" ||
-         name == "objectAnimator";
+         name == "objectAnimator" || name == "gradient";
 }
 
 template <typename T>
@@ -466,6 +490,10 @@
                                      << "linking " << src.path << " (" << doc->file.name << ")");
   }
 
+  // First, strip out any tools namespace attributes. AAPT stripped them out early, which means
+  // that existing projects have out-of-date references which pass compilation.
+  xml::StripAndroidStudioAttributes(doc->root.get());
+
   XmlReferenceLinker xml_linker;
   if (!xml_linker.Consume(context_, doc)) {
     return {};
@@ -542,9 +570,9 @@
           file_op.config = config_value->config;
           file_op.file_to_copy = file;
 
-          const StringPiece src_path = file->GetSource().path;
           if (type->type != ResourceType::kRaw &&
-              (util::EndsWith(src_path, ".xml.flat") || util::EndsWith(src_path, ".xml"))) {
+              (file_ref->type == ResourceFile::Type::kBinaryXml ||
+               file_ref->type == ResourceFile::Type::kProtoXml)) {
             std::unique_ptr<io::IData> data = file->OpenAsData();
             if (!data) {
               context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
@@ -552,11 +580,27 @@
               return false;
             }
 
-            file_op.xml_to_flatten = xml::Inflate(data->data(), data->size(),
-                                                  context_->GetDiagnostics(), file->GetSource());
+            if (file_ref->type == ResourceFile::Type::kProtoXml) {
+              pb::XmlNode pb_xml_node;
+              if (!pb_xml_node.ParseFromArray(data->data(), static_cast<int>(data->size()))) {
+                context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
+                                                  << "failed to parse proto xml");
+                return false;
+              }
 
-            if (!file_op.xml_to_flatten) {
-              return false;
+              std::string error;
+              file_op.xml_to_flatten = DeserializeXmlResourceFromPb(pb_xml_node, &error);
+              if (file_op.xml_to_flatten == nullptr) {
+                context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
+                                                  << "failed to deserialize proto xml: " << error);
+                return false;
+              }
+            } else {
+              file_op.xml_to_flatten = xml::Inflate(data->data(), data->size(),
+                                                    context_->GetDiagnostics(), file->GetSource());
+              if (file_op.xml_to_flatten == nullptr) {
+                return false;
+              }
             }
 
             file_op.xml_to_flatten->file.config = config_value->config;
@@ -606,8 +650,9 @@
                 return false;
               }
             }
-            error |= !FlattenXml(context_, doc.get(), dst_path, options_.keep_raw_values,
-                                 archive_writer);
+
+            error |= !FlattenXml(context_, *doc, dst_path, options_.keep_raw_values,
+                                 false /*utf16*/, options_.output_format, archive_writer);
           }
         } else {
           error |= !io::CopyFileToArchive(context_, file_op.file_to_copy, file_op.dst_path,
@@ -906,23 +951,29 @@
     }
   }
 
-  bool FlattenTable(ResourceTable* table, IArchiveWriter* writer) {
-    BigBuffer buffer(1024);
-    TableFlattener flattener(options_.table_flattener_options, &buffer);
-    if (!flattener.Consume(context_, table)) {
-      context_->GetDiagnostics()->Error(DiagMessage() << "failed to flatten resource table");
-      return false;
+  bool FlattenTable(ResourceTable* table, OutputFormat format, IArchiveWriter* writer) {
+    switch (format) {
+      case OutputFormat::kApk: {
+        BigBuffer buffer(1024);
+        TableFlattener flattener(options_.table_flattener_options, &buffer);
+        if (!flattener.Consume(context_, table)) {
+          context_->GetDiagnostics()->Error(DiagMessage() << "failed to flatten resource table");
+          return false;
+        }
+
+        io::BigBufferInputStream input_stream(&buffer);
+        return io::CopyInputStreamToArchive(context_, &input_stream, kApkResourceTablePath,
+                                            ArchiveEntry::kAlign, writer);
+      } break;
+
+      case OutputFormat::kProto: {
+        pb::ResourceTable pb_table;
+        SerializeTableToPb(*table, &pb_table);
+        return io::CopyProtoToArchive(context_, &pb_table, kProtoResourceTablePath,
+                                      ArchiveEntry::kCompress, writer);
+      } break;
     }
-
-    io::BigBufferInputStream input_stream(&buffer);
-    return io::CopyInputStreamToArchive(context_, &input_stream, "resources.arsc",
-                                        ArchiveEntry::kAlign, writer);
-  }
-
-  bool FlattenTableToPb(ResourceTable* table, IArchiveWriter* writer) {
-    pb::ResourceTable pb_table;
-    SerializeTableToPb(*table, &pb_table);
-    return io::CopyProtoToArchive(context_, &pb_table, "resources.arsc.flat", 0, writer);
+    return false;
   }
 
   bool WriteJavaFile(ResourceTable* table, const StringPiece& package_name_to_generate,
@@ -1151,7 +1202,7 @@
   }
 
   std::unique_ptr<ResourceTable> LoadTablePbFromCollection(io::IFileCollection* collection) {
-    io::IFile* file = collection->FindFile("resources.arsc.flat");
+    io::IFile* file = collection->FindFile(kProtoResourceTablePath);
     if (!file) {
       return {};
     }
@@ -1200,11 +1251,7 @@
       // Clear the package name, so as to make the resources look like they are coming from the
       // local package.
       pkg->name = "";
-      if (override) {
-        result = table_merger_->MergeOverlay(Source(input), table.get(), collection.get());
-      } else {
-        result = table_merger_->Merge(Source(input), table.get(), collection.get());
-      }
+      result = table_merger_->Merge(Source(input), table.get(), override, collection.get());
 
     } else {
       // This is the proper way to merge libraries, where the package name is
@@ -1240,49 +1287,34 @@
       return false;
     }
 
-    bool result = false;
-    if (override) {
-      result = table_merger_->MergeOverlay(file->GetSource(), table.get());
-    } else {
-      result = table_merger_->Merge(file->GetSource(), table.get());
-    }
-    return result;
+    return table_merger_->Merge(file->GetSource(), table.get(), override);
   }
 
-  bool MergeCompiledFile(io::IFile* file, ResourceFile* file_desc, bool override) {
+  bool MergeCompiledFile(const ResourceFile& compiled_file, io::IFile* file, bool override) {
     if (context_->IsVerbose()) {
-      context_->GetDiagnostics()->Note(DiagMessage() << "merging '" << file_desc->name
-                                                     << "' from compiled file "
-                                                     << file->GetSource());
+      context_->GetDiagnostics()->Note(DiagMessage()
+                                       << "merging '" << compiled_file.name
+                                       << "' from compiled file " << compiled_file.source);
     }
 
-    bool result = false;
-    if (override) {
-      result = table_merger_->MergeFileOverlay(*file_desc, file);
-    } else {
-      result = table_merger_->MergeFile(*file_desc, file);
-    }
-
-    if (!result) {
+    if (!table_merger_->MergeFile(compiled_file, override, file)) {
       return false;
     }
 
     // Add the exports of this file to the table.
-    for (SourcedResourceName& exported_symbol : file_desc->exported_symbols) {
-      if (exported_symbol.name.package.empty()) {
-        exported_symbol.name.package = context_->GetCompilationPackage();
+    for (const SourcedResourceName& exported_symbol : compiled_file.exported_symbols) {
+      ResourceName res_name = exported_symbol.name;
+      if (res_name.package.empty()) {
+        res_name.package = context_->GetCompilationPackage();
       }
 
-      ResourceNameRef res_name = exported_symbol.name;
-
-      Maybe<ResourceName> mangled_name =
-          context_->GetNameMangler()->MangleName(exported_symbol.name);
+      Maybe<ResourceName> mangled_name = context_->GetNameMangler()->MangleName(res_name);
       if (mangled_name) {
         res_name = mangled_name.value();
       }
 
       std::unique_ptr<Id> id = util::make_unique<Id>();
-      id->SetSource(file_desc->source.WithLine(exported_symbol.line));
+      id->SetSource(compiled_file.source.WithLine(exported_symbol.line));
       bool result = final_table_.AddResourceAllowMangled(
           res_name, ConfigDescription::DefaultConfig(), std::string(), std::move(id),
           context_->GetDiagnostics());
@@ -1293,15 +1325,11 @@
     return true;
   }
 
-  /**
-   * Takes a path to load as a ZIP file and merges the files within into the
-   * master ResourceTable.
-   * If override is true, conflicting resources are allowed to override each
-   * other, in order of last seen.
-   *
-   * An io::IFileCollection is created from the ZIP file and added to the set of
-   * io::IFileCollections that are open.
-   */
+  // Takes a path to load as a ZIP file and merges the files within into the master ResourceTable.
+  // If override is true, conflicting resources are allowed to override each other, in order of last
+  // seen.
+  // An io::IFileCollection is created from the ZIP file and added to the set of
+  // io::IFileCollections that are open.
   bool MergeArchive(const std::string& input, bool override) {
     if (context_->IsVerbose()) {
       context_->GetDiagnostics()->Note(DiagMessage() << "merging archive " << input);
@@ -1327,18 +1355,11 @@
     return !error;
   }
 
-  /**
-   * Takes a path to load and merge into the master ResourceTable. If override
-   * is true,
-   * conflicting resources are allowed to override each other, in order of last
-   * seen.
-   *
-   * If the file path ends with .flata, .jar, .jack, or .zip the file is treated
-   * as ZIP archive
-   * and the files within are merged individually.
-   *
-   * Otherwise the files is processed on its own.
-   */
+  // Takes a path to load and merge into the master ResourceTable. If override is true,
+  // conflicting resources are allowed to override each other, in order of last seen.
+  // If the file path ends with .flata, .jar, .jack, or .zip the file is treated
+  // as ZIP archive and the files within are merged individually.
+  // Otherwise the file is processed on its own.
   bool MergePath(const std::string& path, bool override) {
     if (util::EndsWith(path, ".flata") || util::EndsWith(path, ".jar") ||
         util::EndsWith(path, ".jack") || util::EndsWith(path, ".zip")) {
@@ -1351,70 +1372,15 @@
     return MergeFile(file, override);
   }
 
-  /**
-   * Takes a file to load and merge into the master ResourceTable. If override
-   * is true,
-   * conflicting resources are allowed to override each other, in order of last
-   * seen.
-   *
-   * If the file ends with .arsc.flat, then it is loaded as a ResourceTable and
-   * merged into the
-   * master ResourceTable. If the file ends with .flat, then it is treated like
-   * a compiled file
-   * and the header data is read and merged into the final ResourceTable.
-   *
-   * All other file types are ignored. This is because these files could be
-   * coming from a zip,
-   * where we could have other files like classes.dex.
-   */
+  // Takes an AAPT Container file (.apc/.flat) to load and merge into the master ResourceTable.
+  // If override is true, conflicting resources are allowed to override each other, in order of last
+  // seen.
+  // All other file types are ignored. This is because these files could be coming from a zip,
+  // where we could have other files like classes.dex.
   bool MergeFile(io::IFile* file, bool override) {
     const Source& src = file->GetSource();
-    if (util::EndsWith(src.path, ".arsc.flat")) {
-      return MergeResourceTable(file, override);
 
-    } else if (util::EndsWith(src.path, ".flat")) {
-      // Try opening the file and looking for an Export header.
-      std::unique_ptr<io::IData> data = file->OpenAsData();
-      if (!data) {
-        context_->GetDiagnostics()->Error(DiagMessage(src) << "failed to open");
-        return false;
-      }
-
-      CompiledFileInputStream input_stream(data->data(), data->size());
-      uint32_t num_files = 0;
-      if (!input_stream.ReadLittleEndian32(&num_files)) {
-        context_->GetDiagnostics()->Error(DiagMessage(src) << "failed read num files");
-        return false;
-      }
-
-      for (uint32_t i = 0; i < num_files; i++) {
-        pb::internal::CompiledFile compiled_file;
-        if (!input_stream.ReadCompiledFile(&compiled_file)) {
-          context_->GetDiagnostics()->Error(DiagMessage(src)
-                                            << "failed to read compiled file header");
-          return false;
-        }
-
-        uint64_t offset, len;
-        if (!input_stream.ReadDataMetaData(&offset, &len)) {
-          context_->GetDiagnostics()->Error(DiagMessage(src) << "failed to read data meta data");
-          return false;
-        }
-
-        ResourceFile resource_file;
-        std::string error;
-        if (!DeserializeCompiledFileFromPb(compiled_file, &resource_file, &error)) {
-          context_->GetDiagnostics()->Error(DiagMessage(src)
-                                            << "failed to read compiled header: " << error);
-          return false;
-        }
-
-        if (!MergeCompiledFile(file->CreateFileSegment(offset, len), &resource_file, override)) {
-          return false;
-        }
-      }
-      return true;
-    } else if (util::EndsWith(src.path, ".xml") || util::EndsWith(src.path, ".png")) {
+    if (util::EndsWith(src.path, ".xml") || util::EndsWith(src.path, ".png")) {
       // Since AAPT compiles these file types and appends .flat to them, seeing
       // their raw extensions is a sign that they weren't compiled.
       const StringPiece file_type = util::EndsWith(src.path, ".xml") ? "XML" : "PNG";
@@ -1422,11 +1388,71 @@
                                                          << " file passed as argument. Must be "
                                                             "compiled first into .flat file.");
       return false;
+    } else if (!util::EndsWith(src.path, ".apc") && !util::EndsWith(src.path, ".flat")) {
+      if (context_->IsVerbose()) {
+        context_->GetDiagnostics()->Warn(DiagMessage(src) << "ignoring unrecognized file");
+        return true;
+      }
     }
 
-    // Ignore non .flat files. This could be classes.dex or something else that
-    // happens
-    // to be in an archive.
+    std::unique_ptr<io::InputStream> input_stream = file->OpenInputStream();
+    if (input_stream == nullptr) {
+      context_->GetDiagnostics()->Error(DiagMessage(src) << "failed to open file");
+      return false;
+    }
+
+    if (input_stream->HadError()) {
+      context_->GetDiagnostics()->Error(DiagMessage(src)
+                                        << "failed to open file: " << input_stream->GetError());
+      return false;
+    }
+
+    ContainerReaderEntry* entry;
+    ContainerReader reader(input_stream.get());
+    while ((entry = reader.Next()) != nullptr) {
+      if (entry->Type() == ContainerEntryType::kResTable) {
+        pb::ResourceTable pb_table;
+        if (!entry->GetResTable(&pb_table)) {
+          context_->GetDiagnostics()->Error(DiagMessage(src) << "failed to read resource table: "
+                                                             << entry->GetError());
+          return false;
+        }
+
+        ResourceTable table;
+        std::string error;
+        if (!DeserializeTableFromPb(pb_table, &table, &error)) {
+          context_->GetDiagnostics()->Error(DiagMessage(src)
+                                            << "failed to deserialize resource table: " << error);
+          return false;
+        }
+
+        if (!table_merger_->Merge(src, &table, override)) {
+          context_->GetDiagnostics()->Error(DiagMessage(src) << "failed to merge resource table");
+          return false;
+        }
+      } else if (entry->Type() == ContainerEntryType::kResFile) {
+        pb::internal::CompiledFile pb_compiled_file;
+        off64_t offset;
+        size_t len;
+        if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &len)) {
+          context_->GetDiagnostics()->Error(DiagMessage(src) << "failed to get resource file: "
+                                                             << entry->GetError());
+          return false;
+        }
+
+        ResourceFile resource_file;
+        std::string error;
+        if (!DeserializeCompiledFileFromPb(pb_compiled_file, &resource_file, &error)) {
+          context_->GetDiagnostics()->Error(DiagMessage(src)
+                                            << "failed to read compiled header: " << error);
+          return false;
+        }
+
+        if (!MergeCompiledFile(resource_file, file->CreateFileSegment(offset, len), override)) {
+          return false;
+        }
+      }
+    }
     return true;
   }
 
@@ -1470,14 +1496,13 @@
     return true;
   }
 
-  /**
-   * Writes the AndroidManifest, ResourceTable, and all XML files referenced by
-   * the ResourceTable to the IArchiveWriter.
-   */
+  // Writes the AndroidManifest, ResourceTable, and all XML files referenced by the ResourceTable
+  // to the IArchiveWriter.
   bool WriteApk(IArchiveWriter* writer, proguard::KeepSet* keep_set, xml::XmlResource* manifest,
                 ResourceTable* table) {
     const bool keep_raw_values = context_->GetPackageType() == PackageType::kStaticLib;
-    bool result = FlattenXml(context_, manifest, "AndroidManifest.xml", keep_raw_values, writer);
+    bool result = FlattenXml(context_, *manifest, "AndroidManifest.xml", keep_raw_values,
+                             true /*utf16*/, options_.output_format, writer);
     if (!result) {
       return false;
     }
@@ -1492,6 +1517,7 @@
     file_flattener_options.no_xml_namespaces = options_.no_xml_namespaces;
     file_flattener_options.update_proguard_spec =
         static_cast<bool>(options_.generate_proguard_rules_path);
+    file_flattener_options.output_format = options_.output_format;
 
     ResourceFileFlattener file_flattener(file_flattener_options, context_, keep_set);
 
@@ -1500,15 +1526,9 @@
       return false;
     }
 
-    if (context_->GetPackageType() == PackageType::kStaticLib) {
-      if (!FlattenTableToPb(table, writer)) {
-        return false;
-      }
-    } else {
-      if (!FlattenTable(table, writer)) {
-        context_->GetDiagnostics()->Error(DiagMessage() << "failed to write resources.arsc");
-        return false;
-      }
+    if (!FlattenTable(table, options_.output_format, writer)) {
+      context_->GetDiagnostics()->Error(DiagMessage() << "failed to write resource table");
+      return false;
     }
     return true;
   }
@@ -1872,6 +1892,7 @@
   bool verbose = false;
   bool shared_lib = false;
   bool static_lib = false;
+  bool proto_format = false;
   Maybe<std::string> stable_id_file_path;
   std::vector<std::string> split_args;
   Flags flags =
@@ -1952,6 +1973,10 @@
           .OptionalSwitch("--shared-lib", "Generates a shared Android runtime library.",
                           &shared_lib)
           .OptionalSwitch("--static-lib", "Generate a static Android library.", &static_lib)
+          .OptionalSwitch("--proto-format",
+                          "Generates compiled resources in Protobuf format.\n"
+                          "Suitable as input to the bundle tool for generating an App Bundle.",
+                          &proto_format)
           .OptionalSwitch("--no-static-lib-packages",
                           "Merge all library resources under the app's package.",
                           &options.no_static_lib_packages)
@@ -2038,21 +2063,25 @@
     context.SetVerbose(verbose);
   }
 
-  if (shared_lib && static_lib) {
-    context.GetDiagnostics()->Error(DiagMessage()
-                                    << "only one of --shared-lib and --static-lib can be defined");
+  if (int{shared_lib} + int{static_lib} + int{proto_format} > 1) {
+    context.GetDiagnostics()->Error(
+        DiagMessage()
+        << "only one of --shared-lib, --static-lib, or --proto_format can be defined");
     return 1;
   }
 
+  // The default build type.
+  context.SetPackageType(PackageType::kApp);
+  context.SetPackageId(kAppPackageId);
+
   if (shared_lib) {
     context.SetPackageType(PackageType::kSharedLib);
     context.SetPackageId(0x00);
   } else if (static_lib) {
     context.SetPackageType(PackageType::kStaticLib);
-    context.SetPackageId(kAppPackageId);
-  } else {
-    context.SetPackageType(PackageType::kApp);
-    context.SetPackageId(kAppPackageId);
+    options.output_format = OutputFormat::kProto;
+  } else if (proto_format) {
+    options.output_format = OutputFormat::kProto;
   }
 
   if (package_id) {
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index 67ac67a..44e148e 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -33,7 +33,7 @@
 #include "filter/AbiFilter.h"
 #include "format/binary/TableFlattener.h"
 #include "format/binary/XmlFlattener.h"
-#include "io/BigBufferInputStream.h"
+#include "io/BigBufferStream.h"
 #include "io/Util.h"
 #include "optimize/MultiApkGenerator.h"
 #include "optimize/ResourceDeduper.h"
diff --git a/tools/aapt2/cmd/Util.cpp b/tools/aapt2/cmd/Util.cpp
index d17858d..708bed8 100644
--- a/tools/aapt2/cmd/Util.cpp
+++ b/tools/aapt2/cmd/Util.cpp
@@ -72,7 +72,6 @@
   }
 
   *out_path = parts[0];
-  std::vector<ConfigDescription> configs;
   for (const StringPiece& config_str : util::Tokenize(parts[1], ',')) {
     ConfigDescription config;
     if (!ConfigDescription::Parse(config_str, &config)) {
@@ -141,6 +140,16 @@
   return decl;
 }
 
+static std::string MakePackageSafeName(const std::string &name) {
+  std::string result(name);
+  for (char &c : result) {
+    if (c == '-') {
+      c = '_';
+    }
+  }
+  return result;
+}
+
 std::unique_ptr<xml::XmlResource> GenerateSplitManifest(const AppInfo& app_info,
                                                         const SplitConstraints& constraints) {
   const ResourceId kVersionCode(0x0101021b);
@@ -172,7 +181,11 @@
   if (app_info.split_name) {
     split_name << app_info.split_name.value() << ".";
   }
-  split_name << "config." << util::Joiner(constraints.configs, "_");
+  std::vector<std::string> sanitized_config_names;
+  for (const auto &config : constraints.configs) {
+    sanitized_config_names.push_back(MakePackageSafeName(config.toString().string()));
+  }
+  split_name << "config." << util::Joiner(sanitized_config_names, "_");
 
   manifest_el->attributes.push_back(xml::Attribute{"", "split", split_name.str()});
 
diff --git a/tools/aapt2/cmd/Util_test.cpp b/tools/aapt2/cmd/Util_test.cpp
new file mode 100644
index 0000000..9c33135
--- /dev/null
+++ b/tools/aapt2/cmd/Util_test.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Util.h"
+
+#include "AppInfo.h"
+#include "split/TableSplitter.h"
+#include "test/Test.h"
+
+namespace aapt {
+
+TEST(UtilTest, SplitNamesAreSanitized) {
+    AppInfo app_info{"com.pkg"};
+    SplitConstraints split_constraints{{test::ParseConfigOrDie("en-rUS-land")}};
+
+    const auto doc = GenerateSplitManifest(app_info, split_constraints);
+    const auto &root = doc->root;
+    EXPECT_EQ(root->name, "manifest");
+    // split names cannot contain hyphens
+    EXPECT_EQ(root->FindAttribute("", "split")->value, "config.en_rUS_land");
+    // but we should use resource qualifiers verbatim in 'targetConfig'.
+    EXPECT_EQ(root->FindAttribute("", "targetConfig")->value, "en-rUS-land");
+}
+
+}  // namespace aapt
diff --git a/tools/aapt2/configuration/ConfigurationParser.cpp b/tools/aapt2/configuration/ConfigurationParser.cpp
index a79a577..b99240f 100644
--- a/tools/aapt2/configuration/ConfigurationParser.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser.cpp
@@ -30,7 +30,7 @@
 #include "ResourceUtils.h"
 #include "io/File.h"
 #include "io/FileSystem.h"
-#include "io/StringInputStream.h"
+#include "io/StringStream.h"
 #include "util/Files.h"
 #include "util/Maybe.h"
 #include "util/Util.h"
diff --git a/tools/aapt2/format/Container.cpp b/tools/aapt2/format/Container.cpp
new file mode 100644
index 0000000..739555c
--- /dev/null
+++ b/tools/aapt2/format/Container.cpp
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "format/Container.h"
+
+#include "android-base/scopeguard.h"
+#include "android-base/stringprintf.h"
+
+using ::android::base::StringPrintf;
+using ::google::protobuf::io::CodedInputStream;
+using ::google::protobuf::io::CodedOutputStream;
+using ::google::protobuf::io::ZeroCopyOutputStream;
+
+namespace aapt {
+
+constexpr const static uint32_t kContainerFormatMagic = 0x54504141u;
+constexpr const static uint32_t kContainerFormatVersion = 1u;
+
+ContainerWriter::ContainerWriter(ZeroCopyOutputStream* out, size_t entry_count)
+    : out_(out), total_entry_count_(entry_count), current_entry_count_(0u) {
+  CodedOutputStream coded_out(out_);
+
+  // Write the magic.
+  coded_out.WriteLittleEndian32(kContainerFormatMagic);
+
+  // Write the version.
+  coded_out.WriteLittleEndian32(kContainerFormatVersion);
+
+  // Write the total number of entries.
+  coded_out.WriteLittleEndian32(static_cast<uint32_t>(total_entry_count_));
+
+  if (coded_out.HadError()) {
+    error_ = "failed writing container format header";
+  }
+}
+
+inline static void WritePadding(int padding, CodedOutputStream* out) {
+  if (padding < 4) {
+    const uint32_t zero = 0u;
+    out->WriteRaw(&zero, padding);
+  }
+}
+
+bool ContainerWriter::AddResTableEntry(const pb::ResourceTable& table) {
+  if (current_entry_count_ >= total_entry_count_) {
+    error_ = "too many entries being serialized";
+    return false;
+  }
+  current_entry_count_++;
+
+  CodedOutputStream coded_out(out_);
+
+  // Write the type.
+  coded_out.WriteLittleEndian32(kResTable);
+
+  // Write the aligned size.
+  const ::google::protobuf::uint64 size = table.ByteSize();
+  const int padding = 4 - (size % 4);
+  coded_out.WriteLittleEndian64(size);
+
+  // Write the table.
+  table.SerializeWithCachedSizes(&coded_out);
+
+  // Write the padding.
+  WritePadding(padding, &coded_out);
+
+  if (coded_out.HadError()) {
+    error_ = "failed writing to output";
+    return false;
+  }
+  return true;
+}
+
+bool ContainerWriter::AddResFileEntry(const pb::internal::CompiledFile& file,
+                                      io::KnownSizeInputStream* in) {
+  if (current_entry_count_ >= total_entry_count_) {
+    error_ = "too many entries being serialized";
+    return false;
+  }
+  current_entry_count_++;
+
+  constexpr const static int kResFileEntryHeaderSize = 12;
+
+  CodedOutputStream coded_out(out_);
+
+  // Write the type.
+  coded_out.WriteLittleEndian32(kResFile);
+
+  // Write the aligned size.
+  const ::google::protobuf::uint32 header_size = file.ByteSize();
+  const int header_padding = 4 - (header_size % 4);
+  const ::google::protobuf::uint64 data_size = in->TotalSize();
+  const int data_padding = 4 - (data_size % 4);
+  coded_out.WriteLittleEndian64(kResFileEntryHeaderSize + header_size + header_padding + data_size +
+                                data_padding);
+
+  // Write the res file header size.
+  coded_out.WriteLittleEndian32(header_size);
+
+  // Write the data payload size.
+  coded_out.WriteLittleEndian64(data_size);
+
+  // Write the header.
+  file.SerializeToCodedStream(&coded_out);
+
+  WritePadding(header_padding, &coded_out);
+
+  // Write the data payload. We need to call Trim() since we are going to write to the underlying
+  // ZeroCopyOutputStream.
+  coded_out.Trim();
+
+  // Check at this point if there were any errors.
+  if (coded_out.HadError()) {
+    error_ = "failed writing to output";
+    return false;
+  }
+
+  if (!io::Copy(out_, in)) {
+    if (in->HadError()) {
+      std::ostringstream error;
+      error << "failed reading from input: " << in->GetError();
+      error_ = error.str();
+    } else {
+      error_ = "failed writing to output";
+    }
+    return false;
+  }
+  WritePadding(data_padding, &coded_out);
+
+  if (coded_out.HadError()) {
+    error_ = "failed writing to output";
+    return false;
+  }
+  return true;
+}
+
+bool ContainerWriter::HadError() const {
+  return !error_.empty();
+}
+
+std::string ContainerWriter::GetError() const {
+  return error_;
+}
+
+static bool AlignRead(CodedInputStream* in) {
+  const int padding = 4 - (in->CurrentPosition() % 4);
+  if (padding < 4) {
+    return in->Skip(padding);
+  }
+  return true;
+}
+
+ContainerReaderEntry::ContainerReaderEntry(ContainerReader* reader) : reader_(reader) {
+}
+
+ContainerEntryType ContainerReaderEntry::Type() const {
+  return type_;
+}
+
+bool ContainerReaderEntry::GetResTable(pb::ResourceTable* out_table) {
+  CHECK(type_ == ContainerEntryType::kResTable) << "reading a kResTable when the type is kResFile";
+  if (length_ > std::numeric_limits<int>::max()) {
+    reader_->error_ = StringPrintf("entry length %zu is too large", length_);
+    return false;
+  }
+
+  CodedInputStream& coded_in = reader_->coded_in_;
+
+  const CodedInputStream::Limit limit = coded_in.PushLimit(static_cast<int>(length_));
+  auto guard = ::android::base::make_scope_guard([&]() { coded_in.PopLimit(limit); });
+
+  if (!out_table->ParseFromCodedStream(&coded_in)) {
+    reader_->error_ = "failed to parse ResourceTable";
+    return false;
+  }
+  return true;
+}
+
+bool ContainerReaderEntry::GetResFileOffsets(pb::internal::CompiledFile* out_file,
+                                             off64_t* out_offset, size_t* out_len) {
+  CHECK(type_ == ContainerEntryType::kResFile) << "reading a kResFile when the type is kResTable";
+
+  CodedInputStream& coded_in = reader_->coded_in_;
+
+  // Read the ResFile header.
+  ::google::protobuf::uint32 header_length;
+  if (!coded_in.ReadLittleEndian32(&header_length)) {
+    std::ostringstream error;
+    error << "failed to read header length from input: " << reader_->in_->GetError();
+    reader_->error_ = error.str();
+    return false;
+  }
+
+  ::google::protobuf::uint64 data_length;
+  if (!coded_in.ReadLittleEndian64(&data_length)) {
+    std::ostringstream error;
+    error << "failed to read data length from input: " << reader_->in_->GetError();
+    reader_->error_ = error.str();
+    return false;
+  }
+
+  if (header_length > std::numeric_limits<int>::max()) {
+    std::ostringstream error;
+    error << "header length " << header_length << " is too large";
+    reader_->error_ = error.str();
+    return false;
+  }
+
+  if (data_length > std::numeric_limits<size_t>::max()) {
+    std::ostringstream error;
+    error << "data length " << data_length << " is too large";
+    reader_->error_ = error.str();
+    return false;
+  }
+
+  {
+    const CodedInputStream::Limit limit = coded_in.PushLimit(static_cast<int>(header_length));
+    auto guard = ::android::base::make_scope_guard([&]() { coded_in.PopLimit(limit); });
+
+    if (!out_file->ParseFromCodedStream(&coded_in)) {
+      reader_->error_ = "failed to parse CompiledFile header";
+      return false;
+    }
+  }
+
+  AlignRead(&coded_in);
+
+  *out_offset = coded_in.CurrentPosition();
+  *out_len = data_length;
+
+  coded_in.Skip(static_cast<int>(data_length));
+  AlignRead(&coded_in);
+  return true;
+}
+
+bool ContainerReaderEntry::HadError() const {
+  return reader_->HadError();
+}
+
+std::string ContainerReaderEntry::GetError() const {
+  return reader_->GetError();
+}
+
+ContainerReader::ContainerReader(io::InputStream* in)
+    : in_(in),
+      adaptor_(in),
+      coded_in_(&adaptor_),
+      total_entry_count_(0u),
+      current_entry_count_(0u),
+      entry_(this) {
+  ::google::protobuf::uint32 magic;
+  if (!coded_in_.ReadLittleEndian32(&magic)) {
+    std::ostringstream error;
+    error << "failed to read magic from input: " << in_->GetError();
+    error_ = error.str();
+    return;
+  }
+
+  if (magic != kContainerFormatMagic) {
+    error_ = "magic value doesn't match AAPT";
+    return;
+  }
+
+  ::google::protobuf::uint32 version;
+  if (!coded_in_.ReadLittleEndian32(&version)) {
+    std::ostringstream error;
+    error << "failed to read version from input: " << in_->GetError();
+    error_ = error.str();
+    return;
+  }
+
+  if (version != kContainerFormatVersion) {
+    error_ = StringPrintf("container version is 0x%08x but AAPT expects version 0x%08x", version,
+                          kContainerFormatVersion);
+    return;
+  }
+
+  ::google::protobuf::uint32 total_entry_count;
+  if (!coded_in_.ReadLittleEndian32(&total_entry_count)) {
+    std::ostringstream error;
+    error << "failed to read entry count from input: " << in_->GetError();
+    error_ = error.str();
+    return;
+  }
+
+  total_entry_count_ = total_entry_count;
+}
+
+ContainerReaderEntry* ContainerReader::Next() {
+  if (current_entry_count_ >= total_entry_count_) {
+    return nullptr;
+  }
+  current_entry_count_++;
+
+  // Ensure the next read is aligned.
+  AlignRead(&coded_in_);
+
+  ::google::protobuf::uint32 entry_type;
+  if (!coded_in_.ReadLittleEndian32(&entry_type)) {
+    std::ostringstream error;
+    error << "failed reading entry type from input: " << in_->GetError();
+    error_ = error.str();
+    return nullptr;
+  }
+
+  ::google::protobuf::uint64 entry_length;
+  if (!coded_in_.ReadLittleEndian64(&entry_length)) {
+    std::ostringstream error;
+    error << "failed reading entry length from input: " << in_->GetError();
+    error_ = error.str();
+    return nullptr;
+  }
+
+  if (entry_type == ContainerEntryType::kResFile || entry_type == ContainerEntryType::kResTable) {
+    entry_.type_ = static_cast<ContainerEntryType>(entry_type);
+  } else {
+    error_ = StringPrintf("entry type 0x%08x is invalid", entry_type);
+    return nullptr;
+  }
+
+  if (entry_length > std::numeric_limits<size_t>::max()) {
+    std::ostringstream error;
+    error << "entry length " << entry_length << " is too large";
+    error_ = error.str();
+    return nullptr;
+  }
+
+  entry_.length_ = entry_length;
+  return &entry_;
+}
+
+bool ContainerReader::HadError() const {
+  return !error_.empty();
+}
+
+std::string ContainerReader::GetError() const {
+  return error_;
+}
+
+}  // namespace aapt
diff --git a/tools/aapt2/format/Container.h b/tools/aapt2/format/Container.h
new file mode 100644
index 0000000..aa5c82c
--- /dev/null
+++ b/tools/aapt2/format/Container.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_FORMAT_CONTAINER_H
+#define AAPT_FORMAT_CONTAINER_H
+
+#include <inttypes.h>
+
+#include "google/protobuf/io/coded_stream.h"
+#include "google/protobuf/io/zero_copy_stream.h"
+
+#include "Resources.pb.h"
+#include "ResourcesInternal.pb.h"
+#include "io/Io.h"
+#include "io/Util.h"
+#include "util/BigBuffer.h"
+
+namespace aapt {
+
+enum ContainerEntryType : uint8_t {
+  kResTable = 0x00u,
+  kResFile = 0x01u,
+};
+
+class ContainerWriter {
+ public:
+  explicit ContainerWriter(::google::protobuf::io::ZeroCopyOutputStream* out, size_t entry_count);
+
+  bool AddResTableEntry(const pb::ResourceTable& table);
+  bool AddResFileEntry(const pb::internal::CompiledFile& file, io::KnownSizeInputStream* in);
+  bool HadError() const;
+  std::string GetError() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ContainerWriter);
+
+  ::google::protobuf::io::ZeroCopyOutputStream* out_;
+  size_t total_entry_count_;
+  size_t current_entry_count_;
+  std::string error_;
+};
+
+class ContainerReader;
+
+class ContainerReaderEntry {
+ public:
+  ContainerEntryType Type() const;
+
+  bool GetResTable(pb::ResourceTable* out_table);
+  bool GetResFileOffsets(pb::internal::CompiledFile* out_file, off64_t* out_offset,
+                         size_t* out_len);
+
+  bool HadError() const;
+  std::string GetError() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ContainerReaderEntry);
+
+  friend class ContainerReader;
+
+  explicit ContainerReaderEntry(ContainerReader* reader);
+
+  ContainerReader* reader_;
+  ContainerEntryType type_ = ContainerEntryType::kResTable;
+  size_t length_ = 0u;
+};
+
+class ContainerReader {
+ public:
+  explicit ContainerReader(io::InputStream* in);
+
+  ContainerReaderEntry* Next();
+
+  bool HadError() const;
+  std::string GetError() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ContainerReader);
+
+  friend class ContainerReaderEntry;
+
+  io::InputStream* in_;
+  io::ZeroCopyInputAdaptor adaptor_;
+  ::google::protobuf::io::CodedInputStream coded_in_;
+  size_t total_entry_count_;
+  size_t current_entry_count_;
+  ContainerReaderEntry entry_;
+  std::string error_;
+};
+
+}  // namespace aapt
+
+#endif /* AAPT_FORMAT_CONTAINER_H */
diff --git a/tools/aapt2/format/Container_test.cpp b/tools/aapt2/format/Container_test.cpp
new file mode 100644
index 0000000..dc81a3a
--- /dev/null
+++ b/tools/aapt2/format/Container_test.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "format/Container.h"
+
+#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
+
+#include "io/StringStream.h"
+#include "test/Test.h"
+
+using ::google::protobuf::io::StringOutputStream;
+using ::testing::Eq;
+using ::testing::IsEmpty;
+using ::testing::IsNull;
+using ::testing::NotNull;
+using ::testing::StrEq;
+
+namespace aapt {
+
+TEST(ContainerTest, SerializeCompiledFile) {
+  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+  const std::string expected_data = "123";
+
+  std::string output_str;
+  {
+    StringOutputStream out_stream(&output_str);
+    ContainerWriter writer(&out_stream, 2u);
+    ASSERT_FALSE(writer.HadError());
+
+    pb::internal::CompiledFile pb_compiled_file;
+    pb_compiled_file.set_resource_name("android:layout/main.xml");
+    pb_compiled_file.set_type(pb::FileReference::PROTO_XML);
+    pb_compiled_file.set_source_path("res/layout/main.xml");
+    io::StringInputStream data(expected_data);
+    ASSERT_TRUE(writer.AddResFileEntry(pb_compiled_file, &data));
+
+    pb::ResourceTable pb_table;
+    pb::Package* pb_pkg = pb_table.add_package();
+    pb_pkg->set_package_name("android");
+    pb_pkg->mutable_package_id()->set_id(0x01u);
+    ASSERT_TRUE(writer.AddResTableEntry(pb_table));
+
+    ASSERT_FALSE(writer.HadError());
+  }
+
+  io::StringInputStream input(output_str);
+  ContainerReader reader(&input);
+  ASSERT_FALSE(reader.HadError());
+
+  ContainerReaderEntry* entry = reader.Next();
+  ASSERT_THAT(entry, NotNull());
+  ASSERT_THAT(entry->Type(), Eq(ContainerEntryType::kResFile));
+
+  pb::internal::CompiledFile pb_new_file;
+  off64_t offset;
+  size_t len;
+  ASSERT_TRUE(entry->GetResFileOffsets(&pb_new_file, &offset, &len)) << entry->GetError();
+  EXPECT_THAT(offset & 0x03, Eq(0u));
+  EXPECT_THAT(output_str.substr(static_cast<size_t>(offset), len), StrEq(expected_data));
+
+  entry = reader.Next();
+  ASSERT_THAT(entry, NotNull());
+  ASSERT_THAT(entry->Type(), Eq(ContainerEntryType::kResTable));
+
+  pb::ResourceTable pb_new_table;
+  ASSERT_TRUE(entry->GetResTable(&pb_new_table));
+  ASSERT_THAT(pb_new_table.package_size(), Eq(1));
+  EXPECT_THAT(pb_new_table.package(0).package_name(), StrEq("android"));
+  EXPECT_THAT(pb_new_table.package(0).package_id().id(), Eq(0x01u));
+
+  EXPECT_THAT(reader.Next(), IsNull());
+  EXPECT_FALSE(reader.HadError());
+  EXPECT_THAT(reader.GetError(), IsEmpty());
+}
+
+}  // namespace aapt
diff --git a/tools/aapt2/format/binary/XmlFlattener.cpp b/tools/aapt2/format/binary/XmlFlattener.cpp
index f8f09ab..345cc95 100644
--- a/tools/aapt2/format/binary/XmlFlattener.cpp
+++ b/tools/aapt2/format/binary/XmlFlattener.cpp
@@ -56,9 +56,9 @@
   return false;
 }
 
-class XmlFlattenerVisitor : public xml::Visitor {
+class XmlFlattenerVisitor : public xml::ConstVisitor {
  public:
-  using xml::Visitor::Visit;
+  using xml::ConstVisitor::Visit;
 
   StringPool pool;
   std::map<uint8_t, StringPool> package_pools;
@@ -74,7 +74,7 @@
       : buffer_(buffer), options_(options) {
   }
 
-  void Visit(xml::Text* node) override {
+  void Visit(const xml::Text* node) override {
     if (util::TrimWhitespace(node->text).empty()) {
       // Skip whitespace only text nodes.
       return;
@@ -95,7 +95,7 @@
     writer.Finish();
   }
 
-  void Visit(xml::Element* node) override {
+  void Visit(const xml::Element* node) override {
     for (const xml::NamespaceDecl& decl : node->namespace_decls) {
       // Skip dedicated tools namespace.
       if (decl.uri != xml::kSchemaTools) {
@@ -125,7 +125,7 @@
       start_writer.Finish();
     }
 
-    xml::Visitor::Visit(node);
+    xml::ConstVisitor::Visit(node);
 
     {
       ChunkWriter end_writer(buffer_);
@@ -182,12 +182,13 @@
     writer.Finish();
   }
 
-  void WriteAttributes(xml::Element* node, ResXMLTree_attrExt* flat_elem, ChunkWriter* writer) {
+  void WriteAttributes(const xml::Element* node, ResXMLTree_attrExt* flat_elem,
+                       ChunkWriter* writer) {
     filtered_attrs_.clear();
     filtered_attrs_.reserve(node->attributes.size());
 
     // Filter the attributes.
-    for (xml::Attribute& attr : node->attributes) {
+    for (const xml::Attribute& attr : node->attributes) {
       if (attr.namespace_uri != xml::kSchemaTools) {
         filtered_attrs_.push_back(&attr);
       }
@@ -282,12 +283,12 @@
   XmlFlattenerOptions options_;
 
   // Scratch vector to filter attributes. We avoid allocations making this a member.
-  std::vector<xml::Attribute*> filtered_attrs_;
+  std::vector<const xml::Attribute*> filtered_attrs_;
 };
 
 }  // namespace
 
-bool XmlFlattener::Flatten(IAaptContext* context, xml::Node* node) {
+bool XmlFlattener::Flatten(IAaptContext* context, const xml::Node* node) {
   BigBuffer node_buffer(1024);
   XmlFlattenerVisitor visitor(&node_buffer, options_);
   node->Accept(&visitor);
@@ -312,7 +313,11 @@
   xml_header_writer.StartChunk<ResXMLTree_header>(RES_XML_TYPE);
 
   // Flatten the StringPool.
-  StringPool::FlattenUtf8(buffer_, visitor.pool);
+  if (options_.use_utf16) {
+    StringPool::FlattenUtf16(buffer_, visitor.pool);
+  } else {
+    StringPool::FlattenUtf8(buffer_, visitor.pool);
+  }
 
   {
     // Write the array of resource IDs, indexed by StringPool order.
@@ -337,7 +342,7 @@
   return true;
 }
 
-bool XmlFlattener::Consume(IAaptContext* context, xml::XmlResource* resource) {
+bool XmlFlattener::Consume(IAaptContext* context, const xml::XmlResource* resource) {
   if (!resource->root) {
     return false;
   }
diff --git a/tools/aapt2/format/binary/XmlFlattener.h b/tools/aapt2/format/binary/XmlFlattener.h
index 6a48835..1f9e777 100644
--- a/tools/aapt2/format/binary/XmlFlattener.h
+++ b/tools/aapt2/format/binary/XmlFlattener.h
@@ -28,20 +28,24 @@
 struct XmlFlattenerOptions {
   // Keep attribute raw string values along with typed values.
   bool keep_raw_values = false;
+
+  // Encode the strings in UTF-16. Only needed for AndroidManifest.xml to avoid a bug in
+  // certain non-AOSP platforms: https://issuetracker.google.com/64434571
+  bool use_utf16 = false;
 };
 
-class XmlFlattener : public IXmlResourceConsumer {
+class XmlFlattener {
  public:
   XmlFlattener(BigBuffer* buffer, XmlFlattenerOptions options)
       : buffer_(buffer), options_(options) {
   }
 
-  bool Consume(IAaptContext* context, xml::XmlResource* resource) override;
+  bool Consume(IAaptContext* context, const xml::XmlResource* resource);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(XmlFlattener);
 
-  bool Flatten(IAaptContext* context, xml::Node* node);
+  bool Flatten(IAaptContext* context, const xml::Node* node);
 
   BigBuffer* buffer_;
   XmlFlattenerOptions options_;
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index c14f09a..86bd865 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -26,7 +26,6 @@
 #include "ValueVisitor.h"
 
 using ::android::ResStringPool;
-using ::google::protobuf::io::CodedInputStream;
 
 namespace aapt {
 
@@ -391,8 +390,15 @@
     }
 
     ResourceTableType* type = pkg->FindOrCreateType(*res_type);
+    if (pb_type.has_type_id()) {
+      type->id = static_cast<uint8_t>(pb_type.type_id().id());
+    }
+
     for (const pb::Entry& pb_entry : pb_type.entry()) {
       ResourceEntry* entry = type->FindOrCreateEntry(pb_entry.name());
+      if (pb_entry.has_entry_id()) {
+        entry->id = static_cast<uint16_t>(pb_entry.entry_id().id());
+      }
 
       // Deserialize the symbol status (public/private with source and comments).
       if (pb_entry.has_symbol_status()) {
@@ -406,21 +412,11 @@
 
         const SymbolState visibility = DeserializeVisibilityFromPb(pb_status.visibility());
         entry->symbol_status.state = visibility;
-
         if (visibility == SymbolState::kPublic) {
-          // This is a public symbol, we must encode the ID now if there is one.
-          if (pb_entry.has_entry_id()) {
-            entry->id = static_cast<uint16_t>(pb_entry.entry_id().id());
-          }
-
-          if (type->symbol_status.state != SymbolState::kPublic) {
-            // If the type has not been made public, do so now.
-            type->symbol_status.state = SymbolState::kPublic;
-            if (pb_type.has_type_id()) {
-              type->id = static_cast<uint8_t>(pb_type.type_id().id());
-            }
-          }
+          // Propagate the public visibility up to the Type.
+          type->symbol_status.state = SymbolState::kPublic;
         } else if (visibility == SymbolState::kPrivate) {
+          // Only propagate if no previous state was assigned.
           if (type->symbol_status.state == SymbolState::kUndefined) {
             type->symbol_status.state = SymbolState::kPrivate;
           }
@@ -485,6 +481,19 @@
   return true;
 }
 
+static ResourceFile::Type DeserializeFileReferenceTypeFromPb(const pb::FileReference::Type& type) {
+  switch (type) {
+    case pb::FileReference::BINARY_XML:
+      return ResourceFile::Type::kBinaryXml;
+    case pb::FileReference::PROTO_XML:
+      return ResourceFile::Type::kProtoXml;
+    case pb::FileReference::PNG:
+      return ResourceFile::Type::kPng;
+    default:
+      return ResourceFile::Type::kUnknown;
+  }
+}
+
 bool DeserializeCompiledFileFromPb(const pb::internal::CompiledFile& pb_file,
                                    ResourceFile* out_file, std::string* out_error) {
   ResourceNameRef name_ref;
@@ -497,6 +506,7 @@
 
   out_file->name = name_ref.ToResourceName();
   out_file->source.path = pb_file.source_path();
+  out_file->type = DeserializeFileReferenceTypeFromPb(pb_file.type());
 
   std::string config_error;
   if (!DeserializeConfigFromPb(pb_file.config(), &out_file->config, &config_error)) {
@@ -759,8 +769,12 @@
     } break;
 
     case pb::Item::kFile: {
-      return util::make_unique<FileReference>(value_pool->MakeRef(
-          pb_item.file().path(), StringPool::Context(StringPool::Context::kHighPriority, config)));
+      const pb::FileReference& pb_file = pb_item.file();
+      std::unique_ptr<FileReference> file_ref =
+          util::make_unique<FileReference>(value_pool->MakeRef(
+              pb_file.path(), StringPool::Context(StringPool::Context::kHighPriority, config)));
+      file_ref->type = DeserializeFileReferenceTypeFromPb(pb_file.type());
+      return std::move(file_ref);
     } break;
 
     default:
@@ -847,72 +861,4 @@
   return true;
 }
 
-CompiledFileInputStream::CompiledFileInputStream(const void* data, size_t size)
-    : in_(static_cast<const uint8_t*>(data), size) {
-}
-
-void CompiledFileInputStream::EnsureAlignedRead() {
-  const int overflow = in_.CurrentPosition() % 4;
-  if (overflow > 0) {
-    // Reads are always 4 byte aligned.
-    in_.Skip(4 - overflow);
-  }
-}
-
-bool CompiledFileInputStream::ReadLittleEndian32(uint32_t* out_val) {
-  EnsureAlignedRead();
-  return in_.ReadLittleEndian32(out_val);
-}
-
-bool CompiledFileInputStream::ReadCompiledFile(pb::internal::CompiledFile* out_val) {
-  EnsureAlignedRead();
-
-  google::protobuf::uint64 pb_size = 0u;
-  if (!in_.ReadLittleEndian64(&pb_size)) {
-    return false;
-  }
-
-  CodedInputStream::Limit l = in_.PushLimit(static_cast<int>(pb_size));
-
-  // Check that we haven't tried to read past the end.
-  if (static_cast<uint64_t>(in_.BytesUntilLimit()) != pb_size) {
-    in_.PopLimit(l);
-    in_.PushLimit(0);
-    return false;
-  }
-
-  if (!out_val->ParsePartialFromCodedStream(&in_)) {
-    in_.PopLimit(l);
-    in_.PushLimit(0);
-    return false;
-  }
-
-  in_.PopLimit(l);
-  return true;
-}
-
-bool CompiledFileInputStream::ReadDataMetaData(uint64_t* out_offset, uint64_t* out_len) {
-  EnsureAlignedRead();
-
-  google::protobuf::uint64 pb_size = 0u;
-  if (!in_.ReadLittleEndian64(&pb_size)) {
-    return false;
-  }
-
-  // Check that we aren't trying to read past the end.
-  if (pb_size > static_cast<uint64_t>(in_.BytesUntilLimit())) {
-    in_.PushLimit(0);
-    return false;
-  }
-
-  uint64_t offset = static_cast<uint64_t>(in_.CurrentPosition());
-  if (!in_.Skip(pb_size)) {
-    return false;
-  }
-
-  *out_offset = offset;
-  *out_len = pb_size;
-  return true;
-}
-
 }  // namespace aapt
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.h b/tools/aapt2/format/proto/ProtoDeserialize.h
index c8a7199..7dc54f2 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.h
+++ b/tools/aapt2/format/proto/ProtoDeserialize.h
@@ -19,7 +19,6 @@
 
 #include "android-base/macros.h"
 #include "androidfw/ResourceTypes.h"
-#include "google/protobuf/io/coded_stream.h"
 
 #include "ConfigDescription.h"
 #include "Configuration.pb.h"
@@ -57,22 +56,6 @@
 bool DeserializeCompiledFileFromPb(const pb::internal::CompiledFile& pb_file,
                                    ResourceFile* out_file, std::string* out_error);
 
-class CompiledFileInputStream {
- public:
-  explicit CompiledFileInputStream(const void* data, size_t size);
-
-  bool ReadLittleEndian32(uint32_t* outVal);
-  bool ReadCompiledFile(pb::internal::CompiledFile* outVal);
-  bool ReadDataMetaData(uint64_t* outOffset, uint64_t* outLen);
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(CompiledFileInputStream);
-
-  void EnsureAlignedRead();
-
-  ::google::protobuf::io::CodedInputStream in_;
-};
-
 }  // namespace aapt
 
 #endif /* AAPT_FORMAT_PROTO_PROTODESERIALIZE_H */
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index c0d3614..1d184fe 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -16,14 +16,9 @@
 
 #include "format/proto/ProtoSerialize.h"
 
-#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
-
 #include "ValueVisitor.h"
 #include "util/BigBuffer.h"
 
-using ::google::protobuf::io::CodedOutputStream;
-using ::google::protobuf::io::ZeroCopyOutputStream;
-
 namespace aapt {
 
 void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool) {
@@ -366,6 +361,19 @@
   return pb::Plural_Arity_OTHER;
 }
 
+static pb::FileReference::Type SerializeFileReferenceTypeToPb(const ResourceFile::Type& type) {
+  switch (type) {
+    case ResourceFile::Type::kBinaryXml:
+      return pb::FileReference::BINARY_XML;
+    case ResourceFile::Type::kProtoXml:
+      return pb::FileReference::PROTO_XML;
+    case ResourceFile::Type::kPng:
+      return pb::FileReference::PNG;
+    default:
+      return pb::FileReference::UNKNOWN;
+  }
+}
+
 namespace {
 
 class ValueSerializer : public ConstValueVisitor {
@@ -400,7 +408,9 @@
   }
 
   void Visit(const FileReference* file) override {
-    out_value_->mutable_item()->mutable_file()->set_path(*file->path);
+    pb::FileReference* pb_file = out_value_->mutable_item()->mutable_file();
+    pb_file->set_path(*file->path);
+    pb_file->set_type(SerializeFileReferenceTypeToPb(file->type));
   }
 
   void Visit(const Id* /*id*/) override {
@@ -515,6 +525,7 @@
 void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file) {
   out_file->set_resource_name(file.name.ToString());
   out_file->set_source_path(file.source.path);
+  out_file->set_type(SerializeFileReferenceTypeToPb(file.type));
   SerializeConfig(file.config, out_file->mutable_config());
 
   for (const SourcedResourceName& exported : file.exported_symbols) {
@@ -579,44 +590,4 @@
   SerializeXmlToPb(*resource.root, out_node);
 }
 
-CompiledFileOutputStream::CompiledFileOutputStream(ZeroCopyOutputStream* out) : out_(out) {
-}
-
-void CompiledFileOutputStream::EnsureAlignedWrite() {
-  const int overflow = out_.ByteCount() % 4;
-  if (overflow > 0) {
-    uint32_t zero = 0u;
-    out_.WriteRaw(&zero, 4 - overflow);
-  }
-}
-
-void CompiledFileOutputStream::WriteLittleEndian32(uint32_t val) {
-  EnsureAlignedWrite();
-  out_.WriteLittleEndian32(val);
-}
-
-void CompiledFileOutputStream::WriteCompiledFile(const pb::internal::CompiledFile& compiled_file) {
-  EnsureAlignedWrite();
-  out_.WriteLittleEndian64(static_cast<uint64_t>(compiled_file.ByteSize()));
-  compiled_file.SerializeWithCachedSizes(&out_);
-}
-
-void CompiledFileOutputStream::WriteData(const BigBuffer& buffer) {
-  EnsureAlignedWrite();
-  out_.WriteLittleEndian64(static_cast<uint64_t>(buffer.size()));
-  for (const BigBuffer::Block& block : buffer) {
-    out_.WriteRaw(block.buffer.get(), block.size);
-  }
-}
-
-void CompiledFileOutputStream::WriteData(const void* data, size_t len) {
-  EnsureAlignedWrite();
-  out_.WriteLittleEndian64(static_cast<uint64_t>(len));
-  out_.WriteRaw(data, len);
-}
-
-bool CompiledFileOutputStream::HadError() {
-  return out_.HadError();
-}
-
 }  // namespace aapt
diff --git a/tools/aapt2/format/proto/ProtoSerialize.h b/tools/aapt2/format/proto/ProtoSerialize.h
index 1694b16..95dd413 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.h
+++ b/tools/aapt2/format/proto/ProtoSerialize.h
@@ -18,7 +18,6 @@
 #define AAPT_FORMAT_PROTO_PROTOSERIALIZE_H
 
 #include "android-base/macros.h"
-#include "google/protobuf/io/coded_stream.h"
 
 #include "ConfigDescription.h"
 #include "Configuration.pb.h"
@@ -29,14 +28,6 @@
 #include "StringPool.h"
 #include "xml/XmlDom.h"
 
-namespace google {
-namespace protobuf {
-namespace io {
-class ZeroCopyOutputStream;
-}  // namespace io
-}  // namespace protobuf
-}  // namespace google
-
 namespace aapt {
 
 // Serializes a Value to its protobuf representation. An optional StringPool will hold the
@@ -66,24 +57,6 @@
 // Serializes a ResourceFile into its protobuf representation.
 void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file);
 
-class CompiledFileOutputStream {
- public:
-  explicit CompiledFileOutputStream(::google::protobuf::io::ZeroCopyOutputStream* out);
-
-  void WriteLittleEndian32(uint32_t value);
-  void WriteCompiledFile(const pb::internal::CompiledFile& compiledFile);
-  void WriteData(const BigBuffer& buffer);
-  void WriteData(const void* data, size_t len);
-  bool HadError();
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(CompiledFileOutputStream);
-
-  void EnsureAlignedWrite();
-
-  ::google::protobuf::io::CodedOutputStream out_;
-};
-
 }  // namespace aapt
 
 #endif /* AAPT_FORMAT_PROTO_PROTOSERIALIZE_H */
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index 2154d5a..8efac8a 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -16,14 +16,11 @@
 
 #include "format/proto/ProtoSerialize.h"
 
-#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
-
 #include "ResourceUtils.h"
 #include "format/proto/ProtoDeserialize.h"
 #include "test/Test.h"
 
 using ::android::StringPiece;
-using ::google::protobuf::io::StringOutputStream;
 using ::testing::Eq;
 using ::testing::IsEmpty;
 using ::testing::NotNull;
@@ -137,113 +134,6 @@
   EXPECT_THAT(actual_styled_str->value->spans[0].last_char, Eq(4u));
 }
 
-TEST(ProtoSerializeTest, SerializeFileHeader) {
-  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
-
-  ResourceFile f;
-  f.config = test::ParseConfigOrDie("hdpi-v9");
-  f.name = test::ParseNameOrDie("com.app.a:layout/main");
-  f.source.path = "res/layout-hdpi-v9/main.xml";
-  f.exported_symbols.push_back(SourcedResourceName{test::ParseNameOrDie("id/unchecked"), 23u});
-
-  const std::string expected_data1 = "123";
-  const std::string expected_data2 = "1234";
-
-  std::string output_str;
-  {
-    pb::internal::CompiledFile pb_f1, pb_f2;
-    SerializeCompiledFileToPb(f, &pb_f1);
-
-    f.name.entry = "__" + f.name.entry + "$0";
-    SerializeCompiledFileToPb(f, &pb_f2);
-
-    StringOutputStream out_stream(&output_str);
-    CompiledFileOutputStream out_file_stream(&out_stream);
-    out_file_stream.WriteLittleEndian32(2);
-    out_file_stream.WriteCompiledFile(pb_f1);
-    out_file_stream.WriteData(expected_data1.data(), expected_data1.size());
-    out_file_stream.WriteCompiledFile(pb_f2);
-    out_file_stream.WriteData(expected_data2.data(), expected_data2.size());
-    ASSERT_FALSE(out_file_stream.HadError());
-  }
-
-  CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
-  uint32_t num_files = 0;
-  ASSERT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
-  ASSERT_EQ(2u, num_files);
-
-  // Read the first compiled file.
-
-  pb::internal::CompiledFile new_pb_f1;
-  ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_f1));
-
-  ResourceFile new_f1;
-  std::string error;
-  ASSERT_TRUE(DeserializeCompiledFileFromPb(new_pb_f1, &new_f1, &error));
-  EXPECT_THAT(error, IsEmpty());
-
-  uint64_t offset, len;
-  ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
-
-  std::string actual_data(output_str.data() + offset, len);
-  EXPECT_EQ(expected_data1, actual_data);
-
-  // Expect the data to be aligned.
-  EXPECT_EQ(0u, offset & 0x03);
-
-  ASSERT_EQ(1u, new_f1.exported_symbols.size());
-  EXPECT_EQ(test::ParseNameOrDie("id/unchecked"), new_f1.exported_symbols[0].name);
-
-  // Read the second compiled file.
-
-  pb::internal::CompiledFile new_pb_f2;
-  ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_f2));
-
-  ResourceFile new_f2;
-  ASSERT_TRUE(DeserializeCompiledFileFromPb(new_pb_f2, &new_f2, &error));
-  EXPECT_THAT(error, IsEmpty());
-
-  ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
-
-  actual_data = std::string(output_str.data() + offset, len);
-  EXPECT_EQ(expected_data2, actual_data);
-
-  // Expect the data to be aligned.
-  EXPECT_EQ(0u, offset & 0x03);
-}
-
-TEST(ProtoSerializeTest, DeserializeCorruptHeaderSafely) {
-  ResourceFile f;
-  pb::internal::CompiledFile pb_file;
-  SerializeCompiledFileToPb(f, &pb_file);
-
-  const std::string expected_data = "1234";
-
-  std::string output_str;
-  {
-    StringOutputStream out_stream(&output_str);
-    CompiledFileOutputStream out_file_stream(&out_stream);
-    out_file_stream.WriteLittleEndian32(1);
-    out_file_stream.WriteCompiledFile(pb_file);
-    out_file_stream.WriteData(expected_data.data(), expected_data.size());
-    ASSERT_FALSE(out_file_stream.HadError());
-  }
-
-  output_str[4] = 0xff;
-
-  CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
-
-  uint32_t num_files = 0;
-  EXPECT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
-  EXPECT_EQ(1u, num_files);
-
-  pb::internal::CompiledFile new_pb_file;
-  EXPECT_FALSE(in_file_stream.ReadCompiledFile(&new_pb_file));
-
-  uint64_t offset, len;
-  EXPECT_FALSE(in_file_stream.ReadDataMetaData(&offset, &len));
-}
-
 TEST(ProtoSerializeTest, SerializeAndDeserializeXml) {
   xml::Element element;
   element.line_number = 22;
diff --git a/tools/aapt2/formats.md b/tools/aapt2/formats.md
new file mode 100644
index 0000000..bb31a00
--- /dev/null
+++ b/tools/aapt2/formats.md
@@ -0,0 +1,44 @@
+# AAPT2 On-Disk Formats
+- AAPT2 Container Format (extension `.apc`)
+- AAPT2 Static Library Format (extension `.sapk`)
+
+## AAPT2 Container Format (extension `.apc`)
+The APC format (AAPT2 Container Format) is generated by AAPT2 during the compile phase and
+consumed by the AAPT2 link phase. It is a simple container format for storing compiled PNGs,
+binary and protobuf XML, and intermediate protobuf resource tables. It also stores all associated
+meta-data from the compile phase.
+
+### Format
+The file starts with a simple header. All multi-byte fields are little-endian.
+
+| Size (in bytes) | Field         | Description                                          |
+|:----------------|:--------------|:-----------------------------------------------------|
+| `4`             | `magic`       | The magic bytes must equal `'AAPT'` or `0x54504141`. |
+| `4`             | `version`     | The version of the container format.                 |
+| `4`             | `entry_count` | The number of entries in this container.             |
+
+This is followed by `entry_count` of the following data structure. It must be aligned on a 32-bit
+boundary, so if a previous entry ends unaligned, padding must be inserted.
+
+| Size (in bytes) | Field          | Description                                                                                               |
+|:----------------|:---------------|:----------------------------------------------------------------------------------------------------------|
+| `4`             | `entry_type`   | The type of the entry. This can be one of two types: `RES_TABLE (0x00000000)` or `RES_FILE (0x00000001)`. |
+| `8`             | `entry_length` | The length of the data that follows.                                                                      |
+| `entry_length`  | `data`         | The payload. The contents of this varies based on the `entry_type`.                                       |
+
+If the `entry_type` is equal to `RES_TABLE (0x00000000)`, the `data` field contains a serialized
+[aapt.pb.ResourceTable](Resources.proto).
+
+If the `entry_type` is equal to `RES_FILE (0x00000001)`, the `data` field contains the following:
+
+
+| Size (in bytes) | Field          | Description                                                                                               |
+|:----------------|:---------------|:----------------------------------------------------------------------------------------------------------|
+| `4`             | `header_size`  | The size of the `header` field.                                                                 |
+| `8`             | `data_size`    | The size of the `data` field.                                                                   |
+| `header_size`   | `header`       | The serialized Protobuf message [aapt.pb.internal.CompiledFile](ResourcesInternal.proto).       |
+| `x`             | `padding`      | Up to 4 bytes of zeros, if padding is necessary to align the `data` field on a 32-bit boundary. |
+| `data_size`     | `data`         | The payload, which is determined by the `type` field in the `aapt.pb.internal.CompiledFile`. This can be a PNG file, binary XML, or [aapt.pb.XmlNode](Resources.proto). |
+
+## AAPT2 Static Library Format (extension `.sapk`)
+
diff --git a/tools/aapt2/io/BigBufferInputStream.h b/tools/aapt2/io/BigBufferInputStream.h
deleted file mode 100644
index 92612c7..0000000
--- a/tools/aapt2/io/BigBufferInputStream.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AAPT_IO_BIGBUFFERINPUTSTREAM_H
-#define AAPT_IO_BIGBUFFERINPUTSTREAM_H
-
-#include "io/Io.h"
-#include "util/BigBuffer.h"
-
-namespace aapt {
-namespace io {
-
-class BigBufferInputStream : public InputStream {
- public:
-  inline explicit BigBufferInputStream(const BigBuffer* buffer)
-      : buffer_(buffer), iter_(buffer->begin()) {}
-  virtual ~BigBufferInputStream() = default;
-
-  bool Next(const void** data, size_t* size) override;
-
-  void BackUp(size_t count) override;
-
-  bool CanRewind() const override;
-
-  bool Rewind() override;
-
-  size_t ByteCount() const override;
-
-  bool HadError() const override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(BigBufferInputStream);
-
-  const BigBuffer* buffer_;
-  BigBuffer::const_iterator iter_;
-  size_t offset_ = 0;
-  size_t bytes_read_ = 0;
-};
-
-}  // namespace io
-}  // namespace aapt
-
-#endif  // AAPT_IO_BIGBUFFERINPUTSTREAM_H
diff --git a/tools/aapt2/io/BigBufferOutputStream.h b/tools/aapt2/io/BigBufferOutputStream.h
deleted file mode 100644
index 95113bc..0000000
--- a/tools/aapt2/io/BigBufferOutputStream.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AAPT_IO_BIGBUFFEROUTPUTSTREAM_H
-#define AAPT_IO_BIGBUFFEROUTPUTSTREAM_H
-
-#include "io/Io.h"
-#include "util/BigBuffer.h"
-
-namespace aapt {
-namespace io {
-
-class BigBufferOutputStream : public OutputStream {
- public:
-  inline explicit BigBufferOutputStream(BigBuffer* buffer) : buffer_(buffer) {}
-  virtual ~BigBufferOutputStream() = default;
-
-  bool Next(void** data, size_t* size) override;
-
-  void BackUp(size_t count) override;
-
-  size_t ByteCount() const override;
-
-  bool HadError() const override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(BigBufferOutputStream);
-
-  BigBuffer* buffer_;
-};
-
-}  // namespace io
-}  // namespace aapt
-
-#endif  // AAPT_IO_BIGBUFFEROUTPUTSTREAM_H
diff --git a/tools/aapt2/io/BigBufferStream.cpp b/tools/aapt2/io/BigBufferStream.cpp
new file mode 100644
index 0000000..9704caa
--- /dev/null
+++ b/tools/aapt2/io/BigBufferStream.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "io/BigBufferStream.h"
+
+namespace aapt {
+namespace io {
+
+//
+// BigBufferInputStream
+//
+
+bool BigBufferInputStream::Next(const void** data, size_t* size) {
+  if (iter_ == buffer_->end()) {
+    return false;
+  }
+
+  if (offset_ == iter_->size) {
+    ++iter_;
+    if (iter_ == buffer_->end()) {
+      return false;
+    }
+    offset_ = 0;
+  }
+
+  *data = iter_->buffer.get() + offset_;
+  *size = iter_->size - offset_;
+  bytes_read_ += iter_->size - offset_;
+  offset_ = iter_->size;
+  return true;
+}
+
+void BigBufferInputStream::BackUp(size_t count) {
+  if (count > offset_) {
+    bytes_read_ -= offset_;
+    offset_ = 0;
+  } else {
+    offset_ -= count;
+    bytes_read_ -= count;
+  }
+}
+
+bool BigBufferInputStream::CanRewind() const {
+  return true;
+}
+
+bool BigBufferInputStream::Rewind() {
+  iter_ = buffer_->begin();
+  offset_ = 0;
+  bytes_read_ = 0;
+  return true;
+}
+
+size_t BigBufferInputStream::ByteCount() const {
+  return bytes_read_;
+}
+
+bool BigBufferInputStream::HadError() const {
+  return false;
+}
+
+size_t BigBufferInputStream::TotalSize() const {
+  return buffer_->size();
+}
+
+//
+// BigBufferOutputStream
+//
+
+bool BigBufferOutputStream::Next(void** data, size_t* size) {
+  *data = buffer_->NextBlock(size);
+  return true;
+}
+
+void BigBufferOutputStream::BackUp(size_t count) {
+  buffer_->BackUp(count);
+}
+
+size_t BigBufferOutputStream::ByteCount() const {
+  return buffer_->size();
+}
+
+bool BigBufferOutputStream::HadError() const {
+  return false;
+}
+
+}  // namespace io
+}  // namespace aapt
diff --git a/tools/aapt2/io/BigBufferStream.h b/tools/aapt2/io/BigBufferStream.h
new file mode 100644
index 0000000..8b5c8b8
--- /dev/null
+++ b/tools/aapt2/io/BigBufferStream.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_IO_BIGBUFFERSTREAM_H
+#define AAPT_IO_BIGBUFFERSTREAM_H
+
+#include "io/Io.h"
+#include "util/BigBuffer.h"
+
+namespace aapt {
+namespace io {
+
+class BigBufferInputStream : public KnownSizeInputStream {
+ public:
+  inline explicit BigBufferInputStream(const BigBuffer* buffer)
+      : buffer_(buffer), iter_(buffer->begin()) {
+  }
+  virtual ~BigBufferInputStream() = default;
+
+  bool Next(const void** data, size_t* size) override;
+
+  void BackUp(size_t count) override;
+
+  bool CanRewind() const override;
+
+  bool Rewind() override;
+
+  size_t ByteCount() const override;
+
+  bool HadError() const override;
+
+  size_t TotalSize() const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BigBufferInputStream);
+
+  const BigBuffer* buffer_;
+  BigBuffer::const_iterator iter_;
+  size_t offset_ = 0;
+  size_t bytes_read_ = 0;
+};
+
+class BigBufferOutputStream : public OutputStream {
+ public:
+  inline explicit BigBufferOutputStream(BigBuffer* buffer) : buffer_(buffer) {
+  }
+  virtual ~BigBufferOutputStream() = default;
+
+  bool Next(void** data, size_t* size) override;
+
+  void BackUp(size_t count) override;
+
+  size_t ByteCount() const override;
+
+  bool HadError() const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BigBufferOutputStream);
+
+  BigBuffer* buffer_;
+};
+
+}  // namespace io
+}  // namespace aapt
+
+#endif  // AAPT_IO_BIGBUFFERSTREAM_H
diff --git a/tools/aapt2/io/BigBufferStreams.cpp b/tools/aapt2/io/BigBufferStreams.cpp
deleted file mode 100644
index eb99033..0000000
--- a/tools/aapt2/io/BigBufferStreams.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "io/BigBufferInputStream.h"
-#include "io/BigBufferOutputStream.h"
-
-namespace aapt {
-namespace io {
-
-//
-// BigBufferInputStream
-//
-
-bool BigBufferInputStream::Next(const void** data, size_t* size) {
-  if (iter_ == buffer_->end()) {
-    return false;
-  }
-
-  if (offset_ == iter_->size) {
-    ++iter_;
-    if (iter_ == buffer_->end()) {
-      return false;
-    }
-    offset_ = 0;
-  }
-
-  *data = iter_->buffer.get() + offset_;
-  *size = iter_->size - offset_;
-  bytes_read_ += iter_->size - offset_;
-  offset_ = iter_->size;
-  return true;
-}
-
-void BigBufferInputStream::BackUp(size_t count) {
-  if (count > offset_) {
-    bytes_read_ -= offset_;
-    offset_ = 0;
-  } else {
-    offset_ -= count;
-    bytes_read_ -= count;
-  }
-}
-
-bool BigBufferInputStream::CanRewind() const { return true; }
-
-bool BigBufferInputStream::Rewind() {
-  iter_ = buffer_->begin();
-  offset_ = 0;
-  bytes_read_ = 0;
-  return true;
-}
-
-size_t BigBufferInputStream::ByteCount() const { return bytes_read_; }
-
-bool BigBufferInputStream::HadError() const { return false; }
-
-//
-// BigBufferOutputStream
-//
-
-bool BigBufferOutputStream::Next(void** data, size_t* size) {
-  *data = buffer_->NextBlock(size);
-  return true;
-}
-
-void BigBufferOutputStream::BackUp(size_t count) { buffer_->BackUp(count); }
-
-size_t BigBufferOutputStream::ByteCount() const { return buffer_->size(); }
-
-bool BigBufferOutputStream::HadError() const { return false; }
-
-}  // namespace io
-}  // namespace aapt
diff --git a/tools/aapt2/io/Data.h b/tools/aapt2/io/Data.h
index 09dc7ea..db91a77 100644
--- a/tools/aapt2/io/Data.h
+++ b/tools/aapt2/io/Data.h
@@ -28,12 +28,16 @@
 namespace io {
 
 // Interface for a block of contiguous memory. An instance of this interface owns the data.
-class IData : public InputStream {
+class IData : public KnownSizeInputStream {
  public:
   virtual ~IData() = default;
 
   virtual const void* data() const = 0;
   virtual size_t size() const = 0;
+
+  virtual size_t TotalSize() const override {
+    return size();
+  }
 };
 
 class DataSegment : public IData {
diff --git a/tools/aapt2/io/File.cpp b/tools/aapt2/io/File.cpp
index ee73728..b4f1ff3 100644
--- a/tools/aapt2/io/File.cpp
+++ b/tools/aapt2/io/File.cpp
@@ -39,5 +39,9 @@
   return {};
 }
 
+std::unique_ptr<io::InputStream> FileSegment::OpenInputStream() {
+  return OpenAsData();
+}
+
 }  // namespace io
 }  // namespace aapt
diff --git a/tools/aapt2/io/File.h b/tools/aapt2/io/File.h
index 7ef6d88..f06e28c 100644
--- a/tools/aapt2/io/File.h
+++ b/tools/aapt2/io/File.h
@@ -43,6 +43,8 @@
   // Returns nullptr on failure.
   virtual std::unique_ptr<IData> OpenAsData() = 0;
 
+  virtual std::unique_ptr<io::InputStream> OpenInputStream() = 0;
+
   // Returns the source of this file. This is for presentation to the user and
   // may not be a valid file system path (for example, it may contain a '@' sign to separate
   // the files within a ZIP archive from the path to the containing ZIP archive.
@@ -71,8 +73,11 @@
       : file_(file), offset_(offset), len_(len) {}
 
   std::unique_ptr<IData> OpenAsData() override;
+  std::unique_ptr<io::InputStream> OpenInputStream() override;
 
-  const Source& GetSource() const override { return file_->GetSource(); }
+  const Source& GetSource() const override {
+    return file_->GetSource();
+  }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(FileSegment);
diff --git a/tools/aapt2/io/FileInputStream.cpp b/tools/aapt2/io/FileInputStream.cpp
deleted file mode 100644
index 07dbb5a..0000000
--- a/tools/aapt2/io/FileInputStream.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "io/FileInputStream.h"
-
-#include <errno.h>   // for errno
-#include <fcntl.h>   // for O_RDONLY
-#include <unistd.h>  // for read
-
-#include "android-base/errors.h"
-#include "android-base/file.h"  // for O_BINARY
-#include "android-base/macros.h"
-#include "android-base/utf8.h"
-
-using ::android::base::SystemErrorCodeToString;
-
-namespace aapt {
-namespace io {
-
-FileInputStream::FileInputStream(const std::string& path, size_t buffer_capacity)
-    : FileInputStream(::android::base::utf8::open(path.c_str(), O_RDONLY | O_BINARY),
-                      buffer_capacity) {
-}
-
-FileInputStream::FileInputStream(int fd, size_t buffer_capacity)
-    : fd_(fd),
-      buffer_capacity_(buffer_capacity),
-      buffer_offset_(0u),
-      buffer_size_(0u),
-      total_byte_count_(0u) {
-  if (fd_ == -1) {
-    error_ = SystemErrorCodeToString(errno);
-  } else {
-    buffer_.reset(new uint8_t[buffer_capacity_]);
-  }
-}
-
-bool FileInputStream::Next(const void** data, size_t* size) {
-  if (HadError()) {
-    return false;
-  }
-
-  // Deal with any remaining bytes after BackUp was called.
-  if (buffer_offset_ != buffer_size_) {
-    *data = buffer_.get() + buffer_offset_;
-    *size = buffer_size_ - buffer_offset_;
-    total_byte_count_ += buffer_size_ - buffer_offset_;
-    buffer_offset_ = buffer_size_;
-    return true;
-  }
-
-  ssize_t n = TEMP_FAILURE_RETRY(read(fd_, buffer_.get(), buffer_capacity_));
-  if (n < 0) {
-    error_ = SystemErrorCodeToString(errno);
-    fd_.reset();
-    return false;
-  }
-
-  buffer_size_ = static_cast<size_t>(n);
-  buffer_offset_ = buffer_size_;
-  total_byte_count_ += buffer_size_;
-
-  *data = buffer_.get();
-  *size = buffer_size_;
-  return buffer_size_ != 0u;
-}
-
-void FileInputStream::BackUp(size_t count) {
-  if (count > buffer_offset_) {
-    count = buffer_offset_;
-  }
-  buffer_offset_ -= count;
-  total_byte_count_ -= count;
-}
-
-size_t FileInputStream::ByteCount() const {
-  return total_byte_count_;
-}
-
-bool FileInputStream::HadError() const {
-  return !error_.empty();
-}
-
-std::string FileInputStream::GetError() const {
-  return error_;
-}
-
-}  // namespace io
-}  // namespace aapt
diff --git a/tools/aapt2/io/FileInputStream.h b/tools/aapt2/io/FileInputStream.h
deleted file mode 100644
index 6beb9a1..0000000
--- a/tools/aapt2/io/FileInputStream.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AAPT_IO_FILEINPUTSTREAM_H
-#define AAPT_IO_FILEINPUTSTREAM_H
-
-#include "io/Io.h"
-
-#include <memory>
-#include <string>
-
-#include "android-base/macros.h"
-#include "android-base/unique_fd.h"
-
-namespace aapt {
-namespace io {
-
-class FileInputStream : public InputStream {
- public:
-  explicit FileInputStream(const std::string& path, size_t buffer_capacity = 4096);
-
-  // Takes ownership of `fd`.
-  explicit FileInputStream(int fd, size_t buffer_capacity = 4096);
-
-  bool Next(const void** data, size_t* size) override;
-
-  void BackUp(size_t count) override;
-
-  size_t ByteCount() const override;
-
-  bool HadError() const override;
-
-  std::string GetError() const override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(FileInputStream);
-
-  android::base::unique_fd fd_;
-  std::string error_;
-  std::unique_ptr<uint8_t[]> buffer_;
-  size_t buffer_capacity_;
-  size_t buffer_offset_;
-  size_t buffer_size_;
-  size_t total_byte_count_;
-};
-
-}  // namespace io
-}  // namespace aapt
-
-#endif  // AAPT_IO_FILEINPUTSTREAM_H
diff --git a/tools/aapt2/io/FileInputStream_test.cpp b/tools/aapt2/io/FileInputStream_test.cpp
deleted file mode 100644
index 7314ab7..0000000
--- a/tools/aapt2/io/FileInputStream_test.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "io/FileInputStream.h"
-
-#include "android-base/macros.h"
-#include "android-base/test_utils.h"
-
-#include "test/Test.h"
-
-using ::android::StringPiece;
-using ::testing::Eq;
-using ::testing::NotNull;
-using ::testing::StrEq;
-
-namespace aapt {
-namespace io {
-
-TEST(FileInputStreamTest, NextAndBackup) {
-  std::string input = "this is a cool string";
-  TemporaryFile file;
-  ASSERT_THAT(TEMP_FAILURE_RETRY(write(file.fd, input.c_str(), input.size())), Eq(21));
-  lseek64(file.fd, 0, SEEK_SET);
-
-  // Use a small buffer size so that we can call Next() a few times.
-  FileInputStream in(file.fd, 10u);
-  ASSERT_FALSE(in.HadError());
-  EXPECT_THAT(in.ByteCount(), Eq(0u));
-
-  const char* buffer;
-  size_t size;
-  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size)) << in.GetError();
-  ASSERT_THAT(size, Eq(10u));
-  ASSERT_THAT(buffer, NotNull());
-  EXPECT_THAT(in.ByteCount(), Eq(10u));
-  EXPECT_THAT(StringPiece(buffer, size), Eq("this is a "));
-
-  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
-  ASSERT_THAT(size, Eq(10u));
-  ASSERT_THAT(buffer, NotNull());
-  EXPECT_THAT(in.ByteCount(), Eq(20u));
-  EXPECT_THAT(StringPiece(buffer, size), Eq("cool strin"));
-
-  in.BackUp(5u);
-  EXPECT_THAT(in.ByteCount(), Eq(15u));
-
-  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
-  ASSERT_THAT(size, Eq(5u));
-  ASSERT_THAT(buffer, NotNull());
-  ASSERT_THAT(in.ByteCount(), Eq(20u));
-  EXPECT_THAT(StringPiece(buffer, size), Eq("strin"));
-
-  // Backup 1 more than possible. Should clamp.
-  in.BackUp(11u);
-  EXPECT_THAT(in.ByteCount(), Eq(10u));
-
-  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
-  ASSERT_THAT(size, Eq(10u));
-  ASSERT_THAT(buffer, NotNull());
-  ASSERT_THAT(in.ByteCount(), Eq(20u));
-  EXPECT_THAT(StringPiece(buffer, size), Eq("cool strin"));
-
-  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
-  ASSERT_THAT(size, Eq(1u));
-  ASSERT_THAT(buffer, NotNull());
-  ASSERT_THAT(in.ByteCount(), Eq(21u));
-  EXPECT_THAT(StringPiece(buffer, size), Eq("g"));
-
-  EXPECT_FALSE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
-  EXPECT_FALSE(in.HadError());
-}
-
-}  // namespace io
-}  // namespace aapt
diff --git a/tools/aapt2/io/FileStream.cpp b/tools/aapt2/io/FileStream.cpp
new file mode 100644
index 0000000..2f7a4b3
--- /dev/null
+++ b/tools/aapt2/io/FileStream.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "io/FileStream.h"
+
+#include <errno.h>   // for errno
+#include <fcntl.h>   // for O_RDONLY
+#include <unistd.h>  // for read
+
+#include "android-base/errors.h"
+#include "android-base/file.h"  // for O_BINARY
+#include "android-base/macros.h"
+#include "android-base/utf8.h"
+
+using ::android::base::SystemErrorCodeToString;
+
+namespace aapt {
+namespace io {
+
+FileInputStream::FileInputStream(const std::string& path, size_t buffer_capacity)
+    : FileInputStream(::android::base::utf8::open(path.c_str(), O_RDONLY | O_BINARY),
+                      buffer_capacity) {
+}
+
+FileInputStream::FileInputStream(int fd, size_t buffer_capacity)
+    : fd_(fd),
+      buffer_capacity_(buffer_capacity),
+      buffer_offset_(0u),
+      buffer_size_(0u),
+      total_byte_count_(0u) {
+  if (fd_ == -1) {
+    error_ = SystemErrorCodeToString(errno);
+  } else {
+    buffer_.reset(new uint8_t[buffer_capacity_]);
+  }
+}
+
+bool FileInputStream::Next(const void** data, size_t* size) {
+  if (HadError()) {
+    return false;
+  }
+
+  // Deal with any remaining bytes after BackUp was called.
+  if (buffer_offset_ != buffer_size_) {
+    *data = buffer_.get() + buffer_offset_;
+    *size = buffer_size_ - buffer_offset_;
+    total_byte_count_ += buffer_size_ - buffer_offset_;
+    buffer_offset_ = buffer_size_;
+    return true;
+  }
+
+  ssize_t n = TEMP_FAILURE_RETRY(read(fd_, buffer_.get(), buffer_capacity_));
+  if (n < 0) {
+    error_ = SystemErrorCodeToString(errno);
+    fd_.reset();
+    buffer_.reset();
+    return false;
+  }
+
+  buffer_size_ = static_cast<size_t>(n);
+  buffer_offset_ = buffer_size_;
+  total_byte_count_ += buffer_size_;
+
+  *data = buffer_.get();
+  *size = buffer_size_;
+  return buffer_size_ != 0u;
+}
+
+void FileInputStream::BackUp(size_t count) {
+  if (count > buffer_offset_) {
+    count = buffer_offset_;
+  }
+  buffer_offset_ -= count;
+  total_byte_count_ -= count;
+}
+
+size_t FileInputStream::ByteCount() const {
+  return total_byte_count_;
+}
+
+bool FileInputStream::HadError() const {
+  return fd_ == -1;
+}
+
+std::string FileInputStream::GetError() const {
+  return error_;
+}
+
+FileOutputStream::FileOutputStream(const std::string& path, int mode, size_t buffer_capacity)
+    : FileOutputStream(::android::base::utf8::open(path.c_str(), mode), buffer_capacity) {
+}
+
+FileOutputStream::FileOutputStream(int fd, size_t buffer_capacity)
+    : fd_(fd), buffer_capacity_(buffer_capacity), buffer_offset_(0u), total_byte_count_(0u) {
+  if (fd_ == -1) {
+    error_ = SystemErrorCodeToString(errno);
+  } else {
+    buffer_.reset(new uint8_t[buffer_capacity_]);
+  }
+}
+
+FileOutputStream::~FileOutputStream() {
+  // Flush the buffer.
+  Flush();
+}
+
+bool FileOutputStream::Next(void** data, size_t* size) {
+  if (fd_ == -1 || HadError()) {
+    return false;
+  }
+
+  if (buffer_offset_ == buffer_capacity_) {
+    if (!FlushImpl()) {
+      return false;
+    }
+  }
+
+  const size_t buffer_size = buffer_capacity_ - buffer_offset_;
+  *data = buffer_.get() + buffer_offset_;
+  *size = buffer_size;
+  total_byte_count_ += buffer_size;
+  buffer_offset_ = buffer_capacity_;
+  return true;
+}
+
+void FileOutputStream::BackUp(size_t count) {
+  if (count > buffer_offset_) {
+    count = buffer_offset_;
+  }
+  buffer_offset_ -= count;
+  total_byte_count_ -= count;
+}
+
+size_t FileOutputStream::ByteCount() const {
+  return total_byte_count_;
+}
+
+bool FileOutputStream::Flush() {
+  if (!HadError()) {
+    return FlushImpl();
+  }
+  return false;
+}
+
+bool FileOutputStream::FlushImpl() {
+  ssize_t n = TEMP_FAILURE_RETRY(write(fd_, buffer_.get(), buffer_offset_));
+  if (n < 0) {
+    error_ = SystemErrorCodeToString(errno);
+    fd_.reset();
+    buffer_.reset();
+    return false;
+  }
+
+  buffer_offset_ = 0u;
+  return true;
+}
+
+bool FileOutputStream::HadError() const {
+  return fd_ == -1;
+}
+
+std::string FileOutputStream::GetError() const {
+  return error_;
+}
+
+}  // namespace io
+}  // namespace aapt
diff --git a/tools/aapt2/io/FileStream.h b/tools/aapt2/io/FileStream.h
new file mode 100644
index 0000000..3b07667
--- /dev/null
+++ b/tools/aapt2/io/FileStream.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_IO_FILESTREAM_H
+#define AAPT_IO_FILESTREAM_H
+
+#include "io/Io.h"
+
+#include <memory>
+#include <string>
+
+#include "android-base/file.h"  // for O_BINARY
+#include "android-base/macros.h"
+#include "android-base/unique_fd.h"
+
+namespace aapt {
+namespace io {
+
+class FileInputStream : public InputStream {
+ public:
+  explicit FileInputStream(const std::string& path, size_t buffer_capacity = 4096);
+
+  // Takes ownership of `fd`.
+  explicit FileInputStream(int fd, size_t buffer_capacity = 4096);
+
+  bool Next(const void** data, size_t* size) override;
+
+  void BackUp(size_t count) override;
+
+  size_t ByteCount() const override;
+
+  bool HadError() const override;
+
+  std::string GetError() const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FileInputStream);
+
+  android::base::unique_fd fd_;
+  std::string error_;
+  std::unique_ptr<uint8_t[]> buffer_;
+  size_t buffer_capacity_;
+  size_t buffer_offset_;
+  size_t buffer_size_;
+  size_t total_byte_count_;
+};
+
+class FileOutputStream : public OutputStream {
+ public:
+  explicit FileOutputStream(const std::string& path, int mode = O_RDWR | O_CREAT | O_BINARY,
+                            size_t buffer_capacity = 4096);
+
+  // Takes ownership of `fd`.
+  explicit FileOutputStream(int fd, size_t buffer_capacity = 4096);
+
+  ~FileOutputStream();
+
+  bool Next(void** data, size_t* size) override;
+
+  // Immediately flushes out the contents of the buffer to disk.
+  bool Flush();
+
+  void BackUp(size_t count) override;
+
+  size_t ByteCount() const override;
+
+  bool HadError() const override;
+
+  std::string GetError() const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FileOutputStream);
+
+  bool FlushImpl();
+
+  android::base::unique_fd fd_;
+  std::string error_;
+  std::unique_ptr<uint8_t[]> buffer_;
+  size_t buffer_capacity_;
+  size_t buffer_offset_;
+  size_t total_byte_count_;
+};
+
+}  // namespace io
+}  // namespace aapt
+
+#endif  // AAPT_IO_FILESTREAM_H
diff --git a/tools/aapt2/io/FileStream_test.cpp b/tools/aapt2/io/FileStream_test.cpp
new file mode 100644
index 0000000..68c3cb1
--- /dev/null
+++ b/tools/aapt2/io/FileStream_test.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "io/FileStream.h"
+
+#include "android-base/macros.h"
+#include "android-base/test_utils.h"
+
+#include "test/Test.h"
+
+using ::android::StringPiece;
+using ::testing::Eq;
+using ::testing::NotNull;
+using ::testing::StrEq;
+
+namespace aapt {
+namespace io {
+
+TEST(FileInputStreamTest, NextAndBackup) {
+  std::string input = "this is a cool string";
+  TemporaryFile file;
+  ASSERT_THAT(TEMP_FAILURE_RETRY(write(file.fd, input.c_str(), input.size())), Eq(21));
+  lseek64(file.fd, 0, SEEK_SET);
+
+  // Use a small buffer size so that we can call Next() a few times.
+  FileInputStream in(file.release(), 10u);
+  ASSERT_FALSE(in.HadError());
+  EXPECT_THAT(in.ByteCount(), Eq(0u));
+
+  const char* buffer;
+  size_t size;
+  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size)) << in.GetError();
+  ASSERT_THAT(size, Eq(10u));
+  ASSERT_THAT(buffer, NotNull());
+  EXPECT_THAT(in.ByteCount(), Eq(10u));
+  EXPECT_THAT(StringPiece(buffer, size), Eq("this is a "));
+
+  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+  ASSERT_THAT(size, Eq(10u));
+  ASSERT_THAT(buffer, NotNull());
+  EXPECT_THAT(in.ByteCount(), Eq(20u));
+  EXPECT_THAT(StringPiece(buffer, size), Eq("cool strin"));
+
+  in.BackUp(5u);
+  EXPECT_THAT(in.ByteCount(), Eq(15u));
+
+  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+  ASSERT_THAT(size, Eq(5u));
+  ASSERT_THAT(buffer, NotNull());
+  ASSERT_THAT(in.ByteCount(), Eq(20u));
+  EXPECT_THAT(StringPiece(buffer, size), Eq("strin"));
+
+  // Backup 1 more than possible. Should clamp.
+  in.BackUp(11u);
+  EXPECT_THAT(in.ByteCount(), Eq(10u));
+
+  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+  ASSERT_THAT(size, Eq(10u));
+  ASSERT_THAT(buffer, NotNull());
+  ASSERT_THAT(in.ByteCount(), Eq(20u));
+  EXPECT_THAT(StringPiece(buffer, size), Eq("cool strin"));
+
+  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+  ASSERT_THAT(size, Eq(1u));
+  ASSERT_THAT(buffer, NotNull());
+  ASSERT_THAT(in.ByteCount(), Eq(21u));
+  EXPECT_THAT(StringPiece(buffer, size), Eq("g"));
+
+  EXPECT_FALSE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+  EXPECT_FALSE(in.HadError());
+}
+
+TEST(FileOutputStreamTest, NextAndBackup) {
+  const std::string input = "this is a cool string";
+
+  TemporaryFile file;
+  int fd = file.release();
+
+  // FileOutputStream takes ownership.
+  FileOutputStream out(fd, 10u);
+  ASSERT_FALSE(out.HadError());
+  EXPECT_THAT(out.ByteCount(), Eq(0u));
+
+  char* buffer;
+  size_t size;
+  ASSERT_TRUE(out.Next(reinterpret_cast<void**>(&buffer), &size));
+  ASSERT_THAT(size, Eq(10u));
+  ASSERT_THAT(buffer, NotNull());
+  EXPECT_THAT(out.ByteCount(), Eq(10u));
+  memcpy(buffer, input.c_str(), size);
+
+  ASSERT_TRUE(out.Next(reinterpret_cast<void**>(&buffer), &size));
+  ASSERT_THAT(size, Eq(10u));
+  ASSERT_THAT(buffer, NotNull());
+  EXPECT_THAT(out.ByteCount(), Eq(20u));
+  memcpy(buffer, input.c_str() + 10u, size);
+
+  ASSERT_TRUE(out.Next(reinterpret_cast<void**>(&buffer), &size));
+  ASSERT_THAT(size, Eq(10u));
+  ASSERT_THAT(buffer, NotNull());
+  EXPECT_THAT(out.ByteCount(), Eq(30u));
+  buffer[0] = input[20u];
+  out.BackUp(size - 1);
+  EXPECT_THAT(out.ByteCount(), Eq(21u));
+
+  ASSERT_TRUE(out.Flush());
+
+  lseek64(fd, 0, SEEK_SET);
+
+  std::string actual;
+  ASSERT_TRUE(android::base::ReadFdToString(fd, &actual));
+  EXPECT_THAT(actual, StrEq(input));
+}
+
+}  // namespace io
+}  // namespace aapt
diff --git a/tools/aapt2/io/FileSystem.cpp b/tools/aapt2/io/FileSystem.cpp
index 027cbd0..1387d22 100644
--- a/tools/aapt2/io/FileSystem.cpp
+++ b/tools/aapt2/io/FileSystem.cpp
@@ -20,11 +20,12 @@
 #include "utils/FileMap.h"
 
 #include "Source.h"
+#include "io/FileStream.h"
 #include "util/Files.h"
 #include "util/Maybe.h"
 #include "util/Util.h"
 
-using android::StringPiece;
+using ::android::StringPiece;
 
 namespace aapt {
 namespace io {
@@ -42,12 +43,20 @@
   return {};
 }
 
-const Source& RegularFile::GetSource() const { return source_; }
+std::unique_ptr<io::InputStream> RegularFile::OpenInputStream() {
+  return util::make_unique<FileInputStream>(source_.path);
+}
+
+const Source& RegularFile::GetSource() const {
+  return source_;
+}
 
 FileCollectionIterator::FileCollectionIterator(FileCollection* collection)
     : current_(collection->files_.begin()), end_(collection->files_.end()) {}
 
-bool FileCollectionIterator::HasNext() { return current_ != end_; }
+bool FileCollectionIterator::HasNext() {
+  return current_ != end_;
+}
 
 IFile* FileCollectionIterator::Next() {
   IFile* result = current_->second.get();
diff --git a/tools/aapt2/io/FileSystem.h b/tools/aapt2/io/FileSystem.h
index dfd3717..6be8807 100644
--- a/tools/aapt2/io/FileSystem.h
+++ b/tools/aapt2/io/FileSystem.h
@@ -24,17 +24,18 @@
 namespace aapt {
 namespace io {
 
-/**
- * A regular file from the file system. Uses mmap to open the data.
- */
+// A regular file from the file system. Uses mmap to open the data.
 class RegularFile : public IFile {
  public:
   explicit RegularFile(const Source& source);
 
   std::unique_ptr<IData> OpenAsData() override;
+  std::unique_ptr<io::InputStream> OpenInputStream() override;
   const Source& GetSource() const override;
 
  private:
+  DISALLOW_COPY_AND_ASSIGN(RegularFile);
+
   Source source_;
 };
 
@@ -48,23 +49,26 @@
   io::IFile* Next() override;
 
  private:
+  DISALLOW_COPY_AND_ASSIGN(FileCollectionIterator);
+
   std::map<std::string, std::unique_ptr<IFile>>::const_iterator current_, end_;
 };
 
-/**
- * An IFileCollection representing the file system.
- */
+// An IFileCollection representing the file system.
 class FileCollection : public IFileCollection {
  public:
-  /**
-   * Adds a file located at path. Returns the IFile representation of that file.
-   */
+  FileCollection() = default;
+
+  // Adds a file located at path. Returns the IFile representation of that file.
   IFile* InsertFile(const android::StringPiece& path);
   IFile* FindFile(const android::StringPiece& path) override;
   std::unique_ptr<IFileCollectionIterator> Iterator() override;
 
  private:
+  DISALLOW_COPY_AND_ASSIGN(FileCollection);
+
   friend class FileCollectionIterator;
+
   std::map<std::string, std::unique_ptr<IFile>> files_;
 };
 
diff --git a/tools/aapt2/io/Io.h b/tools/aapt2/io/Io.h
index a656740..e1df23a6 100644
--- a/tools/aapt2/io/Io.h
+++ b/tools/aapt2/io/Io.h
@@ -58,6 +58,12 @@
   virtual bool HadError() const = 0;
 };
 
+// A sub-InputStream interface that knows the total size of its stream.
+class KnownSizeInputStream : public InputStream {
+ public:
+  virtual size_t TotalSize() const = 0;
+};
+
 // OutputStream interface that mimics protobuf's ZeroCopyOutputStream,
 // with added error handling methods to better report issues.
 class OutputStream {
diff --git a/tools/aapt2/io/StringInputStream.cpp b/tools/aapt2/io/StringInputStream.cpp
deleted file mode 100644
index 51a18a7..0000000
--- a/tools/aapt2/io/StringInputStream.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "io/StringInputStream.h"
-
-using ::android::StringPiece;
-
-namespace aapt {
-namespace io {
-
-StringInputStream::StringInputStream(const StringPiece& str) : str_(str), offset_(0u) {
-}
-
-bool StringInputStream::Next(const void** data, size_t* size) {
-  if (offset_ == str_.size()) {
-    return false;
-  }
-
-  *data = str_.data() + offset_;
-  *size = str_.size() - offset_;
-  offset_ = str_.size();
-  return true;
-}
-
-void StringInputStream::BackUp(size_t count) {
-  if (count > offset_) {
-    count = offset_;
-  }
-  offset_ -= count;
-}
-
-size_t StringInputStream::ByteCount() const {
-  return offset_;
-}
-
-}  // namespace io
-}  // namespace aapt
diff --git a/tools/aapt2/io/StringInputStream.h b/tools/aapt2/io/StringInputStream.h
deleted file mode 100644
index ff5b112..0000000
--- a/tools/aapt2/io/StringInputStream.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AAPT_IO_STRINGINPUTSTREAM_H
-#define AAPT_IO_STRINGINPUTSTREAM_H
-
-#include "io/Io.h"
-
-#include "android-base/macros.h"
-#include "androidfw/StringPiece.h"
-
-namespace aapt {
-namespace io {
-
-class StringInputStream : public InputStream {
- public:
-  explicit StringInputStream(const android::StringPiece& str);
-
-  bool Next(const void** data, size_t* size) override;
-
-  void BackUp(size_t count) override;
-
-  size_t ByteCount() const override;
-
-  inline bool HadError() const override {
-    return false;
-  }
-
-  inline std::string GetError() const override {
-    return {};
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(StringInputStream);
-
-  android::StringPiece str_;
-  size_t offset_;
-};
-
-}  // namespace io
-}  // namespace aapt
-
-#endif  // AAPT_IO_STRINGINPUTSTREAM_H
diff --git a/tools/aapt2/io/StringInputStream_test.cpp b/tools/aapt2/io/StringInputStream_test.cpp
deleted file mode 100644
index cc57bc4..0000000
--- a/tools/aapt2/io/StringInputStream_test.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "io/StringInputStream.h"
-
-#include "test/Test.h"
-
-using ::android::StringPiece;
-using ::testing::Eq;
-using ::testing::NotNull;
-using ::testing::StrEq;
-
-namespace aapt {
-namespace io {
-
-TEST(StringInputStreamTest, OneCallToNextShouldReturnEntireBuffer) {
-  constexpr const size_t kCount = 1000;
-  std::string input;
-  input.resize(kCount, 0x7f);
-  input[0] = 0x00;
-  input[kCount - 1] = 0xff;
-  StringInputStream in(input);
-
-  const char* buffer;
-  size_t size;
-  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
-  ASSERT_THAT(size, Eq(kCount));
-  ASSERT_THAT(buffer, NotNull());
-
-  EXPECT_THAT(buffer[0], Eq(0x00));
-  EXPECT_THAT(buffer[kCount - 1], Eq('\xff'));
-
-  EXPECT_FALSE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
-  EXPECT_FALSE(in.HadError());
-}
-
-TEST(StringInputStreamTest, BackUp) {
-  std::string input = "hello this is a string";
-  StringInputStream in(input);
-
-  const char* buffer;
-  size_t size;
-  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
-  ASSERT_THAT(size, Eq(input.size()));
-  ASSERT_THAT(buffer, NotNull());
-  EXPECT_THAT(in.ByteCount(), Eq(input.size()));
-
-  in.BackUp(6u);
-  EXPECT_THAT(in.ByteCount(), Eq(input.size() - 6u));
-
-  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
-  ASSERT_THAT(size, Eq(6u));
-  ASSERT_THAT(buffer, NotNull());
-  ASSERT_THAT(buffer, StrEq("string"));
-  EXPECT_THAT(in.ByteCount(), Eq(input.size()));
-}
-
-}  // namespace io
-}  // namespace aapt
diff --git a/tools/aapt2/io/StringStream.cpp b/tools/aapt2/io/StringStream.cpp
new file mode 100644
index 0000000..4ca04a8
--- /dev/null
+++ b/tools/aapt2/io/StringStream.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "io/StringStream.h"
+
+using ::android::StringPiece;
+
+namespace aapt {
+namespace io {
+
+StringInputStream::StringInputStream(const StringPiece& str) : str_(str), offset_(0u) {
+}
+
+bool StringInputStream::Next(const void** data, size_t* size) {
+  if (offset_ == str_.size()) {
+    return false;
+  }
+
+  *data = str_.data() + offset_;
+  *size = str_.size() - offset_;
+  offset_ = str_.size();
+  return true;
+}
+
+void StringInputStream::BackUp(size_t count) {
+  if (count > offset_) {
+    offset_ = 0u;
+  } else {
+    offset_ -= count;
+  }
+}
+
+size_t StringInputStream::ByteCount() const {
+  return offset_;
+}
+
+size_t StringInputStream::TotalSize() const {
+  return str_.size();
+}
+
+StringOutputStream::StringOutputStream(std::string* str, size_t buffer_capacity)
+    : str_(str),
+      buffer_capacity_(buffer_capacity),
+      buffer_offset_(0u),
+      buffer_(new char[buffer_capacity]) {
+}
+
+StringOutputStream::~StringOutputStream() {
+  Flush();
+}
+
+bool StringOutputStream::Next(void** data, size_t* size) {
+  if (buffer_offset_ == buffer_capacity_) {
+    FlushImpl();
+  }
+
+  *data = buffer_.get() + buffer_offset_;
+  *size = buffer_capacity_ - buffer_offset_;
+  buffer_offset_ = buffer_capacity_;
+  return true;
+}
+
+void StringOutputStream::BackUp(size_t count) {
+  if (count > buffer_offset_) {
+    buffer_offset_ = 0u;
+  } else {
+    buffer_offset_ -= count;
+  }
+}
+
+size_t StringOutputStream::ByteCount() const {
+  return str_->size() + buffer_offset_;
+}
+
+void StringOutputStream::Flush() {
+  if (buffer_offset_ != 0u) {
+    FlushImpl();
+  }
+}
+
+void StringOutputStream::FlushImpl() {
+  str_->append(buffer_.get(), buffer_offset_);
+  buffer_offset_ = 0u;
+}
+
+}  // namespace io
+}  // namespace aapt
diff --git a/tools/aapt2/io/StringStream.h b/tools/aapt2/io/StringStream.h
new file mode 100644
index 0000000..f29890a
--- /dev/null
+++ b/tools/aapt2/io/StringStream.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_IO_STRINGSTREAM_H
+#define AAPT_IO_STRINGSTREAM_H
+
+#include "io/Io.h"
+
+#include <memory>
+
+#include "android-base/macros.h"
+#include "androidfw/StringPiece.h"
+
+namespace aapt {
+namespace io {
+
+class StringInputStream : public KnownSizeInputStream {
+ public:
+  explicit StringInputStream(const android::StringPiece& str);
+
+  bool Next(const void** data, size_t* size) override;
+
+  void BackUp(size_t count) override;
+
+  size_t ByteCount() const override;
+
+  inline bool HadError() const override {
+    return false;
+  }
+
+  inline std::string GetError() const override {
+    return {};
+  }
+
+  size_t TotalSize() const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StringInputStream);
+
+  android::StringPiece str_;
+  size_t offset_;
+};
+
+class StringOutputStream : public OutputStream {
+ public:
+  explicit StringOutputStream(std::string* str, size_t buffer_capacity = 4096u);
+
+  ~StringOutputStream();
+
+  bool Next(void** data, size_t* size) override;
+
+  void BackUp(size_t count) override;
+
+  void Flush();
+
+  size_t ByteCount() const override;
+
+  inline bool HadError() const override {
+    return false;
+  }
+
+  inline std::string GetError() const override {
+    return {};
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StringOutputStream);
+
+  void FlushImpl();
+
+  std::string* str_;
+  size_t buffer_capacity_;
+  size_t buffer_offset_;
+  std::unique_ptr<char[]> buffer_;
+};
+
+}  // namespace io
+}  // namespace aapt
+
+#endif  // AAPT_IO_STRINGSTREAM_H
diff --git a/tools/aapt2/io/StringStream_test.cpp b/tools/aapt2/io/StringStream_test.cpp
new file mode 100644
index 0000000..fb43fb7
--- /dev/null
+++ b/tools/aapt2/io/StringStream_test.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "io/StringStream.h"
+
+#include "io/Util.h"
+
+#include "test/Test.h"
+
+using ::android::StringPiece;
+using ::testing::Eq;
+using ::testing::NotNull;
+using ::testing::StrEq;
+
+namespace aapt {
+namespace io {
+
+TEST(StringInputStreamTest, OneCallToNextShouldReturnEntireBuffer) {
+  constexpr const size_t kCount = 1000;
+  std::string input;
+  input.resize(kCount, 0x7f);
+  input[0] = 0x00;
+  input[kCount - 1] = 0xff;
+  StringInputStream in(input);
+
+  const char* buffer;
+  size_t size;
+  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+  ASSERT_THAT(size, Eq(kCount));
+  ASSERT_THAT(buffer, NotNull());
+
+  EXPECT_THAT(buffer[0], Eq(0x00));
+  EXPECT_THAT(buffer[kCount - 1], Eq('\xff'));
+
+  EXPECT_FALSE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+  EXPECT_FALSE(in.HadError());
+}
+
+TEST(StringInputStreamTest, BackUp) {
+  std::string input = "hello this is a string";
+  StringInputStream in(input);
+
+  const char* buffer;
+  size_t size;
+  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+  ASSERT_THAT(size, Eq(input.size()));
+  ASSERT_THAT(buffer, NotNull());
+  EXPECT_THAT(in.ByteCount(), Eq(input.size()));
+
+  in.BackUp(6u);
+  EXPECT_THAT(in.ByteCount(), Eq(input.size() - 6u));
+
+  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+  ASSERT_THAT(size, Eq(6u));
+  ASSERT_THAT(buffer, NotNull());
+  ASSERT_THAT(buffer, StrEq("string"));
+  EXPECT_THAT(in.ByteCount(), Eq(input.size()));
+}
+
+TEST(StringOutputStreamTest, NextAndBackUp) {
+  std::string input = "hello this is a string";
+  std::string output;
+
+  StringInputStream in(input);
+  StringOutputStream out(&output, 10u);
+  ASSERT_TRUE(Copy(&out, &in));
+  out.Flush();
+  EXPECT_THAT(output, StrEq(input));
+}
+
+}  // namespace io
+}  // namespace aapt
diff --git a/tools/aapt2/io/Util.cpp b/tools/aapt2/io/Util.cpp
index 15114e8..d270340 100644
--- a/tools/aapt2/io/Util.cpp
+++ b/tools/aapt2/io/Util.cpp
@@ -18,6 +18,8 @@
 
 #include "google/protobuf/io/zero_copy_stream_impl_lite.h"
 
+using ::google::protobuf::io::ZeroCopyOutputStream;
+
 namespace aapt {
 namespace io {
 
@@ -91,5 +93,10 @@
   return !in->HadError();
 }
 
+bool Copy(ZeroCopyOutputStream* out, InputStream* in) {
+  OutputStreamAdaptor adaptor(out);
+  return Copy(&adaptor, in);
+}
+
 }  // namespace io
 }  // namespace aapt
diff --git a/tools/aapt2/io/Util.h b/tools/aapt2/io/Util.h
index 02ee876..1e48508 100644
--- a/tools/aapt2/io/Util.h
+++ b/tools/aapt2/io/Util.h
@@ -42,6 +42,81 @@
 // Copies the data from in to out. Returns false if there was an error.
 // If there was an error, check the individual streams' HadError/GetError methods.
 bool Copy(OutputStream* out, InputStream* in);
+bool Copy(::google::protobuf::io::ZeroCopyOutputStream* out, InputStream* in);
+
+class OutputStreamAdaptor : public io::OutputStream {
+ public:
+  explicit OutputStreamAdaptor(::google::protobuf::io::ZeroCopyOutputStream* out) : out_(out) {
+  }
+
+  bool Next(void** data, size_t* size) override {
+    int out_size;
+    bool result = out_->Next(data, &out_size);
+    *size = static_cast<size_t>(out_size);
+    if (!result) {
+      error_ocurred_ = true;
+    }
+    return result;
+  }
+
+  void BackUp(size_t count) override {
+    out_->BackUp(static_cast<int>(count));
+  }
+
+  size_t ByteCount() const override {
+    return static_cast<size_t>(out_->ByteCount());
+  }
+
+  bool HadError() const override {
+    return error_ocurred_;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(OutputStreamAdaptor);
+
+  ::google::protobuf::io::ZeroCopyOutputStream* out_;
+  bool error_ocurred_ = false;
+};
+
+class ZeroCopyInputAdaptor : public ::google::protobuf::io::ZeroCopyInputStream {
+ public:
+  explicit ZeroCopyInputAdaptor(io::InputStream* in) : in_(in) {
+  }
+
+  bool Next(const void** data, int* size) override {
+    size_t out_size;
+    bool result = in_->Next(data, &out_size);
+    *size = static_cast<int>(out_size);
+    return result;
+  }
+
+  void BackUp(int count) override {
+    in_->BackUp(static_cast<size_t>(count));
+  }
+
+  bool Skip(int count) override {
+    const void* data;
+    int size;
+    while (Next(&data, &size)) {
+      if (size > count) {
+        BackUp(size - count);
+        return true;
+      } else {
+        count -= size;
+      }
+    }
+    return false;
+  }
+
+  ::google::protobuf::int64 ByteCount() const override {
+    return static_cast<::google::protobuf::int64>(in_->ByteCount());
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ZeroCopyInputAdaptor);
+
+  io::InputStream* in_;
+};
 
 }  // namespace io
 }  // namespace aapt
diff --git a/tools/aapt2/io/ZipArchive.cpp b/tools/aapt2/io/ZipArchive.cpp
index 6494d2d..269b6c5 100644
--- a/tools/aapt2/io/ZipArchive.cpp
+++ b/tools/aapt2/io/ZipArchive.cpp
@@ -22,7 +22,7 @@
 #include "Source.h"
 #include "util/Util.h"
 
-using android::StringPiece;
+using ::android::StringPiece;
 
 namespace aapt {
 namespace io {
@@ -57,7 +57,13 @@
   }
 }
 
-const Source& ZipFile::GetSource() const { return source_; }
+std::unique_ptr<io::InputStream> ZipFile::OpenInputStream() {
+  return OpenAsData();
+}
+
+const Source& ZipFile::GetSource() const {
+  return source_;
+}
 
 bool ZipFile::WasCompressed() {
   return zip_entry_.method != kCompressStored;
@@ -67,7 +73,9 @@
     ZipFileCollection* collection)
     : current_(collection->files_.begin()), end_(collection->files_.end()) {}
 
-bool ZipFileCollectionIterator::HasNext() { return current_ != end_; }
+bool ZipFileCollectionIterator::HasNext() {
+  return current_ != end_;
+}
 
 IFile* ZipFileCollectionIterator::Next() {
   IFile* result = current_->get();
diff --git a/tools/aapt2/io/ZipArchive.h b/tools/aapt2/io/ZipArchive.h
index 56c74e3..8381259 100644
--- a/tools/aapt2/io/ZipArchive.h
+++ b/tools/aapt2/io/ZipArchive.h
@@ -28,23 +28,20 @@
 namespace aapt {
 namespace io {
 
-/**
- * An IFile representing a file within a ZIP archive. If the file is compressed,
- * it is uncompressed
- * and copied into memory when opened. Otherwise it is mmapped from the ZIP
- * archive.
- */
+// An IFile representing a file within a ZIP archive. If the file is compressed, it is uncompressed
+// and copied into memory when opened. Otherwise it is mmapped from the ZIP archive.
 class ZipFile : public IFile {
  public:
-  ZipFile(ZipArchiveHandle handle, const ZipEntry& entry, const Source& source);
+  ZipFile(::ZipArchiveHandle handle, const ::ZipEntry& entry, const Source& source);
 
   std::unique_ptr<IData> OpenAsData() override;
+  std::unique_ptr<io::InputStream> OpenInputStream() override;
   const Source& GetSource() const override;
   bool WasCompressed() override;
 
  private:
-  ZipArchiveHandle zip_handle_;
-  ZipEntry zip_entry_;
+  ::ZipArchiveHandle zip_handle_;
+  ::ZipEntry zip_entry_;
   Source source_;
 };
 
@@ -61,9 +58,7 @@
   std::vector<std::unique_ptr<IFile>>::const_iterator current_, end_;
 };
 
-/**
- * An IFileCollection that represents a ZIP archive and the entries within it.
- */
+// An IFileCollection that represents a ZIP archive and the entries within it.
 class ZipFileCollection : public IFileCollection {
  public:
   static std::unique_ptr<ZipFileCollection> Create(const android::StringPiece& path,
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index 93c904f..21c6b11 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -37,13 +37,12 @@
   CHECK(master_package_ != nullptr) << "package name or ID already taken";
 }
 
-bool TableMerger::Merge(const Source& src, ResourceTable* table, io::IFileCollection* collection) {
-  return MergeImpl(src, table, collection, false /*overlay*/, true /*allow_new*/);
-}
-
-bool TableMerger::MergeOverlay(const Source& src, ResourceTable* table,
-                               io::IFileCollection* collection) {
-  return MergeImpl(src, table, collection, true /*overlay*/, options_.auto_add_overlay);
+bool TableMerger::Merge(const Source& src, ResourceTable* table, bool overlay,
+                        io::IFileCollection* collection) {
+  // We allow adding new resources if this is not an overlay, or if the options allow overlays
+  // to add new resources.
+  return MergeImpl(src, table, collection, overlay,
+                   options_.auto_add_overlay || !overlay /*allow_new*/);
 }
 
 // This will merge packages with the same package name (or no package name).
@@ -322,17 +321,20 @@
         util::make_unique<FileReference>(master_table_->string_pool.MakeRef(newPath));
     new_file_ref->SetComment(file_ref.GetComment());
     new_file_ref->SetSource(file_ref.GetSource());
+    new_file_ref->type = file_ref.type;
+    new_file_ref->file = file_ref.file;
     return new_file_ref;
   }
   return std::unique_ptr<FileReference>(file_ref.Clone(&master_table_->string_pool));
 }
 
-bool TableMerger::MergeFileImpl(const ResourceFile& file_desc, io::IFile* file, bool overlay) {
+bool TableMerger::MergeFile(const ResourceFile& file_desc, bool overlay, io::IFile* file) {
   ResourceTable table;
   std::string path = ResourceUtils::BuildResourceFileName(file_desc);
   std::unique_ptr<FileReference> file_ref =
       util::make_unique<FileReference>(table.string_pool.MakeRef(path));
   file_ref->SetSource(file_desc.source);
+  file_ref->type = file_desc.type;
   file_ref->file = file;
 
   ResourceTablePackage* pkg = table.CreatePackage(file_desc.name.package, 0x0);
@@ -341,17 +343,8 @@
       ->FindOrCreateValue(file_desc.config, {})
       ->value = std::move(file_ref);
 
-  return DoMerge(file->GetSource(), &table, pkg, false /* mangle */,
-                 overlay /* overlay */, true /* allow_new */, {});
-}
-
-bool TableMerger::MergeFile(const ResourceFile& file_desc, io::IFile* file) {
-  return MergeFileImpl(file_desc, file, false /* overlay */);
-}
-
-bool TableMerger::MergeFileOverlay(const ResourceFile& file_desc,
-                                   io::IFile* file) {
-  return MergeFileImpl(file_desc, file, true /* overlay */);
+  return DoMerge(file->GetSource(), &table, pkg, false /* mangle */, overlay /* overlay */,
+                 true /* allow_new */, {});
 }
 
 }  // namespace aapt
diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h
index 81518ff..d024aa4 100644
--- a/tools/aapt2/link/TableMerger.h
+++ b/tools/aapt2/link/TableMerger.h
@@ -59,24 +59,18 @@
   }
 
   // Merges resources from the same or empty package. This is for local sources.
+  // If overlay is true, the resources are treated as overlays.
   // An io::IFileCollection is optional and used to find the referenced Files and process them.
-  bool Merge(const Source& src, ResourceTable* table, io::IFileCollection* collection = nullptr);
-
-  // Merges resources from an overlay ResourceTable.
-  // An io::IFileCollection is optional and used to find the referenced Files and process them.
-  bool MergeOverlay(const Source& src, ResourceTable* table,
-                    io::IFileCollection* collection = nullptr);
+  bool Merge(const Source& src, ResourceTable* table, bool overlay,
+             io::IFileCollection* collection = nullptr);
 
   // Merges resources from the given package, mangling the name. This is for static libraries.
   // An io::IFileCollection is needed in order to find the referenced Files and process them.
   bool MergeAndMangle(const Source& src, const android::StringPiece& package, ResourceTable* table,
                       io::IFileCollection* collection);
 
-  // Merges a compiled file that belongs to this same or empty package. This is for local sources.
-  bool MergeFile(const ResourceFile& fileDesc, io::IFile* file);
-
-  // Merges a compiled file from an overlay, overriding an existing definition.
-  bool MergeFileOverlay(const ResourceFile& fileDesc, io::IFile* file);
+  // Merges a compiled file that belongs to this same or empty package.
+  bool MergeFile(const ResourceFile& fileDesc, bool overlay, io::IFile* file);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TableMerger);
@@ -91,9 +85,6 @@
   ResourceTablePackage* master_package_;
   std::set<std::string> merged_packages_;
 
-  bool MergeFileImpl(const ResourceFile& file_desc, io::IFile* file,
-                     bool overlay);
-
   bool MergeImpl(const Source& src, ResourceTable* src_table,
                  io::IFileCollection* collection, bool overlay, bool allow_new);
 
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index 45b01a49..3499809 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -69,7 +69,7 @@
   TableMerger merger(context_.get(), &final_table, TableMergerOptions{});
   io::FileCollection collection;
 
-  ASSERT_TRUE(merger.Merge({}, table_a.get()));
+  ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
   ASSERT_TRUE(merger.MergeAndMangle({}, "com.app.b", table_b.get(), &collection));
 
   EXPECT_TRUE(merger.merged_packages().count("com.app.b") != 0);
@@ -98,7 +98,7 @@
   file_desc.source = Source("res/layout-hdpi/main.xml");
   test::TestFile test_file("path/to/res/layout-hdpi/main.xml.flat");
 
-  ASSERT_TRUE(merger.MergeFile(file_desc, &test_file));
+  ASSERT_TRUE(merger.MergeFile(file_desc, false /*overlay*/, &test_file));
 
   FileReference* file = test::GetValueForConfig<FileReference>(
       &final_table, "com.app.a:layout/main", test::ParseConfigOrDie("hdpi-v4"));
@@ -117,8 +117,8 @@
   test::TestFile file_a("path/to/fileA.xml.flat");
   test::TestFile file_b("path/to/fileB.xml.flat");
 
-  ASSERT_TRUE(merger.MergeFile(file_desc, &file_a));
-  ASSERT_TRUE(merger.MergeFileOverlay(file_desc, &file_b));
+  ASSERT_TRUE(merger.MergeFile(file_desc, false /*overlay*/, &file_a));
+  ASSERT_TRUE(merger.MergeFile(file_desc, true /*overlay*/, &file_b));
 }
 
 TEST_F(TableMergerTest, MergeFileReferences) {
@@ -138,7 +138,7 @@
   io::FileCollection collection;
   collection.InsertFile("res/xml/file.xml");
 
-  ASSERT_TRUE(merger.Merge({}, table_a.get()));
+  ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
   ASSERT_TRUE(merger.MergeAndMangle({}, "com.app.b", table_b.get(), &collection));
 
   FileReference* f = test::GetValue<FileReference>(&final_table, "com.app.a:xml/file");
@@ -167,8 +167,8 @@
   options.auto_add_overlay = false;
   TableMerger merger(context_.get(), &final_table, options);
 
-  ASSERT_TRUE(merger.Merge({}, base.get()));
-  ASSERT_TRUE(merger.MergeOverlay({}, overlay.get()));
+  ASSERT_TRUE(merger.Merge({}, base.get(), false /*overlay*/));
+  ASSERT_TRUE(merger.Merge({}, overlay.get(), true /*overlay*/));
 
   BinaryPrimitive* foo = test::GetValue<BinaryPrimitive>(&final_table, "com.app.a:bool/foo");
   ASSERT_THAT(foo,
@@ -194,8 +194,8 @@
   options.auto_add_overlay = false;
   TableMerger merger(context_.get(), &final_table, options);
 
-  ASSERT_TRUE(merger.Merge({}, base.get()));
-  ASSERT_TRUE(merger.MergeOverlay({}, overlay.get()));
+  ASSERT_TRUE(merger.Merge({}, base.get(), false /*overlay*/));
+  ASSERT_TRUE(merger.Merge({}, overlay.get(), true /*overlay*/));
 }
 
 TEST_F(TableMergerTest, FailToOverrideConflictingTypeIdsWithOverlay) {
@@ -217,8 +217,8 @@
   options.auto_add_overlay = false;
   TableMerger merger(context_.get(), &final_table, options);
 
-  ASSERT_TRUE(merger.Merge({}, base.get()));
-  ASSERT_FALSE(merger.MergeOverlay({}, overlay.get()));
+  ASSERT_TRUE(merger.Merge({}, base.get(), false /*overlay*/));
+  ASSERT_FALSE(merger.Merge({}, overlay.get(), true /*overlay*/));
 }
 
 TEST_F(TableMergerTest, FailToOverrideConflictingEntryIdsWithOverlay) {
@@ -240,8 +240,8 @@
   options.auto_add_overlay = false;
   TableMerger merger(context_.get(), &final_table, options);
 
-  ASSERT_TRUE(merger.Merge({}, base.get()));
-  ASSERT_FALSE(merger.MergeOverlay({}, overlay.get()));
+  ASSERT_TRUE(merger.Merge({}, base.get(), false /*overlay*/));
+  ASSERT_FALSE(merger.Merge({}, overlay.get(), true /*overlay*/));
 }
 
 TEST_F(TableMergerTest, MergeAddResourceFromOverlay) {
@@ -259,8 +259,8 @@
   options.auto_add_overlay = false;
   TableMerger merger(context_.get(), &final_table, options);
 
-  ASSERT_TRUE(merger.Merge({}, table_a.get()));
-  ASSERT_TRUE(merger.MergeOverlay({}, table_b.get()));
+  ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
+  ASSERT_TRUE(merger.Merge({}, table_b.get(), false /*overlay*/));
 }
 
 TEST_F(TableMergerTest, MergeAddResourceFromOverlayWithAutoAddOverlay) {
@@ -277,8 +277,8 @@
   options.auto_add_overlay = true;
   TableMerger merger(context_.get(), &final_table, options);
 
-  ASSERT_TRUE(merger.Merge({}, table_a.get()));
-  ASSERT_TRUE(merger.MergeOverlay({}, table_b.get()));
+  ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
+  ASSERT_TRUE(merger.Merge({}, table_b.get(), false /*overlay*/));
 }
 
 TEST_F(TableMergerTest, FailToMergeNewResourceWithoutAutoAddOverlay) {
@@ -295,8 +295,8 @@
   options.auto_add_overlay = false;
   TableMerger merger(context_.get(), &final_table, options);
 
-  ASSERT_TRUE(merger.Merge({}, table_a.get()));
-  ASSERT_FALSE(merger.MergeOverlay({}, table_b.get()));
+  ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
+  ASSERT_FALSE(merger.Merge({}, table_b.get(), true /*overlay*/));
 }
 
 TEST_F(TableMergerTest, OverlaidStyleablesAndStylesShouldBeMerged) {
@@ -337,8 +337,8 @@
   options.auto_add_overlay = true;
   TableMerger merger(context_.get(), &final_table, options);
 
-  ASSERT_TRUE(merger.Merge({}, table_a.get()));
-  ASSERT_TRUE(merger.MergeOverlay({}, table_b.get()));
+  ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
+  ASSERT_TRUE(merger.Merge({}, table_b.get(), true /*overlay*/));
 
   Styleable* styleable = test::GetValue<Styleable>(&final_table, "com.app.a:styleable/Foo");
   ASSERT_THAT(styleable, NotNull());
diff --git a/tools/aapt2/test/Builders.cpp b/tools/aapt2/test/Builders.cpp
index e658664..5a62e97 100644
--- a/tools/aapt2/test/Builders.cpp
+++ b/tools/aapt2/test/Builders.cpp
@@ -19,7 +19,7 @@
 #include "android-base/logging.h"
 #include "androidfw/StringPiece.h"
 
-#include "io/StringInputStream.h"
+#include "io/StringStream.h"
 #include "test/Common.h"
 #include "util/Util.h"
 
diff --git a/tools/aapt2/test/Common.h b/tools/aapt2/test/Common.h
index 61d0563..4e318a9 100644
--- a/tools/aapt2/test/Common.h
+++ b/tools/aapt2/test/Common.h
@@ -90,6 +90,10 @@
     return {};
   }
 
+  std::unique_ptr<io::InputStream> OpenInputStream() override {
+    return OpenAsData();
+  }
+
   const Source& GetSource() const override {
     return source_;
   }
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index b3e0a92..3522506 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -215,8 +215,8 @@
       return {};
     }
   }
-  return util::make_unique<XmlResource>(ResourceFile{{}, {}, source}, StringPool{},
-                                        std::move(stack.root));
+  return util::make_unique<XmlResource>(ResourceFile{{}, {}, ResourceFile::Type::kUnknown, source},
+                                        StringPool{}, std::move(stack.root));
 }
 
 static void CopyAttributes(Element* el, android::ResXMLParser* parser, StringPool* out_pool) {
diff --git a/tools/aapt2/xml/XmlDom_test.cpp b/tools/aapt2/xml/XmlDom_test.cpp
index 4ba0443..34e6d3f 100644
--- a/tools/aapt2/xml/XmlDom_test.cpp
+++ b/tools/aapt2/xml/XmlDom_test.cpp
@@ -19,7 +19,7 @@
 #include <string>
 
 #include "format/binary/XmlFlattener.h"
-#include "io/StringInputStream.h"
+#include "io/StringStream.h"
 #include "test/Test.h"
 
 using ::aapt::io::StringInputStream;
diff --git a/tools/aapt2/xml/XmlPullParser_test.cpp b/tools/aapt2/xml/XmlPullParser_test.cpp
index 681d9d4..5304bde 100644
--- a/tools/aapt2/xml/XmlPullParser_test.cpp
+++ b/tools/aapt2/xml/XmlPullParser_test.cpp
@@ -18,43 +18,49 @@
 
 #include "androidfw/StringPiece.h"
 
-#include "io/StringInputStream.h"
+#include "io/StringStream.h"
 #include "test/Test.h"
 
 using ::aapt::io::StringInputStream;
 using ::android::StringPiece;
+using ::testing::Eq;
+using ::testing::StrEq;
+
+using Event = ::aapt::xml::XmlPullParser::Event;
 
 namespace aapt {
+namespace xml {
 
 TEST(XmlPullParserTest, NextChildNodeTraversesCorrectly) {
   std::string str =
       R"(<?xml version="1.0" encoding="utf-8"?>
          <a><b><c xmlns:a="http://schema.org"><d/></c><e/></b></a>)";
   StringInputStream input(str);
-  xml::XmlPullParser parser(&input);
+  XmlPullParser parser(&input);
 
   const size_t depth_outer = parser.depth();
-  ASSERT_TRUE(xml::XmlPullParser::NextChildNode(&parser, depth_outer));
+  ASSERT_TRUE(XmlPullParser::NextChildNode(&parser, depth_outer));
 
-  EXPECT_EQ(xml::XmlPullParser::Event::kStartElement, parser.event());
-  EXPECT_EQ(StringPiece("a"), StringPiece(parser.element_name()));
+  EXPECT_THAT(parser.event(), Eq(XmlPullParser::Event::kStartElement));
+  EXPECT_THAT(parser.element_name(), StrEq("a"));
 
   const size_t depth_a = parser.depth();
-  ASSERT_TRUE(xml::XmlPullParser::NextChildNode(&parser, depth_a));
-  EXPECT_EQ(xml::XmlPullParser::Event::kStartElement, parser.event());
-  EXPECT_EQ(StringPiece("b"), StringPiece(parser.element_name()));
+  ASSERT_TRUE(XmlPullParser::NextChildNode(&parser, depth_a));
+  EXPECT_THAT(parser.event(), Eq(XmlPullParser::Event::kStartElement));
+  EXPECT_THAT(parser.element_name(), StrEq("b"));
 
   const size_t depth_b = parser.depth();
-  ASSERT_TRUE(xml::XmlPullParser::NextChildNode(&parser, depth_b));
-  EXPECT_EQ(xml::XmlPullParser::Event::kStartElement, parser.event());
-  EXPECT_EQ(StringPiece("c"), StringPiece(parser.element_name()));
+  ASSERT_TRUE(XmlPullParser::NextChildNode(&parser, depth_b));
+  EXPECT_THAT(parser.event(), Eq(XmlPullParser::Event::kStartElement));
+  EXPECT_THAT(parser.element_name(), StrEq("c"));
 
-  ASSERT_TRUE(xml::XmlPullParser::NextChildNode(&parser, depth_b));
-  EXPECT_EQ(xml::XmlPullParser::Event::kStartElement, parser.event());
-  EXPECT_EQ(StringPiece("e"), StringPiece(parser.element_name()));
+  ASSERT_TRUE(XmlPullParser::NextChildNode(&parser, depth_b));
+  EXPECT_THAT(parser.event(), Eq(XmlPullParser::Event::kStartElement));
+  EXPECT_THAT(parser.element_name(), StrEq("e"));
 
-  ASSERT_FALSE(xml::XmlPullParser::NextChildNode(&parser, depth_outer));
-  EXPECT_EQ(xml::XmlPullParser::Event::kEndDocument, parser.event());
+  ASSERT_FALSE(XmlPullParser::NextChildNode(&parser, depth_outer));
+  EXPECT_THAT(parser.event(), Eq(XmlPullParser::Event::kEndDocument));
 }
 
+}  // namespace xml
 }  // namespace aapt
diff --git a/tools/aapt2/xml/XmlUtil.cpp b/tools/aapt2/xml/XmlUtil.cpp
index c1186e8..0a622b2 100644
--- a/tools/aapt2/xml/XmlUtil.cpp
+++ b/tools/aapt2/xml/XmlUtil.cpp
@@ -16,20 +16,20 @@
 
 #include "xml/XmlUtil.h"
 
+#include <algorithm>
 #include <string>
 
 #include "util/Maybe.h"
 #include "util/Util.h"
+#include "xml/XmlDom.h"
 
-using android::StringPiece;
+using ::android::StringPiece;
 
 namespace aapt {
 namespace xml {
 
-std::string BuildPackageNamespace(const StringPiece& package,
-                                  bool private_reference) {
-  std::string result =
-      private_reference ? kSchemaPrivatePrefix : kSchemaPublicPrefix;
+std::string BuildPackageNamespace(const StringPiece& package, bool private_reference) {
+  std::string result = private_reference ? kSchemaPrivatePrefix : kSchemaPublicPrefix;
   result.append(package.data(), package.size());
   return result;
 }
@@ -39,8 +39,7 @@
   if (util::StartsWith(namespace_uri, kSchemaPublicPrefix)) {
     StringPiece schema_prefix = kSchemaPublicPrefix;
     StringPiece package = namespace_uri;
-    package = package.substr(schema_prefix.size(),
-                             package.size() - schema_prefix.size());
+    package = package.substr(schema_prefix.size(), package.size() - schema_prefix.size());
     if (package.empty()) {
       return {};
     }
@@ -49,8 +48,7 @@
   } else if (util::StartsWith(namespace_uri, kSchemaPrivatePrefix)) {
     StringPiece schema_prefix = kSchemaPrivatePrefix;
     StringPiece package = namespace_uri;
-    package = package.substr(schema_prefix.size(),
-                             package.size() - schema_prefix.size());
+    package = package.substr(schema_prefix.size(), package.size() - schema_prefix.size());
     if (package.empty()) {
       return {};
     }
@@ -76,5 +74,33 @@
   }
 }
 
+namespace {
+
+class ToolsNamespaceRemover : public Visitor {
+ public:
+  using Visitor::Visit;
+
+  void Visit(Element* el) override {
+    auto new_end =
+        std::remove_if(el->namespace_decls.begin(), el->namespace_decls.end(),
+                       [](const NamespaceDecl& decl) -> bool { return decl.uri == kSchemaTools; });
+    el->namespace_decls.erase(new_end, el->namespace_decls.end());
+
+    auto new_attr_end = std::remove_if(
+        el->attributes.begin(), el->attributes.end(),
+        [](const Attribute& attr) -> bool { return attr.namespace_uri == kSchemaTools; });
+    el->attributes.erase(new_attr_end, el->attributes.end());
+
+    Visitor::Visit(el);
+  }
+};
+
+}  // namespace
+
+void StripAndroidStudioAttributes(Element* el) {
+  ToolsNamespaceRemover remover;
+  el->Accept(&remover);
+}
+
 }  // namespace xml
 }  // namespace aapt
diff --git a/tools/aapt2/xml/XmlUtil.h b/tools/aapt2/xml/XmlUtil.h
index 4eb359a..592a604f 100644
--- a/tools/aapt2/xml/XmlUtil.h
+++ b/tools/aapt2/xml/XmlUtil.h
@@ -78,6 +78,12 @@
 // package declaration was private.
 void ResolvePackage(const IPackageDeclStack* decl_stack, Reference* in_ref);
 
+class Element;
+
+// Strips out any attributes in the http://schemas.android.com/tools namespace, which is owned by
+// Android Studio and should not make it to the final APK.
+void StripAndroidStudioAttributes(Element* el);
+
 }  // namespace xml
 }  // namespace aapt
 
diff --git a/tools/bit/Android.bp b/tools/bit/Android.bp
index 258e9b5..a806271 100644
--- a/tools/bit/Android.bp
+++ b/tools/bit/Android.bp
@@ -30,6 +30,11 @@
         "util.cpp",
     ],
 
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
     static_libs: [
         "libexpat",
         "libinstrumentation",
diff --git a/tools/bit/adb.cpp b/tools/bit/adb.cpp
index c8faf5c..fa7d3d4 100644
--- a/tools/bit/adb.cpp
+++ b/tools/bit/adb.cpp
@@ -302,7 +302,9 @@
     print_command(cmd);
 
     int fds[2];
-    pipe(fds);
+    if (0 != pipe(fds)) {
+        return errno;
+    }
 
     pid_t pid = fork();
 
diff --git a/tools/bit/command.cpp b/tools/bit/command.cpp
index 9a8449b..f95ea11 100644
--- a/tools/bit/command.cpp
+++ b/tools/bit/command.cpp
@@ -105,7 +105,9 @@
     }
 
     int fds[2];
-    pipe(fds);
+    if (0 != pipe(fds)) {
+        return string();
+    }
 
     pid_t pid = fork();
 
@@ -187,7 +189,7 @@
 int
 exec_with_path_search(const char* prog, char const* const* argv, char const* const* envp)
 {
-    if (prog[0] == '/') {
+    if (strchr(prog, '/') != NULL) {
         return execve(prog, (char*const*)argv, (char*const*)envp);
     } else {
         char* pathEnv = strdup(getenv("PATH"));
diff --git a/tools/bit/main.cpp b/tools/bit/main.cpp
index 91ca514..a71cea1 100644
--- a/tools/bit/main.cpp
+++ b/tools/bit/main.cpp
@@ -596,6 +596,15 @@
     }
 }
 
+static void
+chdir_or_exit(const char *path) {
+    // TODO: print_command("cd", path);
+    if (0 != chdir(path)) {
+        print_error("Error: Could not chdir: %s", path);
+        exit(1);
+    }
+}
+
 /**
  * Run the build, install, and test actions.
  */
@@ -614,12 +623,12 @@
     const string buildProduct = get_required_env("TARGET_PRODUCT", false);
     const string buildVariant = get_required_env("TARGET_BUILD_VARIANT", false);
     const string buildType = get_required_env("TARGET_BUILD_TYPE", false);
-    const string buildDevice = get_build_var(buildTop, "TARGET_DEVICE", false);
-    const string buildId = get_build_var(buildTop, "BUILD_ID", false);
-    const string buildOut = get_out_dir();
 
-    // TODO: print_command("cd", buildTop.c_str());
-    chdir(buildTop.c_str());
+    chdir_or_exit(buildTop.c_str());
+
+    const string buildDevice = get_build_var("TARGET_DEVICE", false);
+    const string buildId = get_build_var("BUILD_ID", false);
+    const string buildOut = get_out_dir();
 
     // Get the modules for the targets
     map<string,Module> modules;
@@ -999,7 +1008,7 @@
     const string buildProduct = get_required_env("TARGET_PRODUCT", false);
     const string buildOut = get_out_dir();
 
-    chdir(buildTop.c_str());
+    chdir_or_exit(buildTop.c_str());
 
     string buildDevice = sniff_device_name(buildOut, buildProduct);
 
diff --git a/tools/bit/make.cpp b/tools/bit/make.cpp
index a800241..5a9ab22 100644
--- a/tools/bit/make.cpp
+++ b/tools/bit/make.cpp
@@ -36,31 +36,16 @@
 
 map<string,string> g_buildVars;
 
-static unsigned int
-get_thread_count()
-{
-    unsigned int threads = std::thread::hardware_concurrency();
-    // Guess if the value cannot be computed
-    return threads == 0 ? 4 : static_cast<unsigned int>(threads * 1.3f);
-}
-
 string
-get_build_var(const string& buildTop, const string& name, bool quiet)
+get_build_var(const string& name, bool quiet)
 {
     int err;
 
     map<string,string>::iterator it = g_buildVars.find(name);
     if (it == g_buildVars.end()) {
-        Command cmd("make");
-        cmd.AddArg("--no-print-directory");
-        cmd.AddArg(string("-j") + std::to_string(get_thread_count()));
-        cmd.AddArg("-C");
-        cmd.AddArg(buildTop);
-        cmd.AddArg("-f");
-        cmd.AddArg("build/core/config.mk");
-        cmd.AddArg(string("dumpvar-") + name);
-        cmd.AddEnv("CALLED_FROM_SETUP", "true");
-        cmd.AddEnv("BUILD_SYSTEM", "build/core");
+        Command cmd("build/soong/soong_ui.bash");
+        cmd.AddArg("--dumpvar-mode");
+        cmd.AddArg(name);
 
         string output = trim(get_command_output(cmd, &err, quiet));
         if (err == 0) {
@@ -182,7 +167,7 @@
         for (ssize_t i = module.classes.size() - 1; i >= 0; i--) {
             string cl = module.classes[i];
             if (!(cl == "JAVA_LIBRARIES" || cl == "EXECUTABLES" || cl == "SHARED_LIBRARIES"
-                    || cl == "APPS")) {
+                    || cl == "APPS" || cl == "NATIVE_TESTS")) {
                 module.classes.erase(module.classes.begin() + i);
             }
         }
@@ -208,10 +193,8 @@
 int
 build_goals(const vector<string>& goals)
 {
-    Command cmd("make");
-    cmd.AddArg(string("-j") + std::to_string(get_thread_count()));
-    cmd.AddArg("-f");
-    cmd.AddArg("build/core/main.mk");
+    Command cmd("build/soong/soong_ui.bash");
+    cmd.AddArg("--make-mode");
     for (size_t i=0; i<goals.size(); i++) {
         cmd.AddArg(goals[i]);
     }
diff --git a/tools/bit/make.h b/tools/bit/make.h
index bb83c6e..1c9504d 100644
--- a/tools/bit/make.h
+++ b/tools/bit/make.h
@@ -31,7 +31,7 @@
     vector<string> installed;
 };
 
-string get_build_var(const string& buildTop, const string& name, bool quiet);
+string get_build_var(const string& name, bool quiet);
 
 /**
  * Poke around in the out directory and try to find a device name that matches
diff --git a/tools/bit/util.cpp b/tools/bit/util.cpp
index fc93bcb..9223931 100644
--- a/tools/bit/util.cpp
+++ b/tools/bit/util.cpp
@@ -101,7 +101,6 @@
 void
 get_directory_contents(const string& name, map<string,FileInfo>* results)
 {
-    int err;
     DIR* dir = opendir(name.c_str());
     if (dir == NULL) {
         return;
@@ -241,7 +240,9 @@
     fseek(file, 0, SEEK_SET);
 
     char* buf = (char*)malloc(size);
-    fread(buf, 1, size, file);
+    if ((size_t) size != fread(buf, 1, size, file)) {
+        return string();
+    }
 
     string result(buf, size);
 
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index c6ad4c2a..dcb90e4 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -13,6 +13,7 @@
 
 LANG_TO_SCRIPT = {
     'as': 'Beng',
+    'be': 'Cyrl',
     'bg': 'Cyrl',
     'bn': 'Beng',
     'cu': 'Cyrl',
@@ -33,6 +34,7 @@
     'ja': 'Jpan',
     'kn': 'Knda',
     'ko': 'Kore',
+    'la': 'Latn',
     'ml': 'Mlym',
     'mn': 'Cyrl',
     'mr': 'Deva',
diff --git a/tools/incident_report/Android.bp b/tools/incident_report/Android.bp
index ab55dbd..f2d0d0f 100644
--- a/tools/incident_report/Android.bp
+++ b/tools/incident_report/Android.bp
@@ -31,5 +31,5 @@
         "libprotobuf-cpp-full",
     ],
 
-    cflags: ["-Wno-unused-parameter"],
+    cflags: ["-Wall", "-Werror"],
 }
diff --git a/tools/incident_report/main.cpp b/tools/incident_report/main.cpp
index d4ad340..bd1b973 100644
--- a/tools/incident_report/main.cpp
+++ b/tools/incident_report/main.cpp
@@ -45,8 +45,9 @@
 read_length_delimited(CodedInputStream* in, uint32 fieldId, Descriptor const* descriptor,
         GenericMessage* message)
 {
-    uint32 size;
+    uint32_t size;
     if (!in->ReadVarint32(&size)) {
+        fprintf(stderr, "Fail to read size of %s\n", descriptor->name().c_str());
         return false;
     }
 
@@ -68,6 +69,9 @@
                 message->addString(fieldId, str);
                 return true;
             } else {
+                fprintf(stderr, "Fail to read string of field %s, expect size %d, read %lu\n",
+                        field->full_name().c_str(), size, str.size());
+                fprintf(stderr, "String read \"%s\"\n", str.c_str());
                 return false;
             }
         } else if (type == FieldDescriptor::TYPE_BYTES) {
@@ -97,8 +101,8 @@
                     message->addInt64(fieldId, value64);
                     break;
                 } else {
-                    fprintf(stderr, "bad VARINT: 0x%x (%d) at index %d\n", tag, tag,
-                                                    in->CurrentPosition());
+                    fprintf(stderr, "bad VARINT: 0x%x (%d) at index %d of field %s\n",
+                            tag, tag, in->CurrentPosition(), descriptor->name().c_str());
                     return false;
                 }
             case WireFormatLite::WIRETYPE_FIXED64:
@@ -106,14 +110,14 @@
                     message->addInt64(fieldId, value64);
                     break;
                 } else {
-                    fprintf(stderr, "bad VARINT: 0x%x (%d) at index %d\n", tag, tag,
-                            in->CurrentPosition());
+                    fprintf(stderr, "bad VARINT: 0x%x (%d) at index %d of field %s\n",
+                            tag, tag, in->CurrentPosition(), descriptor->name().c_str());
                     return false;
                 }
             case WireFormatLite::WIRETYPE_LENGTH_DELIMITED:
                 if (!read_length_delimited(in, fieldId, descriptor, message)) {
-                    fprintf(stderr, "bad LENGTH_DELIMITED: 0x%x (%d) at index %d\n",
-                            tag, tag, in->CurrentPosition());
+                    fprintf(stderr, "bad LENGTH_DELIMITED: 0x%x (%d) at index %d of field %s\n",
+                            tag, tag, in->CurrentPosition(), descriptor->name().c_str());
                     return false;
                 }
                 break;
@@ -122,13 +126,13 @@
                     message->addInt32(fieldId, value32);
                     break;
                 } else {
-                    fprintf(stderr, "bad FIXED32: 0x%x (%d) at index %d\n", tag, tag,
-                            in->CurrentPosition());
+                    fprintf(stderr, "bad FIXED32: 0x%x (%d) at index %d of field %s\n",
+                            tag, tag, in->CurrentPosition(), descriptor->name().c_str());
                     return false;
                 }
             default:
-                fprintf(stderr, "bad tag: 0x%x (%d) at index %d\n", tag, tag,
-                        in->CurrentPosition());
+                fprintf(stderr, "bad tag: 0x%x (%d) at index %d of field %s\n", tag, tag,
+                        in->CurrentPosition(), descriptor->name().c_str());
                 return false;
         }
     }
@@ -153,7 +157,8 @@
                     out->printf("%f", *(float*)&node.value32);
                     break;
                 default:
-                    out->printf("(unexpected value32 %d (0x%x)", node.value32, node.value32);
+                    out->printf("(unexpected type %d: value32 %d (0x%x)",
+                                type, node.value32, node.value32);
                     break;
             }
             break;
@@ -194,7 +199,8 @@
                     }
                     break;
                 default:
-                    out->printf("(unexpected value64 %lld (0x%x))", node.value64, node.value64);
+                    out->printf("(unexpected type %d: value64 %lld (0x%x))",
+                                type, node.value64, node.value64);
                     break;
             }
             break;
diff --git a/tools/incident_report/printer.cpp b/tools/incident_report/printer.cpp
index bd660dd2..bff1025 100644
--- a/tools/incident_report/printer.cpp
+++ b/tools/incident_report/printer.cpp
@@ -70,7 +70,6 @@
 
     len = vsnprintf(mBuf, mBufSize, format, args);
     va_end(args);
-    bool truncated = (len >= mBufSize) && (reallocate(len) < len);
 
     va_start(args, format);
     len = vsnprintf(mBuf, mBufSize, format, args);
diff --git a/tools/incident_section_gen/Android.bp b/tools/incident_section_gen/Android.bp
index 1756e06..f07445a 100644
--- a/tools/incident_section_gen/Android.bp
+++ b/tools/incident_section_gen/Android.bp
@@ -22,6 +22,8 @@
     cflags: [
         "-g",
         "-O0",
+        "-Wall",
+        "-Werror",
     ],
     srcs: ["main.cpp"],
     shared_libs: [
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index 900690c..135df40 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -113,7 +113,7 @@
     return field->options().GetExtension(privacy).dest() == PrivacyFlags::default_instance().dest();
 }
 
-// Returns true if the descriptor doesn't have any non default privacy flags set, including its submessages
+// Returns false if the descriptor doesn't have any non default privacy flags set, including its submessages
 static bool generatePrivacyFlags(const Descriptor* descriptor, const char* alias, map<string, bool> &msgNames) {
     bool hasDefaultFlags[descriptor->field_count()];
     // iterate though its field and generate sub flags first
@@ -129,13 +129,18 @@
         };
 
         PrivacyFlags p = field->options().GetExtension(privacy);
-
         switch (field->type()) {
             case FieldDescriptor::TYPE_MESSAGE:
-                if (generatePrivacyFlags(field->message_type(), field_name, msgNames) &&
-                    isDefaultDest(field)) break;
-
-                printf("Privacy %s { %d, %d, %s_LIST, %d, NULL };\n", field_name, field->number(), field->type(), field_name, p.dest());
+                if (generatePrivacyFlags(field->message_type(), field_name, msgNames)) {
+                    printf("Privacy %s { %d, %d, %s_LIST, %d, NULL };\n", field_name, field->number(),
+                            field->type(), field_name, p.dest());
+                } else if (isDefaultDest(field)) {
+                    // don't create a new privacy if the value is default.
+                    break;
+                } else{
+                    printf("Privacy %s { %d, %d, NULL, %d, NULL };\n", field_name, field->number(),
+                            field->type(), p.dest());
+                }
                 hasDefaultFlags[i] = false;
                 break;
             case FieldDescriptor::TYPE_STRING:
@@ -147,12 +152,14 @@
                     printf("    \"%s\",\n", replaceAll(p.patterns(i), '\\', "\\\\").c_str());
                 }
                 printf("    NULL };\n");
-                printf("Privacy %s { %d, %d, NULL, %d, %s_patterns };\n", field_name, field->number(), field->type(), p.dest(), field_name);
+                printf("Privacy %s { %d, %d, NULL, %d, %s_patterns };\n", field_name, field->number(),
+                        field->type(), p.dest(), field_name);
                 hasDefaultFlags[i] = false;
                 break;
             default:
                 if (isDefaultDest(field)) break;
-                printf("Privacy %s { %d, %d, NULL, %d, NULL };\n", field_name, field->number(), field->type(), p.dest());
+                printf("Privacy %s { %d, %d, NULL, %d, NULL };\n", field_name, field->number(),
+                        field->type(), p.dest());
                 hasDefaultFlags[i] = false;
         }
         // add the field name to message map, true means it has default flags
@@ -163,14 +170,14 @@
     for (int i=0; i<descriptor->field_count(); i++) {
         allDefaults &= hasDefaultFlags[i];
     }
-    if (allDefaults) return true;
+    if (allDefaults) return false;
 
     emptyline();
 
     bool needConst = strcmp(alias, "PRIVACY_POLICY") == 0;
     int policyCount = 0;
 
-    printf("%s Privacy* %s_LIST[] = {\n", needConst ? "const" : "", alias);
+    printf("%sPrivacy* %s_LIST[] = {\n", needConst ? "const " : "", alias);
     for (int i=0; i<descriptor->field_count(); i++) {
         const FieldDescriptor* field = descriptor->field(i);
         if (hasDefaultFlags[i]) continue;
@@ -184,7 +191,7 @@
         printf("    NULL };\n");
     }
     emptyline();
-    return false;
+    return true;
 }
 
 static bool generateSectionListCpp(Descriptor const* descriptor) {
@@ -222,7 +229,7 @@
 
     // generates PRIVACY_POLICY
     map<string, bool> messageNames;
-    if (generatePrivacyFlags(descriptor, "PRIVACY_POLICY", messageNames)) {
+    if (!generatePrivacyFlags(descriptor, "PRIVACY_POLICY", messageNames)) {
         // if no privacy options set at all, define an empty list
         printf("const Privacy* PRIVACY_POLICY_LIST[] = {};\n");
         printf("const int PRIVACY_POLICY_COUNT = 0;\n");
diff --git a/tools/locked_region_code_injection/Android.mk b/tools/locked_region_code_injection/Android.mk
index 77d5163..bb5f4d6 100644
--- a/tools/locked_region_code_injection/Android.mk
+++ b/tools/locked_region_code_injection/Android.mk
@@ -6,10 +6,10 @@
 LOCAL_MODULE := lockedregioncodeinjection
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    asm-5.2 \
-    asm-commons-5.2 \
-    asm-tree-5.2 \
-    asm-analysis-5.2 \
+    asm-6.0_BETA \
+    asm-commons-6.0_BETA \
+    asm-tree-6.0_BETA \
+    asm-analysis-6.0_BETA \
     guava-21.0 \
 
 include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockFindingClassVisitor.java b/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockFindingClassVisitor.java
index 99ef8a7..a60f2a2 100644
--- a/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockFindingClassVisitor.java
+++ b/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockFindingClassVisitor.java
@@ -76,7 +76,7 @@
         private MethodVisitor chain;
 
         public LockFindingMethodVisitor(String owner, MethodNode mn, MethodVisitor chain) {
-            super(Opcodes.ASM5, mn);
+            super(Opcodes.ASM6, mn);
             assert owner != null;
             this.owner = owner;
             this.chain = chain;
diff --git a/tools/locked_region_code_injection/test/lockedregioncodeinjection/TestMain.java b/tools/locked_region_code_injection/test/lockedregioncodeinjection/TestMain.java
index b86954d..c408b9e 100644
--- a/tools/locked_region_code_injection/test/lockedregioncodeinjection/TestMain.java
+++ b/tools/locked_region_code_injection/test/lockedregioncodeinjection/TestMain.java
@@ -23,11 +23,14 @@
  * <code>
  * set -x
  *
+ * croot frameworks/base/tools/locked_region_code_injection
+ *
  * # Clean
+ * mkdir -p out
  * rm -fr out/*
  *
  * # Make booster
- * javac -cp lib/asm-all-5.2.jar src&#47;*&#47;*.java -d out/
+ * javac -cp lib/asm-6.0_BETA.jar:lib/asm-commons-6.0_BETA.jar:lib/asm-tree-6.0_BETA.jar:lib/asm-analysis-6.0_BETA.jar:lib/guava-21.0.jar src&#47;*&#47;*.java -d out/
  * pushd out
  * jar cfe lockedregioncodeinjection.jar lockedregioncodeinjection.Main *&#47;*.class
  * popd
@@ -40,7 +43,7 @@
  * popd
  *
  * # Run tool on unit tests.
- * java -ea -cp lib/asm-all-5.2.jar:out/lockedregioncodeinjection.jar \
+ * java -ea -cp lib/asm-6.0_BETA.jar:lib/asm-commons-6.0_BETA.jar:lib/asm-tree-6.0_BETA.jar:lib/asm-analysis-6.0_BETA.jar:lib/guava-21.0.jar:out/lockedregioncodeinjection.jar \
  *     lockedregioncodeinjection.Main \
  *     -i out/test_input.jar -o out/test_output.jar \
  *     --targets 'Llockedregioncodeinjection/TestTarget;' \
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
new file mode 100644
index 0000000..a910c62
--- /dev/null
+++ b/tools/stats_log_api_gen/Android.bp
@@ -0,0 +1,98 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// ==========================================================
+// Build the host executable: stats-log-api-gen
+// ==========================================================
+cc_binary_host {
+    name: "stats-log-api-gen",
+    srcs: [
+        "Collation.cpp",
+        "main.cpp",
+    ],
+
+    shared_libs: [
+        "libstats_proto_host",
+        "libprotobuf-cpp-full",
+    ],
+
+    proto: {
+        type: "full",
+    },
+}
+
+// ==========================================================
+// Build the host test executable: stats-log-api-gen
+// ==========================================================
+cc_test_host {
+    name: "stats-log-api-gen-test",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-g",
+        "-DUNIT_TEST",
+    ],
+    srcs: [
+        "Collation.cpp",
+        "test_collation.cpp",
+        "test.proto",
+    ],
+
+    static_libs: [
+        "libgmock_host",
+    ],
+
+    shared_libs: [
+        "libstats_proto_host",
+    ],
+
+    proto: {
+        type: "full",
+    },
+}
+
+// ==========================================================
+// Native library
+// ==========================================================
+genrule {
+    name: "statslog.h",
+    tools: ["stats-log-api-gen"],
+    cmd: "$(location stats-log-api-gen) --header $(genDir)/statslog.h",
+    out: [
+        "statslog.h",
+    ],
+}
+
+genrule {
+    name: "statslog.cpp",
+    tools: ["stats-log-api-gen"],
+    cmd: "$(location stats-log-api-gen) --cpp $(genDir)/statslog.cpp",
+    out: [
+        "statslog.cpp",
+    ],
+}
+
+cc_library_shared {
+    name: "libstatslog",
+    generated_sources: ["statslog.cpp"],
+    generated_headers: ["statslog.h"],
+    export_generated_headers: ["statslog.h"],
+    shared_libs: [
+        "liblog",
+    ],
+}
+
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
new file mode 100644
index 0000000..5d29268
--- /dev/null
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Collation.h"
+
+#include <stdio.h>
+#include <map>
+
+namespace android {
+namespace stats_log_api_gen {
+
+using google::protobuf::FieldDescriptor;
+using google::protobuf::FileDescriptor;
+using google::protobuf::SourceLocation;
+using std::map;
+
+
+//
+// AtomDecl class
+//
+
+AtomDecl::AtomDecl()
+    :code(0),
+     name()
+{
+}
+
+AtomDecl::AtomDecl(const AtomDecl& that)
+    :code(that.code),
+     name(that.name),
+     message(that.message),
+     fields(that.fields)
+{
+}
+
+AtomDecl::AtomDecl(int c, const string& n, const string& m)
+    :code(c),
+     name(n),
+     message(m)
+{
+}
+
+AtomDecl::~AtomDecl()
+{
+}
+
+
+/**
+ * Print an error message for a FieldDescriptor, including the file name and line number.
+ */
+static void
+print_error(const FieldDescriptor* field, const char* format, ...)
+{
+    const Descriptor* message = field->containing_type();
+    const FileDescriptor* file = message->file();
+
+    SourceLocation loc;
+    if (field->GetSourceLocation(&loc)) {
+        // TODO: this will work if we can figure out how to pass --include_source_info to protoc
+        fprintf(stderr, "%s:%d: ", file->name().c_str(), loc.start_line);
+    } else {
+        fprintf(stderr, "%s: ", file->name().c_str());
+    }
+    va_list args;
+    va_start(args, format);
+    vfprintf(stderr, format, args);
+    va_end (args);
+}
+
+/**
+ * Convert a protobuf type into a java type.
+ */
+static java_type_t
+java_type(const FieldDescriptor* field)
+{
+    int protoType = field->type();
+    switch (protoType) {
+        case FieldDescriptor::TYPE_DOUBLE:
+            return JAVA_TYPE_DOUBLE;
+        case FieldDescriptor::TYPE_FLOAT:
+            return JAVA_TYPE_FLOAT;
+        case FieldDescriptor::TYPE_INT64:
+            return JAVA_TYPE_LONG;
+        case FieldDescriptor::TYPE_UINT64:
+            return JAVA_TYPE_LONG;
+        case FieldDescriptor::TYPE_INT32:
+            return JAVA_TYPE_INT;
+        case FieldDescriptor::TYPE_FIXED64:
+            return JAVA_TYPE_LONG;
+        case FieldDescriptor::TYPE_FIXED32:
+            return JAVA_TYPE_INT;
+        case FieldDescriptor::TYPE_BOOL:
+            return JAVA_TYPE_BOOLEAN;
+        case FieldDescriptor::TYPE_STRING:
+            return JAVA_TYPE_STRING;
+        case FieldDescriptor::TYPE_GROUP:
+            return JAVA_TYPE_UNKNOWN;
+        case FieldDescriptor::TYPE_MESSAGE:
+            // TODO: not the final package name
+            if (field->message_type()->full_name() == "android.os.statsd.WorkSource") {
+                return JAVA_TYPE_WORK_SOURCE;
+            } else {
+                return JAVA_TYPE_OBJECT;
+            }
+        case FieldDescriptor::TYPE_BYTES:
+            return JAVA_TYPE_BYTE_ARRAY;
+        case FieldDescriptor::TYPE_UINT32:
+            return JAVA_TYPE_INT;
+        case FieldDescriptor::TYPE_ENUM:
+            return JAVA_TYPE_INT;
+        case FieldDescriptor::TYPE_SFIXED32:
+            return JAVA_TYPE_INT;
+        case FieldDescriptor::TYPE_SFIXED64:
+            return JAVA_TYPE_LONG;
+        case FieldDescriptor::TYPE_SINT32:
+            return JAVA_TYPE_INT;
+        case FieldDescriptor::TYPE_SINT64:
+            return JAVA_TYPE_LONG;
+        default:
+            return JAVA_TYPE_UNKNOWN;
+    }
+}
+
+/**
+ * Gather the info about the atoms.
+ */
+int
+collate_atoms(const Descriptor* descriptor, Atoms* atoms)
+{
+    int errorCount = 0;
+    const bool dbg = false;
+
+    for (int i=0; i<descriptor->field_count(); i++) {
+        const FieldDescriptor* atomField = descriptor->field(i);
+
+        if (dbg) {
+            printf("   %s (%d)\n", atomField->name().c_str(), atomField->number());
+        }
+
+        // StatsEvent only has one oneof, which contains only messages. Don't allow other types.
+        if (atomField->type() != FieldDescriptor::TYPE_MESSAGE) {
+            print_error(atomField,
+                    "Bad type for atom. StatsEvent can only have message type fields: %s\n",
+                    atomField->name().c_str());
+            errorCount++;
+            continue;
+        }
+
+        const Descriptor* atom = atomField->message_type();
+
+        // Build a sorted list of the fields. Descriptor has them in source file order.
+        map<int,const FieldDescriptor*> fields;
+        for (int j=0; j<atom->field_count(); j++) {
+            const FieldDescriptor* field = atom->field(j);
+            fields[field->number()] = field;
+        }
+
+        // Check that the parameters start at 1 and go up sequentially.
+        int expectedNumber = 1;
+        for (map<int,const FieldDescriptor*>::const_iterator it = fields.begin();
+                it != fields.end(); it++) {
+            const int number = it->first;
+            const FieldDescriptor* field = it->second;
+            if (number != expectedNumber) {
+                print_error(field, "Fields must be numbered consecutively starting at 1:"
+                        " '%s' is %d but should be %d\n",
+                        field->name().c_str(), number, expectedNumber);
+                errorCount++;
+                expectedNumber = number;
+                continue;
+            }
+            expectedNumber++;
+        }
+
+        // Check that only allowed types are present. Remove any invalid ones.
+        for (map<int,const FieldDescriptor*>::const_iterator it = fields.begin();
+                it != fields.end(); it++) {
+            const FieldDescriptor* field = it->second;
+
+            java_type_t javaType = java_type(field);
+
+            if (javaType == JAVA_TYPE_UNKNOWN) {
+                print_error(field, "Unkown type for field: %s\n", field->name().c_str());
+                errorCount++;
+                continue;
+            } else if (javaType == JAVA_TYPE_OBJECT) {
+                // Allow WorkSources, but only at position 1.
+                print_error(field, "Message type not allowed for field: %s\n",
+                        field->name().c_str());
+                errorCount++;
+                continue;
+            } else if (javaType == JAVA_TYPE_BYTE_ARRAY) {
+                print_error(field, "Raw bytes type not allowed for field: %s\n",
+                        field->name().c_str());
+                errorCount++;
+                continue;
+            }
+
+        }
+
+        // Check that if there's a WorkSource, it's at position 1.
+        for (map<int,const FieldDescriptor*>::const_iterator it = fields.begin();
+                it != fields.end(); it++) {
+            int number = it->first;
+            if (number != 1) {
+                const FieldDescriptor* field = it->second;
+                java_type_t javaType = java_type(field);
+                if (javaType == JAVA_TYPE_WORK_SOURCE) {
+                    print_error(field, "WorkSource fields must have field id 1, in message: '%s'\n",
+                           atom->name().c_str());
+                    errorCount++;
+                }
+            }
+        }
+
+        AtomDecl atomDecl(atomField->number(), atomField->name(), atom->name());
+
+        // Build the type signature
+        vector<java_type_t> signature;
+        for (map<int,const FieldDescriptor*>::const_iterator it = fields.begin();
+                it != fields.end(); it++) {
+            const FieldDescriptor* field = it->second;
+            java_type_t javaType = java_type(field);
+
+            atomDecl.fields.push_back(AtomField(field->name(), javaType));
+            signature.push_back(javaType);
+        }
+
+        atoms->signatures.insert(signature);
+        atoms->decls.insert(atomDecl);
+    }
+
+    if (dbg) {
+        printf("signatures = [\n");
+        for (set<vector<java_type_t>>::const_iterator it = atoms->signatures.begin();
+                it != atoms->signatures.end(); it++) {
+            printf("   ");
+            for (vector<java_type_t>::const_iterator jt = it->begin(); jt != it->end(); jt++) {
+                printf(" %d", (int)*jt);
+            }
+            printf("\n");
+        }
+        printf("]\n");
+    }
+
+    return errorCount;
+}
+
+}  // namespace stats_log_api_gen
+}  // namespace android
+
+
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
new file mode 100644
index 0000000..50af7ea
--- /dev/null
+++ b/tools/stats_log_api_gen/Collation.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_STATS_LOG_API_GEN_COLLATION_H
+#define ANDROID_STATS_LOG_API_GEN_COLLATION_H
+
+
+#include <google/protobuf/descriptor.h>
+
+#include <set>
+#include <vector>
+
+namespace android {
+namespace stats_log_api_gen {
+
+using std::set;
+using std::string;
+using std::vector;
+using google::protobuf::Descriptor;
+
+/**
+ * The types for atom parameters.
+ */
+typedef enum {
+    JAVA_TYPE_UNKNOWN = 0,
+
+    JAVA_TYPE_WORK_SOURCE = 1,
+    JAVA_TYPE_BOOLEAN = 2,
+    JAVA_TYPE_INT = 3,
+    JAVA_TYPE_LONG = 4,
+    JAVA_TYPE_FLOAT = 5,
+    JAVA_TYPE_DOUBLE = 6,
+    JAVA_TYPE_STRING = 7,
+
+    JAVA_TYPE_OBJECT = -1,
+    JAVA_TYPE_BYTE_ARRAY = -2,
+} java_type_t;
+
+
+/**
+ * The name and type for an atom field.
+ */
+struct AtomField {
+    string name;
+    java_type_t javaType;
+
+    inline AtomField() :name(), javaType(JAVA_TYPE_UNKNOWN) {}
+    inline AtomField(const AtomField& that) :name(that.name), javaType(that.javaType) {}
+    inline AtomField(string n, java_type_t jt) :name(n), javaType(jt) {}
+    inline ~AtomField() {}
+};
+
+/**
+ * The name and code for an atom.
+ */
+struct AtomDecl {
+    int code;
+    string name;
+
+    string message;
+    vector<AtomField> fields;
+
+    AtomDecl();
+    AtomDecl(const AtomDecl& that);
+    AtomDecl(int code, const string& name, const string& message);
+    ~AtomDecl();
+
+    inline bool operator<(const AtomDecl& that) const {
+        return (code == that.code) ? (name < that.name) : (code < that.code);
+    }
+};
+
+struct Atoms {
+    set<vector<java_type_t>> signatures;
+    set<AtomDecl> decls;
+};
+
+/**
+ * Gather the information about the atoms.  Returns the number of errors.
+ */
+int collate_atoms(const Descriptor* descriptor, Atoms* atoms);
+
+}  // namespace stats_log_api_gen
+}  // namespace android
+
+
+#endif // ANDROID_STATS_LOG_API_GEN_COLLATION_H
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
new file mode 100644
index 0000000..aaea4f6
--- /dev/null
+++ b/tools/stats_log_api_gen/main.cpp
@@ -0,0 +1,623 @@
+
+
+#include "Collation.h"
+
+#include "frameworks/base/cmds/statsd/src/stats_events.pb.h"
+
+#include <set>
+#include <vector>
+
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+using namespace google::protobuf;
+using namespace std;
+
+namespace android {
+namespace stats_log_api_gen {
+
+using android::os::statsd::StatsEvent;
+
+// TODO: Support WorkSources
+
+/**
+ * Turn lower and camel case into upper case with underscores.
+ */
+static string
+make_constant_name(const string& str)
+{
+    string result;
+    const int N = str.size();
+    bool underscore_next = false;
+    for (int i=0; i<N; i++) {
+        char c = str[i];
+        if (c >= 'A' && c <= 'Z') {
+            if (underscore_next) {
+                result += '_';
+                underscore_next = false;
+            }
+        } else if (c >= 'a' && c <= 'z') {
+            c = 'A' + c - 'a';
+            underscore_next = true;
+        } else if (c == '_') {
+            underscore_next = false;
+        }
+        result += c;
+    }
+    return result;
+}
+
+static const char*
+cpp_type_name(java_type_t type)
+{
+    switch (type) {
+        case JAVA_TYPE_BOOLEAN:
+            return "bool";
+        case JAVA_TYPE_INT:
+            return "int32_t";
+        case JAVA_TYPE_LONG:
+            return "int64_t";
+        case JAVA_TYPE_FLOAT:
+            return "float";
+        case JAVA_TYPE_DOUBLE:
+            return "double";
+        case JAVA_TYPE_STRING:
+            return "char const*";
+        default:
+            return "UNKNOWN";
+    }
+}
+
+static const char*
+java_type_name(java_type_t type)
+{
+    switch (type) {
+        case JAVA_TYPE_BOOLEAN:
+            return "boolean";
+        case JAVA_TYPE_INT:
+            return "int";
+        case JAVA_TYPE_LONG:
+            return "long";
+        case JAVA_TYPE_FLOAT:
+            return "float";
+        case JAVA_TYPE_DOUBLE:
+            return "double";
+        case JAVA_TYPE_STRING:
+            return "java.lang.String";
+        default:
+            return "UNKNOWN";
+    }
+}
+
+static int
+write_stats_log_cpp(FILE* out, const Atoms& atoms)
+{
+    int errorCount;
+
+    // Print prelude
+    fprintf(out, "// This file is autogenerated\n");
+    fprintf(out, "\n");
+
+    fprintf(out, "#include <log/log_event_list.h>\n");
+    fprintf(out, "#include <log/log.h>\n");
+    fprintf(out, "#include <statslog.h>\n");
+    fprintf(out, "\n");
+
+    fprintf(out, "namespace android {\n");
+    fprintf(out, "namespace util {\n");
+
+    // Print write methods
+    fprintf(out, "\n");
+    for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
+            signature != atoms.signatures.end(); signature++) {
+        int argIndex;
+
+        fprintf(out, "void\n");
+        fprintf(out, "stats_write(int code");
+        argIndex = 1;
+        for (vector<java_type_t>::const_iterator arg = signature->begin();
+                arg != signature->end(); arg++) {
+            fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
+            argIndex++;
+        }
+        fprintf(out, ")\n");
+
+        fprintf(out, "{\n");
+        argIndex = 1;
+        fprintf(out, "    android_log_event_list event(code);\n");
+        for (vector<java_type_t>::const_iterator arg = signature->begin();
+                arg != signature->end(); arg++) {
+            if (*arg == JAVA_TYPE_STRING) {
+                fprintf(out, "    if (arg%d == NULL) {\n", argIndex);
+                fprintf(out, "        arg%d = \"\";\n", argIndex);
+                fprintf(out, "    }\n");
+            }
+            fprintf(out, "    event << arg%d;\n", argIndex);
+            argIndex++;
+        }
+
+        fprintf(out, "    event.write(LOG_ID_STATS);\n");
+        fprintf(out, "}\n");
+        fprintf(out, "\n");
+    }
+
+    // Print footer
+    fprintf(out, "\n");
+    fprintf(out, "} // namespace util\n");
+    fprintf(out, "} // namespace android\n");
+
+    return 0;
+}
+
+
+static int
+write_stats_log_header(FILE* out, const Atoms& atoms)
+{
+    int errorCount;
+
+    // Print prelude
+    fprintf(out, "// This file is autogenerated\n");
+    fprintf(out, "\n");
+    fprintf(out, "#pragma once\n");
+    fprintf(out, "\n");
+    fprintf(out, "#include <stdint.h>\n");
+    fprintf(out, "\n");
+
+    fprintf(out, "namespace android {\n");
+    fprintf(out, "namespace util {\n");
+    fprintf(out, "\n");
+    fprintf(out, "/*\n");
+    fprintf(out, " * API For logging statistics events.\n");
+    fprintf(out, " */\n");
+    fprintf(out, "\n");
+    fprintf(out, "/**\n");
+    fprintf(out, " * Constants for event codes.\n");
+    fprintf(out, " */\n");
+    fprintf(out, "enum {\n");
+
+    size_t i = 0;
+    // Print constants
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+            atom != atoms.decls.end(); atom++) {
+        string constant = make_constant_name(atom->name);
+        fprintf(out, "\n");
+        fprintf(out, "    /**\n");
+        fprintf(out, "     * %s %s\n", atom->message.c_str(), atom->name.c_str());
+        fprintf(out, "     * Usage: stats_write(StatsLog.%s", constant.c_str());
+        for (vector<AtomField>::const_iterator field = atom->fields.begin();
+                field != atom->fields.end(); field++) {
+            fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
+        }
+        fprintf(out, ");\n");
+        fprintf(out, "     */\n");
+        char const* const comma = (i == atoms.decls.size() - 1) ? "" : ",";
+        fprintf(out, "    %s = %d%s\n", constant.c_str(), atom->code, comma);
+        i++;
+    }
+    fprintf(out, "\n");
+    fprintf(out, "};\n");
+    fprintf(out, "\n");
+
+    // Print write methods
+    fprintf(out, "//\n");
+    fprintf(out, "// Write methods\n");
+    fprintf(out, "//\n");
+    for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
+            signature != atoms.signatures.end(); signature++) {
+
+        fprintf(out, "void stats_write(int code");
+        int argIndex = 1;
+        for (vector<java_type_t>::const_iterator arg = signature->begin();
+                arg != signature->end(); arg++) {
+            fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
+            argIndex++;
+        }
+        fprintf(out, ");\n");
+    }
+
+    fprintf(out, "\n");
+    fprintf(out, "} // namespace util\n");
+    fprintf(out, "} // namespace android\n");
+
+    return 0;
+}
+
+static int
+write_stats_log_java(FILE* out, const Atoms& atoms)
+{
+    int errorCount;
+
+    // Print prelude
+    fprintf(out, "// This file is autogenerated\n");
+    fprintf(out, "\n");
+    fprintf(out, "package android.util;\n");
+    fprintf(out, "\n");
+    fprintf(out, "\n");
+    fprintf(out, "/**\n");
+    fprintf(out, " * API For logging statistics events.\n");
+    fprintf(out, " * @hide\n");
+    fprintf(out, " */\n");
+    fprintf(out, "public final class StatsLog {\n");
+    fprintf(out, "    // Constants for event codes.\n");
+
+    // Print constants
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+            atom != atoms.decls.end(); atom++) {
+        string constant = make_constant_name(atom->name);
+        fprintf(out, "\n");
+        fprintf(out, "    /**\n");
+        fprintf(out, "     * %s %s\n", atom->message.c_str(), atom->name.c_str());
+        fprintf(out, "     * Usage: StatsLog.write(StatsLog.%s", constant.c_str());
+        for (vector<AtomField>::const_iterator field = atom->fields.begin();
+                field != atom->fields.end(); field++) {
+            fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str());
+        }
+        fprintf(out, ");\n");
+        fprintf(out, "     */\n");
+        fprintf(out, "    public static final int %s = %d;\n", constant.c_str(), atom->code);
+    }
+    fprintf(out, "\n");
+
+    // Print write methods
+    fprintf(out, "    // Write methods\n");
+    for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
+            signature != atoms.signatures.end(); signature++) {
+        fprintf(out, "    public static native void write(int code");
+        int argIndex = 1;
+        for (vector<java_type_t>::const_iterator arg = signature->begin();
+                arg != signature->end(); arg++) {
+            fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
+            argIndex++;
+        }
+        fprintf(out, ");\n");
+    }
+
+    fprintf(out, "}\n");
+
+    return 0;
+}
+
+static const char*
+jni_type_name(java_type_t type)
+{
+    switch (type) {
+        case JAVA_TYPE_BOOLEAN:
+            return "jboolean";
+        case JAVA_TYPE_INT:
+            return "jint";
+        case JAVA_TYPE_LONG:
+            return "jlong";
+        case JAVA_TYPE_FLOAT:
+            return "jfloat";
+        case JAVA_TYPE_DOUBLE:
+            return "jdouble";
+        case JAVA_TYPE_STRING:
+            return "jstring";
+        default:
+            return "UNKNOWN";
+    }
+}
+
+static string
+jni_function_name(const vector<java_type_t>& signature)
+{
+    string result("StatsLog_write");
+    for (vector<java_type_t>::const_iterator arg = signature.begin();
+            arg != signature.end(); arg++) {
+        switch (*arg) {
+            case JAVA_TYPE_BOOLEAN:
+                result += "_boolean";
+                break;
+            case JAVA_TYPE_INT:
+                result += "_int";
+                break;
+            case JAVA_TYPE_LONG:
+                result += "_long";
+                break;
+            case JAVA_TYPE_FLOAT:
+                result += "_float";
+                break;
+            case JAVA_TYPE_DOUBLE:
+                result += "_double";
+                break;
+            case JAVA_TYPE_STRING:
+                result += "_String";
+                break;
+            default:
+                result += "_UNKNOWN";
+                break;
+        }
+    }
+    return result;
+}
+
+static const char*
+java_type_signature(java_type_t type)
+{
+    switch (type) {
+        case JAVA_TYPE_BOOLEAN:
+            return "Z";
+        case JAVA_TYPE_INT:
+            return "I";
+        case JAVA_TYPE_LONG:
+            return "J";
+        case JAVA_TYPE_FLOAT:
+            return "F";
+        case JAVA_TYPE_DOUBLE:
+            return "D";
+        case JAVA_TYPE_STRING:
+            return "Ljava/lang/String;";
+        default:
+            return "UNKNOWN";
+    }
+}
+
+static string
+jni_function_signature(const vector<java_type_t>& signature)
+{
+    string result("(I");
+    for (vector<java_type_t>::const_iterator arg = signature.begin();
+            arg != signature.end(); arg++) {
+        result += java_type_signature(*arg);
+    }
+    result += ")V";
+    return result;
+}
+
+static int
+write_stats_log_jni(FILE* out, const Atoms& atoms)
+{
+    int errorCount;
+
+    // Print prelude
+    fprintf(out, "// This file is autogenerated\n");
+    fprintf(out, "\n");
+
+    fprintf(out, "#include <statslog.h>\n");
+    fprintf(out, "\n");
+    fprintf(out, "#include <nativehelper/JNIHelp.h>\n");
+    fprintf(out, "#include \"core_jni_helpers.h\"\n");
+    fprintf(out, "#include \"jni.h\"\n");
+    fprintf(out, "\n");
+    fprintf(out, "#define UNUSED  __attribute__((__unused__))\n");
+    fprintf(out, "\n");
+
+    fprintf(out, "namespace android {\n");
+    fprintf(out, "\n");
+
+    // Print write methods
+    for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
+            signature != atoms.signatures.end(); signature++) {
+        int argIndex;
+
+        fprintf(out, "static void\n");
+        fprintf(out, "%s(JNIEnv* env, jobject clazz UNUSED, jint code",
+                jni_function_name(*signature).c_str());
+        argIndex = 1;
+        for (vector<java_type_t>::const_iterator arg = signature->begin();
+                arg != signature->end(); arg++) {
+            fprintf(out, ", %s arg%d", jni_type_name(*arg), argIndex);
+            argIndex++;
+        }
+        fprintf(out, ")\n");
+
+        fprintf(out, "{\n");
+
+        // Prepare strings
+        argIndex = 1;
+        bool hadString = false;
+        for (vector<java_type_t>::const_iterator arg = signature->begin();
+                arg != signature->end(); arg++) {
+            if (*arg == JAVA_TYPE_STRING) {
+                fprintf(out, "    const char* str%d;\n", argIndex);
+                fprintf(out, "    if (arg%d != NULL) {\n", argIndex);
+                fprintf(out, "        str%d = env->GetStringUTFChars(arg%d, NULL);\n",
+                        argIndex, argIndex);
+                fprintf(out, "    } else {\n");
+                fprintf(out, "        str%d = NULL;\n", argIndex);
+                fprintf(out, "    }\n");
+                hadString = true;
+            }
+            argIndex++;
+        }
+
+        // Emit this to quiet the unused parameter warning if there were no strings.
+        if (!hadString) {
+            fprintf(out, "    (void)env;\n");
+        }
+
+        // stats_write call
+        argIndex = 1;
+        fprintf(out, "    android::util::stats_write(code");
+        for (vector<java_type_t>::const_iterator arg = signature->begin();
+                arg != signature->end(); arg++) {
+            const char* argName = (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
+            fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
+            argIndex++;
+        }
+        fprintf(out, ");\n");
+
+        // Clean up strings
+        argIndex = 1;
+        for (vector<java_type_t>::const_iterator arg = signature->begin();
+                arg != signature->end(); arg++) {
+            if (*arg == JAVA_TYPE_STRING) {
+                fprintf(out, "    if (str%d != NULL) {\n", argIndex);
+                fprintf(out, "        env->ReleaseStringUTFChars(arg%d, str%d);\n",
+                        argIndex, argIndex);
+                fprintf(out, "    }\n");
+            }
+            argIndex++;
+        }
+
+        fprintf(out, "}\n");
+        fprintf(out, "\n");
+    }
+
+    // Print registration function table
+    fprintf(out, "/*\n");
+    fprintf(out, " * JNI registration.\n");
+    fprintf(out, " */\n");
+    fprintf(out, "static const JNINativeMethod gRegisterMethods[] = {\n");
+    for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
+            signature != atoms.signatures.end(); signature++) {
+        fprintf(out, "    { \"write\", \"%s\", (void*)%s },\n",
+                jni_function_signature(*signature).c_str(),
+                jni_function_name(*signature).c_str());
+    }
+    fprintf(out, "};\n");
+    fprintf(out, "\n");
+
+    // Print registration function
+    fprintf(out, "int register_android_util_StatsLog(JNIEnv* env) {\n");
+    fprintf(out, "    return RegisterMethodsOrDie(\n");
+    fprintf(out, "            env,\n");
+    fprintf(out, "            \"android/util/StatsLog\",\n");
+    fprintf(out, "            gRegisterMethods, NELEM(gRegisterMethods));\n");
+    fprintf(out, "}\n");
+
+    fprintf(out, "\n");
+    fprintf(out, "} // namespace android\n");
+
+    return 0;
+}
+
+
+static void
+print_usage()
+{
+    fprintf(stderr, "usage: stats-log-api-gen OPTIONS\n");
+    fprintf(stderr, "\n");
+    fprintf(stderr, "OPTIONS\n");
+    fprintf(stderr, "  --cpp FILENAME       the header file to output\n");
+    fprintf(stderr, "  --header FILENAME    the cpp file to output\n");
+    fprintf(stderr, "  --help               this message\n");
+    fprintf(stderr, "  --java FILENAME      the java file to output\n");
+    fprintf(stderr, "  --jni FILENAME       the jni file to output\n");
+}
+
+/**
+ * Do the argument parsing and execute the tasks.
+ */
+static int
+run(int argc, char const*const* argv)
+{
+    string cppFilename;
+    string headerFilename;
+    string javaFilename;
+    string jniFilename;
+
+    int index = 1;
+    while (index < argc) {
+        if (0 == strcmp("--help", argv[index])) {
+            print_usage();
+            return 0;
+        } else if (0 == strcmp("--cpp", argv[index])) {
+            index++;
+            if (index >= argc) {
+                print_usage();
+                return 1;
+            }
+            cppFilename = argv[index];
+        } else if (0 == strcmp("--header", argv[index])) {
+            index++;
+            if (index >= argc) {
+                print_usage();
+                return 1;
+            }
+            headerFilename = argv[index];
+        } else if (0 == strcmp("--java", argv[index])) {
+            index++;
+            if (index >= argc) {
+                print_usage();
+                return 1;
+            }
+            javaFilename = argv[index];
+        } else if (0 == strcmp("--jni", argv[index])) {
+            index++;
+            if (index >= argc) {
+                print_usage();
+                return 1;
+            }
+            jniFilename = argv[index];
+        }
+        index++;
+    }
+
+    if (cppFilename.size() == 0
+            && headerFilename.size() == 0
+            && javaFilename.size() == 0
+            && jniFilename.size() == 0) {
+        print_usage();
+        return 1;
+    }
+
+    // Collate the parameters
+    Atoms atoms;
+    int errorCount = collate_atoms(StatsEvent::descriptor(), &atoms);
+    if (errorCount != 0) {
+        return 1;
+    }
+
+    // Write the .cpp file
+    if (cppFilename.size() != 0) {
+        FILE* out = fopen(cppFilename.c_str(), "w");
+        if (out == NULL) {
+            fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str());
+            return 1;
+        }
+        errorCount = android::stats_log_api_gen::write_stats_log_cpp(out, atoms);
+        fclose(out);
+    }
+
+    // Write the .h file
+    if (headerFilename.size() != 0) {
+        FILE* out = fopen(headerFilename.c_str(), "w");
+        if (out == NULL) {
+            fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str());
+            return 1;
+        }
+        errorCount = android::stats_log_api_gen::write_stats_log_header(out, atoms);
+        fclose(out);
+    }
+
+    // Write the .java file
+    if (javaFilename.size() != 0) {
+        FILE* out = fopen(javaFilename.c_str(), "w");
+        if (out == NULL) {
+            fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
+            return 1;
+        }
+        errorCount = android::stats_log_api_gen::write_stats_log_java(out, atoms);
+        fclose(out);
+    }
+
+    // Write the jni file
+    if (jniFilename.size() != 0) {
+        FILE* out = fopen(jniFilename.c_str(), "w");
+        if (out == NULL) {
+            fprintf(stderr, "Unable to open file for write: %s\n", jniFilename.c_str());
+            return 1;
+        }
+        errorCount = android::stats_log_api_gen::write_stats_log_jni(out, atoms);
+        fclose(out);
+    }
+
+    return 0;
+}
+
+}
+}
+
+/**
+ * Main.
+ */
+int
+main(int argc, char const*const* argv)
+{
+    GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+    return android::stats_log_api_gen::run(argc, argv);
+}
diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto
new file mode 100644
index 0000000..2311a11
--- /dev/null
+++ b/tools/stats_log_api_gen/test.proto
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+import "frameworks/base/cmds/statsd/src/stats_events.proto";
+
+package android.stats_log_api_gen;
+
+message IntAtom {
+    optional int32 field1 = 1;
+}
+
+message AnotherIntAtom {
+    optional int32 field1 = 1;
+}
+
+message OutOfOrderAtom {
+    optional int32 field2 = 2;
+    optional int32 field1 = 1;
+}
+
+enum AnEnum {
+    VALUE0 = 0;
+    VALUE1 = 1;
+}
+
+message AllTypesAtom {
+    optional android.os.statsd.WorkSource attribution = 1;
+    optional double double_field = 2;
+    optional float float_field = 3;
+    optional int64 int64_field = 4;
+    optional uint64 uint64_field = 5;
+    optional int32 int32_field = 6;
+    optional fixed64 fixed64_field = 7;
+    optional fixed32 fixed32_field = 8;
+    optional bool bool_field = 9;
+    optional string string_field = 10;
+    optional uint32 uint32_field = 11;
+    optional AnEnum enum_field = 12;
+    optional sfixed32 sfixed32_field = 13;
+    optional sfixed64 sfixed64_field = 14;
+    optional sint32 sint32_field = 15;
+    optional sint64 sint64_field = 16;
+}
+
+message Event {
+    oneof event {
+        OutOfOrderAtom out_of_order_atom = 2;
+        IntAtom int_atom = 1;
+        AnotherIntAtom another_int_atom = 3;
+        AllTypesAtom all_types_atom = 4;
+    }
+}
+
+message BadTypesAtom {
+    optional IntAtom bad_int_atom = 1;
+    optional bytes bad_bytes = 2;
+}
+
+message BadTypesEvent {
+    oneof event {
+        BadTypesAtom bad_types_atom = 1;
+    }
+}
+
+message BadSkippedFieldSingleAtom {
+    optional int32 field2 = 2;
+}
+
+message BadSkippedFieldSingle {
+    oneof event {
+        BadSkippedFieldSingleAtom bad = 1;
+    }
+}
+
+message BadSkippedFieldMultipleAtom {
+    optional int32 field1 = 1;
+    optional int32 field3 = 3;
+    optional int32 field5 = 5;
+}
+
+message BadSkippedFieldMultiple {
+    oneof event {
+        BadSkippedFieldMultipleAtom bad = 1;
+    }
+}
+
+message BadWorkSourcePositionAtom {
+    optional int32 field1 = 1;
+    optional android.os.statsd.WorkSource attribution = 2;
+}
+
+message BadWorkSourcePosition {
+    oneof event {
+        BadWorkSourcePositionAtom bad = 1;
+    }
+}
+
diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp
new file mode 100644
index 0000000..1bd2e3d
--- /dev/null
+++ b/tools/stats_log_api_gen/test_collation.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "frameworks/base/tools/stats_log_api_gen/test.pb.h"
+#include "Collation.h"
+
+#include <stdio.h>
+
+namespace android {
+namespace stats_log_api_gen {
+
+using std::set;
+using std::vector;
+
+/**
+ * Return whether the set contains a vector of the elements provided.
+ */
+static bool
+set_contains_vector(const set<vector<java_type_t>>& s, int count, ...)
+{
+    va_list args;
+    vector<java_type_t> v;
+
+    va_start(args, count);
+    for (int i=0; i<count; i++) {
+        v.push_back((java_type_t)va_arg(args, int));
+    }
+    va_end(args);
+
+    return s.find(v) != s.end();
+}
+
+/**
+ * Expect that the provided set contains the elements provided.
+ */
+#define EXPECT_SET_CONTAINS_SIGNATURE(s, ...) \
+    do { \
+        int count = sizeof((int[]){__VA_ARGS__})/sizeof(int); \
+        EXPECT_TRUE(set_contains_vector(s, count, __VA_ARGS__)); \
+    } while(0)
+
+/**
+ * Test a correct collation, with all the types.
+ */
+TEST(CollationTest, CollateStats) {
+    Atoms atoms;
+    int errorCount = collate_atoms(Event::descriptor(), &atoms);
+
+    EXPECT_EQ(0, errorCount);
+    EXPECT_EQ(3ul, atoms.signatures.size());
+
+    // IntAtom, AnotherIntAtom
+    EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures, JAVA_TYPE_INT);
+
+    // OutOfOrderAtom
+    EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures, JAVA_TYPE_INT, JAVA_TYPE_INT);
+
+    // AllTypesAtom
+    EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures,
+                JAVA_TYPE_WORK_SOURCE, // WorkSource
+                JAVA_TYPE_DOUBLE, // double
+                JAVA_TYPE_FLOAT, // float
+                JAVA_TYPE_LONG, // int64
+                JAVA_TYPE_LONG, // uint64
+                JAVA_TYPE_INT, // int32
+                JAVA_TYPE_LONG, // fixed64
+                JAVA_TYPE_INT, // fixed32
+                JAVA_TYPE_BOOLEAN, // bool
+                JAVA_TYPE_STRING, // string
+                JAVA_TYPE_INT, // uint32
+                JAVA_TYPE_INT, // AnEnum
+                JAVA_TYPE_INT, // sfixed32
+                JAVA_TYPE_LONG, // sfixed64
+                JAVA_TYPE_INT, // sint32
+                JAVA_TYPE_LONG // sint64
+            );
+
+    set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+    EXPECT_EQ(1, atom->code);
+    EXPECT_EQ("int_atom", atom->name);
+    EXPECT_EQ("IntAtom", atom->message);
+    atom++;
+
+    EXPECT_EQ(2, atom->code);
+    EXPECT_EQ("out_of_order_atom", atom->name);
+    EXPECT_EQ("OutOfOrderAtom", atom->message);
+    atom++;
+
+    EXPECT_EQ(3, atom->code);
+    EXPECT_EQ("another_int_atom", atom->name);
+    EXPECT_EQ("AnotherIntAtom", atom->message);
+    atom++;
+
+    EXPECT_EQ(4, atom->code);
+    EXPECT_EQ("all_types_atom", atom->name);
+    EXPECT_EQ("AllTypesAtom", atom->message);
+    atom++;
+
+    EXPECT_TRUE(atom == atoms.decls.end());
+}
+
+/**
+ * Test that event class that contains stuff other than the atoms is rejected.
+ */
+TEST(CollationTest, NonMessageTypeFails) {
+    Atoms atoms;
+    int errorCount = collate_atoms(IntAtom::descriptor(), &atoms);
+
+    EXPECT_EQ(1, errorCount);
+}
+
+/**
+ * Test that atoms that have non-primitve types are rejected.
+ */
+TEST(CollationTest, FailOnBadTypes) {
+    Atoms atoms;
+    int errorCount = collate_atoms(BadTypesEvent::descriptor(), &atoms);
+
+    EXPECT_EQ(2, errorCount);
+}
+
+/**
+ * Test that atoms that skip field numbers (in the first position) are rejected.
+ */
+TEST(CollationTest, FailOnSkippedFieldsSingle) {
+    Atoms atoms;
+    int errorCount = collate_atoms(BadSkippedFieldSingle::descriptor(), &atoms);
+
+    EXPECT_EQ(1, errorCount);
+}
+
+/**
+ * Test that atoms that skip field numbers (not in the first position, and multiple
+ * times) are rejected.
+ */
+TEST(CollationTest, FailOnSkippedFieldsMultiple) {
+    Atoms atoms;
+    int errorCount = collate_atoms(BadSkippedFieldMultiple::descriptor(), &atoms);
+
+    EXPECT_EQ(2, errorCount);
+}
+
+/**
+ * Test that atoms that have a WorkSource not in the first position are rejected.
+ */
+TEST(CollationTest, FailBadWorkSourcePosition) {
+    Atoms atoms;
+    int errorCount = collate_atoms(BadWorkSourcePosition::descriptor(), &atoms);
+
+    EXPECT_EQ(1, errorCount);
+}
+
+
+}  // namespace stats_log_api_gen
+}  // namespace android
+
diff --git a/wifi/java/android/net/wifi/rtt/IRttCallback.aidl b/wifi/java/android/net/wifi/rtt/IRttCallback.aidl
index fb1636f..578dd1e 100644
--- a/wifi/java/android/net/wifi/rtt/IRttCallback.aidl
+++ b/wifi/java/android/net/wifi/rtt/IRttCallback.aidl
@@ -26,7 +26,12 @@
 oneway interface IRttCallback
 {
     /**
-     * Service to manager callback providing RTT status and results.
+     * Service to manager callback indicating failure.
      */
-    void onRangingResults(int status, in List<RangingResult> results);
+    void onRangingFailure(int status);
+
+    /**
+     * Service to manager callback indicating success and providing results.
+     */
+    void onRangingResults(in List<RangingResult> results);
 }
diff --git a/wifi/java/android/net/wifi/rtt/RangingRequest.java b/wifi/java/android/net/wifi/rtt/RangingRequest.java
index 997b680..a396281 100644
--- a/wifi/java/android/net/wifi/rtt/RangingRequest.java
+++ b/wifi/java/android/net/wifi/rtt/RangingRequest.java
@@ -17,13 +17,22 @@
 package android.net.wifi.rtt;
 
 import android.net.wifi.ScanResult;
+import android.net.wifi.aware.AttachCallback;
+import android.net.wifi.aware.DiscoverySessionCallback;
+import android.net.wifi.aware.IdentityChangedListener;
+import android.net.wifi.aware.PeerHandle;
+import android.net.wifi.aware.WifiAwareManager;
 import android.os.Handler;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
 
+import libcore.util.HexEncoding;
+
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 import java.util.StringJoiner;
 
 /**
@@ -33,8 +42,8 @@
  * {@link WifiRttManager#startRanging(RangingRequest, RangingResultCallback, Handler)}.
  * <p>
  * The ranging request is a batch request - specifying a set of devices (specified using
- * {@link RangingRequest.Builder#addAp(ScanResult)} and
- * {@link RangingRequest.Builder#addAps(List)}).
+ * {@link RangingRequest.Builder#addAccessPoint(ScanResult)} and
+ * {@link RangingRequest.Builder#addAccessPoints(List)}).
  *
  * @hide RTT_API
  */
@@ -44,8 +53,8 @@
     /**
      * Returns the maximum number of peers to range which can be specified in a single {@code
      * RangingRequest}. The limit applies no matter how the peers are added to the request, e.g.
-     * through {@link RangingRequest.Builder#addAp(ScanResult)} or
-     * {@link RangingRequest.Builder#addAps(List)}.
+     * through {@link RangingRequest.Builder#addAccessPoint(ScanResult)} or
+     * {@link RangingRequest.Builder#addAccessPoints(List)}.
      *
      * @return Maximum number of peers.
      */
@@ -94,11 +103,34 @@
     }
 
     /** @hide */
-    public void enforceValidity() {
+    public void enforceValidity(boolean awareSupported) {
         if (mRttPeers.size() > MAX_PEERS) {
             throw new IllegalArgumentException(
                     "Ranging to too many peers requested. Use getMaxPeers() API to get limit.");
         }
+
+        for (RttPeer peer: mRttPeers) {
+            if (peer instanceof RttPeerAp) {
+                RttPeerAp apPeer = (RttPeerAp) peer;
+                if (apPeer.scanResult == null || apPeer.scanResult.BSSID == null) {
+                    throw new IllegalArgumentException("Invalid AP peer specification");
+                }
+            } else if (peer instanceof RttPeerAware) {
+                if (!awareSupported) {
+                    throw new IllegalArgumentException(
+                            "Request contains Aware peers - but Aware isn't supported on this "
+                                    + "device");
+                }
+
+                RttPeerAware awarePeer = (RttPeerAware) peer;
+                if (awarePeer.peerMacAddress == null && awarePeer.peerHandle == null) {
+                    throw new IllegalArgumentException("Invalid Aware peer specification");
+                }
+            } else {
+                throw new IllegalArgumentException(
+                        "Request contains unknown peer specification types");
+            }
+        }
     }
 
     /**
@@ -116,7 +148,7 @@
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
-        public Builder addAp(ScanResult apInfo) {
+        public Builder addAccessPoint(ScanResult apInfo) {
             if (apInfo == null) {
                 throw new IllegalArgumentException("Null ScanResult!");
             }
@@ -133,17 +165,55 @@
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
-        public Builder addAps(List<ScanResult> apInfos) {
+        public Builder addAccessPoints(List<ScanResult> apInfos) {
             if (apInfos == null) {
                 throw new IllegalArgumentException("Null list of ScanResults!");
             }
             for (ScanResult scanResult : apInfos) {
-                addAp(scanResult);
+                addAccessPoint(scanResult);
             }
             return this;
         }
 
         /**
+         * Add the device specified by the {@code peerMacAddress} to the list of devices with
+         * which to measure range.
+         *
+         * The MAC address may be obtained out-of-band from a peer Wi-Fi Aware device. A Wi-Fi
+         * Aware device may obtain its MAC address using the {@link IdentityChangedListener}
+         * provided to
+         * {@link WifiAwareManager#attach(AttachCallback, IdentityChangedListener, Handler)}.
+         *
+         * * Note: in order to use this API the device must support Wi-Fi Aware
+         * {@link android.net.wifi.aware}.
+         *
+         * @param peerMacAddress The MAC address of the Wi-Fi Aware peer.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder addWifiAwarePeer(byte[] peerMacAddress) {
+            mRttPeers.add(new RttPeerAware(peerMacAddress));
+            return this;
+        }
+
+        /**
+         * Add a device specified by a {@link PeerHandle} to the list of devices with which to
+         * measure range.
+         *
+         * The {@link PeerHandle} may be obtained as part of the Wi-Fi Aware discovery process. E.g.
+         * using {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], List)}.
+         *
+         * Note: in order to use this API the device must support Wi-Fi Aware
+         * {@link android.net.wifi.aware}.
+         *
+         * @param peerHandle The peer handler of the peer Wi-Fi Aware device.
+         * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder addWifiAwarePeer(PeerHandle peerHandle) {
+            mRttPeers.add(new RttPeerAware(peerHandle));
+            return this;
+        }
+
+        /**
          * Build {@link RangingRequest} given the current configurations made on the
          * builder.
          */
@@ -234,4 +304,89 @@
             return scanResult.hashCode();
         }
     }
-}
\ No newline at end of file
+
+    /** @hide */
+    public static class RttPeerAware implements RttPeer, Parcelable {
+        public PeerHandle peerHandle;
+        public byte[] peerMacAddress;
+
+        public RttPeerAware(PeerHandle peerHandle) {
+            if (peerHandle == null) {
+                throw new IllegalArgumentException("Null peerHandle");
+            }
+            this.peerHandle = peerHandle;
+            peerMacAddress = null;
+        }
+
+        public RttPeerAware(byte[] peerMacAddress) {
+            if (peerMacAddress == null) {
+                throw new IllegalArgumentException("Null peerMacAddress");
+            }
+
+            this.peerMacAddress = peerMacAddress;
+            peerHandle = null;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            if (peerHandle == null) {
+                dest.writeBoolean(false);
+                dest.writeByteArray(peerMacAddress);
+            } else {
+                dest.writeBoolean(true);
+                dest.writeInt(peerHandle.peerId);
+            }
+        }
+
+        public static final Creator<RttPeerAware> CREATOR = new Creator<RttPeerAware>() {
+            @Override
+            public RttPeerAware[] newArray(int size) {
+                return new RttPeerAware[size];
+            }
+
+            @Override
+            public RttPeerAware createFromParcel(Parcel in) {
+                boolean peerHandleAvail = in.readBoolean();
+                if (peerHandleAvail) {
+                    return new RttPeerAware(new PeerHandle(in.readInt()));
+                } else {
+                    return new RttPeerAware(in.createByteArray());
+                }
+            }
+        };
+
+        @Override
+        public String toString() {
+            return new StringBuilder("RttPeerAware: peerHandle=").append(
+                    peerHandle == null ? "<null>" : Integer.toString(peerHandle.peerId)).append(
+                    ", peerMacAddress=").append(peerMacAddress == null ? "<null>"
+                    : new String(HexEncoding.encode(peerMacAddress))).toString();
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+
+            if (!(o instanceof RttPeerAware)) {
+                return false;
+            }
+
+            RttPeerAware lhs = (RttPeerAware) o;
+
+            return Objects.equals(peerHandle, lhs.peerHandle) && Arrays.equals(peerMacAddress,
+                    lhs.peerMacAddress);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(peerHandle.peerId, peerMacAddress);
+        }
+    }
+}
diff --git a/wifi/java/android/net/wifi/rtt/RangingResult.java b/wifi/java/android/net/wifi/rtt/RangingResult.java
index 918803e..93e52ae 100644
--- a/wifi/java/android/net/wifi/rtt/RangingResult.java
+++ b/wifi/java/android/net/wifi/rtt/RangingResult.java
@@ -16,13 +16,16 @@
 
 package android.net.wifi.rtt;
 
+import android.annotation.IntDef;
+import android.net.wifi.aware.PeerHandle;
 import android.os.Handler;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.Log;
 
 import libcore.util.HexEncoding;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
@@ -40,28 +43,61 @@
 public final class RangingResult implements Parcelable {
     private static final String TAG = "RangingResult";
 
+    /** @hide */
+    @IntDef({STATUS_SUCCESS, STATUS_FAIL})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RangeResultStatus {
+    }
+
+    /**
+     * Individual range request status, {@link #getStatus()}. Indicates ranging operation was
+     * successful and distance value is valid.
+     */
+    public static final int STATUS_SUCCESS = 0;
+
+    /**
+     * Individual range request status, {@link #getStatus()}. Indicates ranging operation failed
+     * and the distance value is invalid.
+     */
+    public static final int STATUS_FAIL = 1;
+
     private final int mStatus;
     private final byte[] mMac;
-    private final int mDistanceCm;
-    private final int mDistanceStdDevCm;
+    private final PeerHandle mPeerHandle;
+    private final int mDistanceMm;
+    private final int mDistanceStdDevMm;
     private final int mRssi;
     private final long mTimestamp;
 
     /** @hide */
-    public RangingResult(int status, byte[] mac, int distanceCm, int distanceStdDevCm, int rssi,
-            long timestamp) {
+    public RangingResult(@RangeResultStatus int status, byte[] mac, int distanceMm,
+            int distanceStdDevMm, int rssi, long timestamp) {
         mStatus = status;
         mMac = mac;
-        mDistanceCm = distanceCm;
-        mDistanceStdDevCm = distanceStdDevCm;
+        mPeerHandle = null;
+        mDistanceMm = distanceMm;
+        mDistanceStdDevMm = distanceStdDevMm;
+        mRssi = rssi;
+        mTimestamp = timestamp;
+    }
+
+    /** @hide */
+    public RangingResult(@RangeResultStatus int status, PeerHandle peerHandle, int distanceMm,
+            int distanceStdDevMm, int rssi, long timestamp) {
+        mStatus = status;
+        mMac = null;
+        mPeerHandle = peerHandle;
+        mDistanceMm = distanceMm;
+        mDistanceStdDevMm = distanceStdDevMm;
         mRssi = rssi;
         mTimestamp = timestamp;
     }
 
     /**
-     * @return The status of ranging measurement: {@link RangingResultCallback#STATUS_SUCCESS} in
-     * case of success, and {@link RangingResultCallback#STATUS_FAIL} in case of failure.
+     * @return The status of ranging measurement: {@link #STATUS_SUCCESS} in case of success, and
+     * {@link #STATUS_FAIL} in case of failure.
      */
+    @RangeResultStatus
     public int getStatus() {
         return mStatus;
     }
@@ -70,57 +106,80 @@
      * @return The MAC address of the device whose range measurement was requested. Will correspond
      * to the MAC address of the device in the {@link RangingRequest}.
      * <p>
-     * Always valid (i.e. when {@link #getStatus()} is either SUCCESS or FAIL.
+     * Will return a {@code null} for results corresponding to requests issued using a {@code
+     * PeerHandle}, i.e. using the {@link RangingRequest.Builder#addWifiAwarePeer(PeerHandle)} API.
      */
     public byte[] getMacAddress() {
         return mMac;
     }
 
     /**
-     * @return The distance (in cm) to the device specified by {@link #getMacAddress()}.
+     * @return The PeerHandle of the device whose reange measurement was requested. Will correspond
+     * to the PeerHandle of the devices requested using
+     * {@link RangingRequest.Builder#addWifiAwarePeer(PeerHandle)}.
      * <p>
-     * Only valid if {@link #getStatus()} returns {@link RangingResultCallback#STATUS_SUCCESS}.
+     * Will return a {@code null} for results corresponding to requests issued using a MAC address.
      */
-    public int getDistanceCm() {
-        if (mStatus != RangingResultCallback.STATUS_SUCCESS) {
-            Log.e(TAG, "getDistanceCm(): invalid value retrieved");
-        }
-        return mDistanceCm;
+    public PeerHandle getPeerHandle() {
+        return mPeerHandle;
     }
 
     /**
-     * @return The standard deviation of the measured distance (in cm) to the device specified by
-     * {@link #getMacAddress()}. The standard deviation is calculated over the measurements
-     * executed in a single RTT burst.
+     * @return The distance (in mm) to the device specified by {@link #getMacAddress()} or
+     * {@link #getPeerHandle()}.
      * <p>
-     * Only valid if {@link #getStatus()} returns {@link RangingResultCallback#STATUS_SUCCESS}.
+     * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an
+     * exception.
      */
-    public int getDistanceStdDevCm() {
-        if (mStatus != RangingResultCallback.STATUS_SUCCESS) {
-            Log.e(TAG, "getDistanceStdDevCm(): invalid value retrieved");
+    public int getDistanceMm() {
+        if (mStatus != STATUS_SUCCESS) {
+            throw new IllegalStateException(
+                    "getDistanceMm(): invoked on an invalid result: getStatus()=" + mStatus);
         }
-        return mDistanceStdDevCm;
+        return mDistanceMm;
+    }
+
+    /**
+     * @return The standard deviation of the measured distance (in mm) to the device specified by
+     * {@link #getMacAddress()} or {@link #getPeerHandle()}. The standard deviation is calculated
+     * over the measurements executed in a single RTT burst.
+     * <p>
+     * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an
+     * exception.
+     */
+    public int getDistanceStdDevMm() {
+        if (mStatus != STATUS_SUCCESS) {
+            throw new IllegalStateException(
+                    "getDistanceStdDevMm(): invoked on an invalid result: getStatus()=" + mStatus);
+        }
+        return mDistanceStdDevMm;
     }
 
     /**
      * @return The average RSSI (in units of -0.5dB) observed during the RTT measurement.
      * <p>
-     * Only valid if {@link #getStatus()} returns {@link RangingResultCallback#STATUS_SUCCESS}.
+     * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an
+     * exception.
      */
     public int getRssi() {
-        if (mStatus != RangingResultCallback.STATUS_SUCCESS) {
-            // TODO: should this be an exception?
-            Log.e(TAG, "getRssi(): invalid value retrieved");
+        if (mStatus != STATUS_SUCCESS) {
+            throw new IllegalStateException(
+                    "getRssi(): invoked on an invalid result: getStatus()=" + mStatus);
         }
         return mRssi;
     }
 
     /**
-     * @return The timestamp (in us) at which the ranging operation was performed
+     * @return The timestamp, in us since boot, at which the ranging operation was performed.
      * <p>
-     * Only valid if {@link #getStatus()} returns {@link RangingResultCallback#STATUS_SUCCESS}.
+     * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an
+     * exception.
      */
-    public long getRangingTimestamp() {
+    public long getRangingTimestampUs() {
+        if (mStatus != STATUS_SUCCESS) {
+            throw new IllegalStateException(
+                    "getRangingTimestamp(): invoked on an invalid result: getStatus()=" + mStatus);
+        }
         return mTimestamp;
     }
 
@@ -135,8 +194,14 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mStatus);
         dest.writeByteArray(mMac);
-        dest.writeInt(mDistanceCm);
-        dest.writeInt(mDistanceStdDevCm);
+        if (mPeerHandle == null) {
+            dest.writeBoolean(false);
+        } else {
+            dest.writeBoolean(true);
+            dest.writeInt(mPeerHandle.peerId);
+        }
+        dest.writeInt(mDistanceMm);
+        dest.writeInt(mDistanceStdDevMm);
         dest.writeInt(mRssi);
         dest.writeLong(mTimestamp);
     }
@@ -152,11 +217,22 @@
         public RangingResult createFromParcel(Parcel in) {
             int status = in.readInt();
             byte[] mac = in.createByteArray();
-            int distanceCm = in.readInt();
-            int distanceStdDevCm = in.readInt();
+            boolean peerHandlePresent = in.readBoolean();
+            PeerHandle peerHandle = null;
+            if (peerHandlePresent) {
+                peerHandle = new PeerHandle(in.readInt());
+            }
+            int distanceMm = in.readInt();
+            int distanceStdDevMm = in.readInt();
             int rssi = in.readInt();
             long timestamp = in.readLong();
-            return new RangingResult(status, mac, distanceCm, distanceStdDevCm, rssi, timestamp);
+            if (peerHandlePresent) {
+                return new RangingResult(status, peerHandle, distanceMm, distanceStdDevMm, rssi,
+                        timestamp);
+            } else {
+                return new RangingResult(status, mac, distanceMm, distanceStdDevMm, rssi,
+                        timestamp);
+            }
         }
     };
 
@@ -164,9 +240,10 @@
     @Override
     public String toString() {
         return new StringBuilder("RangingResult: [status=").append(mStatus).append(", mac=").append(
-                mMac == null ? "<null>" : HexEncoding.encodeToString(mMac)).append(
-                ", distanceCm=").append(mDistanceCm).append(", distanceStdDevCm=").append(
-                mDistanceStdDevCm).append(", rssi=").append(mRssi).append(", timestamp=").append(
+                mMac == null ? "<null>" : new String(HexEncoding.encodeToString(mMac))).append(
+                ", peerHandle=").append(mPeerHandle == null ? "<null>" : mPeerHandle.peerId).append(
+                ", distanceMm=").append(mDistanceMm).append(", distanceStdDevMm=").append(
+                mDistanceStdDevMm).append(", rssi=").append(mRssi).append(", timestamp=").append(
                 mTimestamp).append("]").toString();
     }
 
@@ -182,13 +259,15 @@
 
         RangingResult lhs = (RangingResult) o;
 
-        return mStatus == lhs.mStatus && Arrays.equals(mMac, lhs.mMac)
-                && mDistanceCm == lhs.mDistanceCm && mDistanceStdDevCm == lhs.mDistanceStdDevCm
-                && mRssi == lhs.mRssi && mTimestamp == lhs.mTimestamp;
+        return mStatus == lhs.mStatus && Arrays.equals(mMac, lhs.mMac) && Objects.equals(
+                mPeerHandle, lhs.mPeerHandle) && mDistanceMm == lhs.mDistanceMm
+                && mDistanceStdDevMm == lhs.mDistanceStdDevMm && mRssi == lhs.mRssi
+                && mTimestamp == lhs.mTimestamp;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mStatus, mMac, mDistanceCm, mDistanceStdDevCm, mRssi, mTimestamp);
+        return Objects.hash(mStatus, mMac, mPeerHandle, mDistanceMm, mDistanceStdDevMm, mRssi,
+                mTimestamp);
     }
-}
\ No newline at end of file
+}
diff --git a/wifi/java/android/net/wifi/rtt/RangingResultCallback.java b/wifi/java/android/net/wifi/rtt/RangingResultCallback.java
index d7270ad..7405e82 100644
--- a/wifi/java/android/net/wifi/rtt/RangingResultCallback.java
+++ b/wifi/java/android/net/wifi/rtt/RangingResultCallback.java
@@ -16,35 +16,43 @@
 
 package android.net.wifi.rtt;
 
+import android.annotation.IntDef;
 import android.os.Handler;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.List;
 
 /**
  * Base class for ranging result callbacks. Should be extended by applications and set when calling
- * {@link WifiRttManager#startRanging(RangingRequest, RangingResultCallback, Handler)}. A single
- * result from a range request will be called in this object.
+ * {@link WifiRttManager#startRanging(RangingRequest, RangingResultCallback, Handler)}. If the
+ * ranging operation fails in whole (not attempted) then {@link #onRangingFailure(int)} will be
+ * called with a failure code. If the ranging operation is performed for each of the requested
+ * peers then the {@link #onRangingResults(List)} will be called with the set of results (@link
+ * {@link RangingResult}, each of which has its own success/failure code
+ * {@link RangingResult#getStatus()}.
  *
  * @hide RTT_API
  */
 public abstract class RangingResultCallback {
-    /**
-     * Individual range request status, {@link RangingResult#getStatus()}. Indicates ranging
-     * operation was successful and distance value is valid.
-     */
-    public static final int STATUS_SUCCESS = 0;
+    /** @hide */
+    @IntDef({STATUS_CODE_FAIL})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RangingOperationStatus {
+    }
 
     /**
-     * Individual range request status, {@link RangingResult#getStatus()}. Indicates ranging
-     * operation failed and the distance value is invalid.
+     * A failure code for the whole ranging request operation. Indicates a failure.
      */
-    public static final int STATUS_FAIL = 1;
+    public static final int STATUS_CODE_FAIL = 1;
 
     /**
      * Called when a ranging operation failed in whole - i.e. no ranging operation to any of the
      * devices specified in the request was attempted.
+     *
+     * @param code A status code indicating the type of failure.
      */
-    public abstract void onRangingFailure();
+    public abstract void onRangingFailure(@RangingOperationStatus int code);
 
     /**
      * Called when a ranging operation was executed. The list of results corresponds to devices
diff --git a/wifi/java/android/net/wifi/rtt/WifiRttManager.java b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
index a085de1..435bb37 100644
--- a/wifi/java/android/net/wifi/rtt/WifiRttManager.java
+++ b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
@@ -83,17 +83,18 @@
         }
 
         @Override
-        public void onRangingResults(int status, List<RangingResult> results) throws RemoteException {
-            if (VDBG) {
-                Log.v(TAG, "RttCallbackProxy: onRanginResults: status=" + status + ", results="
-                        + results);
-            }
+        public void onRangingFailure(int status) throws RemoteException {
+            if (VDBG) Log.v(TAG, "RttCallbackProxy: onRangingFailure: status=" + status);
             mHandler.post(() -> {
-               if (status == RangingResultCallback.STATUS_SUCCESS) {
-                   mCallback.onRangingResults(results);
-               } else {
-                   mCallback.onRangingFailure();
-               }
+               mCallback.onRangingFailure(status);
+            });
+        }
+
+        @Override
+        public void onRangingResults(List<RangingResult> results) throws RemoteException {
+            if (VDBG) Log.v(TAG, "RttCallbackProxy: onRanginResults: results=" + results);
+            mHandler.post(() -> {
+               mCallback.onRangingResults(results);
             });
         }
     }
diff --git a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
index 23c75ce..33bd982 100644
--- a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
@@ -26,6 +26,7 @@
 
 import android.content.Context;
 import android.net.wifi.ScanResult;
+import android.net.wifi.aware.PeerHandle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -78,7 +79,7 @@
     public void testRangeSuccess() throws Exception {
         RangingRequest request = new RangingRequest.Builder().build();
         List<RangingResult> results = new ArrayList<>();
-        results.add(new RangingResult(RangingResultCallback.STATUS_SUCCESS, null, 15, 5, 10, 666));
+        results.add(new RangingResult(RangingResult.STATUS_SUCCESS, (byte[]) null, 15, 5, 10, 666));
         RangingResultCallback callbackMock = mock(RangingResultCallback.class);
         ArgumentCaptor<IRttCallback> callbackCaptor = ArgumentCaptor.forClass(IRttCallback.class);
 
@@ -88,7 +89,7 @@
                 callbackCaptor.capture());
 
         // service calls back with success
-        callbackCaptor.getValue().onRangingResults(RangingResultCallback.STATUS_SUCCESS, results);
+        callbackCaptor.getValue().onRangingResults(results);
         mMockLooper.dispatchAll();
         verify(callbackMock).onRangingResults(results);
 
@@ -100,6 +101,8 @@
      */
     @Test
     public void testRangeFail() throws Exception {
+        int failureCode = RangingResultCallback.STATUS_CODE_FAIL;
+
         RangingRequest request = new RangingRequest.Builder().build();
         RangingResultCallback callbackMock = mock(RangingResultCallback.class);
         ArgumentCaptor<IRttCallback> callbackCaptor = ArgumentCaptor.forClass(IRttCallback.class);
@@ -110,9 +113,9 @@
                 callbackCaptor.capture());
 
         // service calls back with failure code
-        callbackCaptor.getValue().onRangingResults(RangingResultCallback.STATUS_FAIL, null);
+        callbackCaptor.getValue().onRangingFailure(failureCode);
         mMockLooper.dispatchAll();
-        verify(callbackMock).onRangingFailure();
+        verify(callbackMock).onRangingFailure(failureCode);
 
         verifyNoMoreInteractions(mockRttService, callbackMock);
     }
@@ -132,10 +135,14 @@
         List<ScanResult> scanResults2and3 = new ArrayList<>(2);
         scanResults2and3.add(scanResult2);
         scanResults2and3.add(scanResult3);
+        final byte[] mac1 = HexEncoding.decode("000102030405".toCharArray(), false);
+        PeerHandle peerHandle1 = new PeerHandle(12);
 
         RangingRequest.Builder builder = new RangingRequest.Builder();
-        builder.addAp(scanResult1);
-        builder.addAps(scanResults2and3);
+        builder.addAccessPoint(scanResult1);
+        builder.addAccessPoints(scanResults2and3);
+        builder.addWifiAwarePeer(mac1);
+        builder.addWifiAwarePeer(peerHandle1);
         RangingRequest request = builder.build();
 
         Parcel parcelW = Parcel.obtain();
@@ -157,20 +164,23 @@
     @Test
     public void testRangingRequestAtLimit() {
         ScanResult scanResult = new ScanResult();
+        scanResult.BSSID = "AA:BB:CC:DD:EE:FF";
         List<ScanResult> scanResultList = new ArrayList<>();
-        for (int i = 0; i < RangingRequest.getMaxPeers() - 2; ++i) {
+        for (int i = 0; i < RangingRequest.getMaxPeers() - 3; ++i) {
             scanResultList.add(scanResult);
         }
+        final byte[] mac1 = HexEncoding.decode("000102030405".toCharArray(), false);
 
         // create request
         RangingRequest.Builder builder = new RangingRequest.Builder();
-        builder.addAp(scanResult);
-        builder.addAps(scanResultList);
-        builder.addAp(scanResult);
+        builder.addAccessPoint(scanResult);
+        builder.addAccessPoints(scanResultList);
+        builder.addAccessPoint(scanResult);
+        builder.addWifiAwarePeer(mac1);
         RangingRequest request = builder.build();
 
         // verify request
-        request.enforceValidity();
+        request.enforceValidity(true);
     }
 
     /**
@@ -180,19 +190,35 @@
     public void testRangingRequestPastLimit() {
         ScanResult scanResult = new ScanResult();
         List<ScanResult> scanResultList = new ArrayList<>();
-        for (int i = 0; i < RangingRequest.getMaxPeers() - 1; ++i) {
+        for (int i = 0; i < RangingRequest.getMaxPeers() - 2; ++i) {
             scanResultList.add(scanResult);
         }
+        final byte[] mac1 = HexEncoding.decode("000102030405".toCharArray(), false);
 
         // create request
         RangingRequest.Builder builder = new RangingRequest.Builder();
-        builder.addAp(scanResult);
-        builder.addAps(scanResultList);
-        builder.addAp(scanResult);
+        builder.addAccessPoint(scanResult);
+        builder.addAccessPoints(scanResultList);
+        builder.addAccessPoint(scanResult);
+        builder.addWifiAwarePeer(mac1);
         RangingRequest request = builder.build();
 
         // verify request
-        request.enforceValidity();
+        request.enforceValidity(true);
+    }
+
+    /**
+     * Validate that Aware requests are invalid on devices which do not support Aware
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testRangingRequestWithAwareWithNoAwareSupport() {
+        // create request
+        RangingRequest.Builder builder = new RangingRequest.Builder();
+        builder.addWifiAwarePeer(new PeerHandle(10));
+        RangingRequest request = builder.build();
+
+        // verify request
+        request.enforceValidity(false);
     }
 
     /**
@@ -201,13 +227,15 @@
     @Test
     public void testRangingResultsParcel() {
         // Note: not validating parcel code of ScanResult (assumed to work)
-        int status = RangingResultCallback.STATUS_SUCCESS;
+        int status = RangingResult.STATUS_SUCCESS;
         final byte[] mac = HexEncoding.decode("000102030405".toCharArray(), false);
+        PeerHandle peerHandle = new PeerHandle(10);
         int distanceCm = 105;
         int distanceStdDevCm = 10;
         int rssi = 5;
         long timestamp = System.currentTimeMillis();
 
+        // RangingResults constructed with a MAC address
         RangingResult result = new RangingResult(status, mac, distanceCm, distanceStdDevCm, rssi,
                 timestamp);
 
@@ -222,5 +250,21 @@
         RangingResult rereadResult = RangingResult.CREATOR.createFromParcel(parcelR);
 
         assertEquals(result, rereadResult);
+
+        // RangingResults constructed with a PeerHandle
+        result = new RangingResult(status, peerHandle, distanceCm, distanceStdDevCm, rssi,
+                timestamp);
+
+        parcelW = Parcel.obtain();
+        result.writeToParcel(parcelW, 0);
+        bytes = parcelW.marshall();
+        parcelW.recycle();
+
+        parcelR = Parcel.obtain();
+        parcelR.unmarshall(bytes, 0, bytes.length);
+        parcelR.setDataPosition(0);
+        rereadResult = RangingResult.CREATOR.createFromParcel(parcelR);
+
+        assertEquals(result, rereadResult);
     }
 }