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
+ * —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—
+ * 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 > Programme > 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">"በስርዓት ቅንብሮች ውስጥ ይሄንን ዳግም አንቃ> 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-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">"يمكنك إعادة تمكين هذا في إعدادات النظام > التطبيقات > ما تم تنزيله."</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ş > Tətbiqlər >."</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 > Aplikacije > 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">"Зноў уключыце гэта ў раздзеле \"Сістэмныя налады > Прыкладанні > Спампаваныя\"."</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">"Активирайте отново това в „Системни настройки“ > „Приложения“ > „Изтеглени“."</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">"সিস্টেম সেটিংস> অ্যাপ্স> ডাউনলোড করাগুলি এ এটি পুনঃসক্ষম করুন৷"</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 > Aplikacije > 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 > Aplicacions > 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 > Aplikace > 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 > Apps > 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 > 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">"Ενεργοποιήστε το ξανά στις Ρυθμίσεις συστημάτων > Εφαρμογές > Ληφθείσες."</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 > Aplicaciones > 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 > Aplicaciones > 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 > Rakendused > 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 > Aplikazioak > 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">"در تنظیمات سیستم >برنامهها > مورد بارگیری شده آن را دوباره فعال کنید."</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 > Sovellukset > 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 > Applications > 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 > Applications > 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 > Aplicacións > 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">"આને સિસ્ટમ સેટિંગ્સ > ઍપ્લિકેશનો > ડાઉનલોડ કરેલમાં ફરીથી સક્ષમ કરો."</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">"इसे सिस्टम सेटिंग > ऐप > डाउनलोड किए गए में फिर से चालू करें."</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 > Aplikacije > 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 > Alkalmazások > 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">"Կրկին ակտիվացնել սա Համակարգի կարգավորումներում &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 > Apl > 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 > Forrit > 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 > Applicazioni > 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">"אפשר תכונה זו מחדש ב\'הגדרות מערכת\' < Google Apps < \'הורדות\'."</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">"[システム設定]>[アプリ]>[ダウンロード済み]で再度有効にします。"</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">"ხელახალი გააქტიურება განყოფილებაში: სისტემის პარამეტრები > აპები > ჩამოტვირთულები."</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">"Мұны «Жүйелік параметрлер» > «Қолданбалар» > «Жүктелгендер» тармағында қосыңыз."</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">"បើកវាឡើងវិញក្នុងការកំណត់ប្រព័ន្ធ > កម្មវិធី > ទាញយក។"</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">"ಸಿಸ್ಟಂ ಸೆಟ್ಟಿಂಗ್ಗಳು > ಅಪ್ಲಿಕೇಶನ್ಗಳು > ಡೌನ್ಲೋಡ್ ಆಗಿರುವುದರಲ್ಲಿ ಇದನ್ನು ಮರು ಸಕ್ರಿಯಗೊಳಿಸಿ."</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">"시스템 설정 > 앱 > 다운로드로 이동하여 이 모드를 다시 사용하도록 설정합니다."</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">"Муну тутум жөндөөлөрүнөн кайра иштетүү > Колдонмолор > Жүктөлүп алынган."</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“ > „Programos“ > „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 > Lietotnes > 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">"Повторно овозможете го ова во Системски поставки > Апликации > Преземено."</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">"സിസ്റ്റം ക്രമീകരണങ്ങൾ > അപ്ലിക്കേഷനുകൾ > ഡൗൺലോഡുചെയ്തവ എന്നതിൽ ഇത് വീണ്ടും പ്രവർത്തനക്ഷമമാക്കുക."</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">"Энийг Системийн тохиргоо > Апп > Татаж авсан дотроос дахин идэвхтэй болгох боломжтой."</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">"सिस्टम सेटिंग्ज > Apps > डाउनलोड केलेले मध्ये हे पुन्हा-सक्षम करा."</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 > Apl > 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">"ဒါကို စနစ် ဆက်တင်များထဲ ပြန်ဖွင့်ပေးရန် > Apps > ဒေါင်းလုဒ် လုပ်ပြီး။"</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 > Apper > 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">"प्रणाली सेटिङहरूमा यसलाई पुनःसक्षम गराउनुहोस् > अनुप्रयोगहरू > डाउनलोड गरेको।"</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 > Apps > 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">"ਸਿਸਟਮ ਸੈਟਿੰਗਾਂ > ਐਪਾਂ > ਡਾਊਨਲੋਡ ਕੀਤਿਆਂ ਵਿੱਚ ਇਸਨੂੰ ਮੁੜ-ਸਮਰੱਥ ਬਣਾਓ।"</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 > Aplikacje > 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 > Apps > 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 > Aplicações > 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 > Apps > 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 > Aplicații > 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">"Включить эту функцию можно в меню \"Настройки > Приложения > Загруженные\"."</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">"පද්ධති සැකසීම් තුළ මෙය නැවත ක්රියාත්මක කරන්න > යෙදුම් > බාගන්නා ලදි."</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 > Aplikácie > 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 > Aplikacije > 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\" > \"Aplikacionet\" > \"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">"Поново омогућите у менију Системска подешавања > Апликације > Преузето."</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 > Appar > 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 > Programu > 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">"சிஸ்டம் அமைப்பு > பயன்பாடுகள் > பதிவிறக்கம் என்பதில் இதை மீண்டும் இயக்கவும்."</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">"సిస్టమ్ సెట్టింగ్లు > అనువర్తనాలు > డౌన్లోడ్ చేసినవిలో దీన్ని పునఃప్రారంభించండి."</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">"เปิดใช้งานอีกครั้งในการตั้งค่าระบบ > แอปพลิเคชัน > ดาวน์โหลด"</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 > Apps > 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ı > Uygulamalar > İ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">"Знову ввімкнути це в меню Налаштування системи > Програми > Завантажені."</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">"سسٹم ترتیبات > ایپس > ڈاؤن لوڈ کردہ میں اسے دوبارہ فعال کریں۔"</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 > Ilovalar > 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 > Ứng dụng > Đã 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">"在“系统设置”>“应用”>“已下载”中重新启用此模式。"</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">"前往 [系統設定] > [應用程式] > [下載] 重新啟用這個模式。"</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">"前往 [系統設定] > [應用程式] > [下載] 重新啟用這個模式。"</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 > Izinhlelo zokusebenza > 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 > Apps > 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 & 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, ¤t_entry,
- ¤t_config, ¤t_flags)) {
+
+ FindEntryResult current_entry;
+ if (!loaded_package->FindEntry(type_idx, entry_id, *desired_config, ¤t_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 “input” and “output” are from the standpoint of the device. So a
-synthesizer will have an “input” port that receives messages. A keyboard will
-have an “output” port that sends messages.</p>
+<p>Note that “input” and “output” 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(©ing_adaptor, 1u);
pb::ResourceTable pb_table;
SerializeTableToPb(table, &pb_table);
- if (!pb_table.SerializeToZeroCopyStream(©ing_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(©ing_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(©ing_adaptor);
-
- // Number of CompiledFiles.
- output_stream.WriteLittleEndian32(1);
+ ContainerWriter container_writer(©ing_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(©ing_adaptor);
+ ContainerWriter container_writer(©ing_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/*/*.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/*/*.java -d out/
* pushd out
* jar cfe lockedregioncodeinjection.jar lockedregioncodeinjection.Main */*.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);
}
}