Merge "Fix the focus not move to the place where the finger clicks"
diff --git a/Android.bp b/Android.bp
index 6b55cc9..c90e00c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -580,6 +580,7 @@
aidl: {
generate_get_transaction_name: true,
local_include_dirs: ["media/aidl"],
+ include_dirs: ["frameworks/av/aidl"],
},
dxflags: [
"--core-library",
@@ -596,6 +597,7 @@
"framework-platform-compat-config",
// TODO: remove gps_debug and protolog.conf.json when the build system propagates "required" properly.
"gps_debug.conf",
+ "icu4j-platform-compat-config",
"libcore-platform-compat-config",
"protolog.conf.json.gz",
"services-platform-compat-config",
@@ -614,6 +616,7 @@
// If MimeMap ever becomes its own APEX, then this dependency would need to be removed
// in favor of an API stubs dependency in java_library "framework" below.
"mimemap",
+ "av-types-aidl-java",
"mediatranscoding_aidl_interface-java",
"soundtrigger_middleware-aidl-java",
],
diff --git a/ApiDocs.bp b/ApiDocs.bp
index faa0e5d..7ed7ec5 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -86,6 +86,7 @@
// TODO(b/169090544): remove below aidl includes.
aidl: {
local_include_dirs: ["media/aidl"],
+ include_dirs: ["frameworks/av/aidl"],
},
}
@@ -157,6 +158,7 @@
// TODO(b/169090544): remove below aidl includes.
aidl: {
local_include_dirs: ["media/aidl"],
+ include_dirs: ["frameworks/av/aidl"],
},
}
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 8090bec..228b3da 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -57,6 +57,7 @@
"telephony/java",
"media/aidl",
],
+ include_dirs: ["frameworks/av/aidl"],
},
// These are libs from framework-internal-utils that are required (i.e. being referenced)
// from framework-non-updatable-sources. Add more here when there's a need.
@@ -338,19 +339,6 @@
"framework-wifi.stubs",
"private-stub-annotations-jar",
],
- defaults: ["android_defaults_stubs_current"],
-}
-
-java_library_static {
- name: "android_stubs_current",
- static_libs: ["android_merged_stubs_current"],
- defaults: ["android_defaults_stubs_current"],
-}
-
-java_library_static {
- name: "android_system_monolith_stubs_current",
- srcs: [ ":system-api-stubs-docs" ],
- static_libs: [ "private-stub-annotations-jar" ],
defaults: [
"android_defaults_stubs_current",
"android_stubs_dists_default",
@@ -369,6 +357,21 @@
}
java_library_static {
+ name: "android_stubs_current",
+ static_libs: ["android_merged_stubs_current"],
+ defaults: ["android_defaults_stubs_current"],
+}
+
+java_library_static {
+ name: "android_system_monolith_stubs_current",
+ srcs: [ ":system-api-stubs-docs" ],
+ static_libs: [ "private-stub-annotations-jar" ],
+ defaults: [
+ "android_defaults_stubs_current",
+ ],
+}
+
+java_library_static {
name: "android_system_merged_stubs_current",
srcs: [ ":system-api-stubs-docs-non-updatable" ],
static_libs: [
diff --git a/apct-tests/perftests/core/src/android/text/VariableFontPerfTest.java b/apct-tests/perftests/core/src/android/text/VariableFontPerfTest.java
new file mode 100644
index 0000000..fbe67a4
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/text/VariableFontPerfTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 android.graphics.Paint;
+import android.graphics.RecordingCanvas;
+import android.graphics.RenderNode;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Random;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class VariableFontPerfTest {
+ private static final int WORD_LENGTH = 9; // Random word has 9 characters.
+ private static final boolean NO_STYLE_TEXT = false;
+
+ private static final TextPaint PAINT = new TextPaint();
+
+ public VariableFontPerfTest() {}
+
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private final TextPerfUtils mTextUtil = new TextPerfUtils();
+
+ @Before
+ public void setUp() {
+ mTextUtil.resetRandom(0 /* seed */);
+ }
+
+ @Test
+ public void testDraw_SetVariationOnce() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+ final Paint paint = new Paint(PAINT);
+ paint.setFontVariationSettings("'wght' 700");
+ final RenderNode node = RenderNode.create("benchmark", null);
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final RecordingCanvas c = node.beginRecording(1200, 200);
+ state.resumeTiming();
+
+ c.drawText(text, 0, text.length(), 0, 100, paint);
+
+ state.pauseTiming();
+ node.endRecording();
+ state.resumeTiming();
+
+ }
+ }
+
+ @Test
+ public void testDraw_SetVariationEachDraw() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+ final Paint paint = new Paint(PAINT);
+ final RenderNode node = RenderNode.create("benchmark", null);
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final RecordingCanvas c = node.beginRecording(1200, 200);
+ paint.setFontVariationSettings("'wght' 700");
+ state.resumeTiming();
+
+ c.drawText(text, 0, text.length(), 0, 100, paint);
+
+ state.pauseTiming();
+ node.endRecording();
+ state.resumeTiming();
+
+ }
+ }
+
+ @Test
+ public void testDraw_SetDifferentVariationEachDraw() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+ final Paint paint = new Paint(PAINT);
+ final RenderNode node = RenderNode.create("benchmark", null);
+ final Random random = new Random(0);
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final RecordingCanvas c = node.beginRecording(1200, 200);
+ int weight = random.nextInt(1000);
+ paint.setFontVariationSettings("'wght' " + weight);
+ state.resumeTiming();
+
+ c.drawText(text, 0, text.length(), 0, 100, paint);
+
+ state.pauseTiming();
+ node.endRecording();
+ state.resumeTiming();
+ }
+ }
+
+ @Test
+ public void testSetFontVariationSettings() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final Paint paint = new Paint(PAINT);
+ final Random random = new Random(0);
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ int weight = random.nextInt(1000);
+ state.resumeTiming();
+
+ paint.setFontVariationSettings("'wght' " + weight);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java b/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java
index f4ad5dd..c48fa4f 100644
--- a/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java
@@ -43,8 +43,8 @@
@Parameters(name = "{0}")
public static Collection cases() {
return Arrays.asList(new Object[][] {
- { "10x30K", 10, 30000 },
- { "300x1K", 300, 1000 },
+ { "10x3K", 10, 3000 },
+ { "30x1K", 30, 1000 },
});
}
diff --git a/apex/Android.bp b/apex/Android.bp
index c5b4901..0a535a8 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -112,6 +112,8 @@
],
stubs_source_visibility: ["//visibility:private"],
+ defaults_visibility: ["//visibility:private"],
+
// Collates API usages from each module for further analysis.
plugins: ["java_api_finder"],
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index c8a04d6..d4ea7af 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -268,6 +268,7 @@
*/
Bundle mIdleOptions;
+ // TODO(b/172085676): Move inside alarm store.
private final SparseArray<AlarmManager.AlarmClockInfo> mNextAlarmClockForUser =
new SparseArray<>();
private final SparseArray<AlarmManager.AlarmClockInfo> mTmpSparseAlarmClockArray =
@@ -276,6 +277,9 @@
new SparseBooleanArray();
private boolean mNextAlarmClockMayChange;
+ @GuardedBy("mLock")
+ private final Runnable mAlarmClockUpdater = () -> mNextAlarmClockMayChange = true;
+
// May only use on mHandler's thread, locking not required.
private final SparseArray<AlarmManager.AlarmClockInfo> mHandlerSparseAlarmClockArray =
new SparseArray<>();
@@ -410,6 +414,9 @@
private static final String KEY_APP_STANDBY_RESTRICTED_WINDOW =
"app_standby_restricted_window";
+ @VisibleForTesting
+ static final String KEY_LAZY_BATCHING = "lazy_batching";
+
private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
private static final long DEFAULT_MAX_INTERVAL = 365 * DateUtils.DAY_IN_MILLIS;
@@ -432,6 +439,8 @@
private static final int DEFAULT_APP_STANDBY_RESTRICTED_QUOTA = 1;
private static final long DEFAULT_APP_STANDBY_RESTRICTED_WINDOW = MILLIS_IN_DAY;
+ private static final boolean DEFAULT_LAZY_BATCHING = true;
+
// Minimum futurity of a new alarm
public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY;
@@ -460,6 +469,8 @@
public int APP_STANDBY_RESTRICTED_QUOTA = DEFAULT_APP_STANDBY_RESTRICTED_QUOTA;
public long APP_STANDBY_RESTRICTED_WINDOW = DEFAULT_APP_STANDBY_RESTRICTED_WINDOW;
+ public boolean LAZY_BATCHING = DEFAULT_LAZY_BATCHING;
+
private long mLastAllowWhileIdleWhitelistDuration = -1;
Constants() {
@@ -538,6 +549,14 @@
case KEY_APP_STANDBY_RESTRICTED_WINDOW:
updateStandbyWindowsLocked();
break;
+ case KEY_LAZY_BATCHING:
+ final boolean oldLazyBatching = LAZY_BATCHING;
+ LAZY_BATCHING = properties.getBoolean(
+ KEY_LAZY_BATCHING, DEFAULT_LAZY_BATCHING);
+ if (oldLazyBatching != LAZY_BATCHING) {
+ migrateAlarmsToNewStoreLocked();
+ }
+ break;
default:
if (name.startsWith(KEY_PREFIX_STANDBY_QUOTA) && !standbyQuotaUpdated) {
// The quotas need to be updated in order, so we can't just rely
@@ -551,6 +570,15 @@
}
}
+ private void migrateAlarmsToNewStoreLocked() {
+ final AlarmStore newStore = LAZY_BATCHING ? new LazyAlarmStore()
+ : new BatchingAlarmStore();
+ final ArrayList<Alarm> allAlarms = mAlarmStore.remove((unused) -> true);
+ newStore.addAll(allAlarms);
+ mAlarmStore = newStore;
+ mAlarmStore.setAlarmClockRemovalListener(mAlarmClockUpdater);
+ }
+
private void updateStandbyQuotasLocked() {
// The bucket quotas need to be read as an atomic unit but the properties passed to
// onPropertiesChanged may only have one key populated at a time.
@@ -659,6 +687,9 @@
TimeUtils.formatDuration(APP_STANDBY_RESTRICTED_WINDOW, pw);
pw.println();
+ pw.print(KEY_LAZY_BATCHING, LAZY_BATCHING);
+ pw.println();
+
pw.decreaseIndent();
}
@@ -770,7 +801,7 @@
// minimum recurrence period or alarm futurity for us to be able to fuzz it
static final long MIN_FUZZABLE_INTERVAL = 10000;
@GuardedBy("mLock")
- final AlarmStore mAlarmStore;
+ AlarmStore mAlarmStore;
// set to non-null if in idle mode; while in this mode, any alarms we don't want
// to run during this time are rescehduled to go off after this alarm.
@@ -781,7 +812,6 @@
AlarmManagerService(Context context, Injector injector) {
super(context);
mInjector = injector;
- mAlarmStore = new BatchingAlarmStore(() -> mNextAlarmClockMayChange = true);
}
public AlarmManagerService(Context context) {
@@ -1219,6 +1249,11 @@
synchronized (mLock) {
mHandler = new AlarmHandler();
mConstants = new Constants();
+
+ mAlarmStore = mConstants.LAZY_BATCHING ? new LazyAlarmStore()
+ : new BatchingAlarmStore();
+ mAlarmStore.setAlarmClockRemovalListener(mAlarmClockUpdater);
+
mAppWakeupHistory = new AppWakeupHistory(Constants.DEFAULT_APP_STANDBY_WINDOW);
mNextWakeup = mNextNonWakeup = 0;
@@ -3055,12 +3090,13 @@
static final void dumpAlarmList(IndentingPrintWriter ipw, ArrayList<Alarm> list,
long nowELAPSED, SimpleDateFormat sdf) {
- for (int i = list.size() - 1; i >= 0; i--) {
+ final int n = list.size();
+ for (int i = n - 1; i >= 0; i--) {
final Alarm a = list.get(i);
final String label = Alarm.typeToString(a.type);
ipw.print(label);
ipw.print(" #");
- ipw.print(i);
+ ipw.print(n - i);
ipw.print(": ");
ipw.println(a);
ipw.increaseIndent();
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java
index 7a846b9..0e442d0 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java
@@ -40,6 +40,13 @@
void add(Alarm a);
/**
+ * Adds all the given alarms to this store.
+ *
+ * @param alarms The alarms to add.
+ */
+ void addAll(ArrayList<Alarm> alarms);
+
+ /**
* Removes alarms that pass the given predicate.
*
* @param whichAlarms The predicate describing the alarms to remove.
@@ -48,11 +55,17 @@
ArrayList<Alarm> remove(Predicate<Alarm> whichAlarms);
/**
+ * Set a listener to be invoked whenever an alarm clock is removed by a call to
+ * {@link #remove(Predicate) remove} from this store.
+ */
+ void setAlarmClockRemovalListener(Runnable listener);
+
+ /**
* Gets the earliest alarm with the flag {@link android.app.AlarmManager#FLAG_WAKE_FROM_IDLE}
* based on {@link Alarm#getWhenElapsed()}.
*
* @return An alarm object matching the description above or {@code null} if no such alarm was
- * found.
+ * found.
*/
Alarm getNextWakeFromIdleAlarm();
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java
index cbfe80b..e7edfb7 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java
@@ -41,45 +41,22 @@
*/
public class BatchingAlarmStore implements AlarmStore {
- private ArrayList<Batch> mAlarmBatches = new ArrayList<>();
+ private final ArrayList<Batch> mAlarmBatches = new ArrayList<>();
private int mSize;
- private AlarmClockRemovalListener mAlarmClockRemovalListener;
+ private Runnable mOnAlarmClockRemoved;
interface Stats {
int REBATCH_ALL_ALARMS = 0;
}
- final StatLogger mStatLogger = new StatLogger("Alarm store stats", new String[]{
+ final StatLogger mStatLogger = new StatLogger("BatchingAlarmStore stats", new String[]{
"REBATCH_ALL_ALARMS",
});
- private static final Comparator<Batch> sBatchOrder = (b1, b2) -> {
- long when1 = b1.mStart;
- long when2 = b2.mStart;
- if (when1 > when2) {
- return 1;
- }
- if (when1 < when2) {
- return -1;
- }
- return 0;
- };
+ private static final Comparator<Batch> sBatchOrder = Comparator.comparingLong(b -> b.mStart);
- private static final Comparator<Alarm> sIncreasingTimeOrder = (a1, a2) -> {
- long when1 = a1.getWhenElapsed();
- long when2 = a2.getWhenElapsed();
- if (when1 > when2) {
- return 1;
- }
- if (when1 < when2) {
- return -1;
- }
- return 0;
- };
-
- BatchingAlarmStore(AlarmClockRemovalListener listener) {
- mAlarmClockRemovalListener = listener;
- }
+ private static final Comparator<Alarm> sIncreasingTimeOrder = Comparator.comparingLong(
+ Alarm::getWhenElapsed);
@Override
public void add(Alarm a) {
@@ -88,6 +65,16 @@
}
@Override
+ public void addAll(ArrayList<Alarm> alarms) {
+ if (alarms == null) {
+ return;
+ }
+ for (final Alarm a : alarms) {
+ add(a);
+ }
+ }
+
+ @Override
public ArrayList<Alarm> remove(Predicate<Alarm> whichAlarms) {
final ArrayList<Alarm> removed = new ArrayList<>();
for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
@@ -106,6 +93,11 @@
}
@Override
+ public void setAlarmClockRemovalListener(Runnable listener) {
+ mOnAlarmClockRemoved = listener;
+ }
+
+ @Override
public Alarm getNextWakeFromIdleAlarm() {
for (final Batch batch : mAlarmBatches) {
if ((batch.mFlags & AlarmManager.FLAG_WAKE_FROM_IDLE) == 0) {
@@ -317,8 +309,8 @@
Alarm alarm = mAlarms.get(i);
if (predicate.test(alarm)) {
removed.add(mAlarms.remove(i));
- if (alarm.alarmClock != null && mAlarmClockRemovalListener != null) {
- mAlarmClockRemovalListener.onRemoved();
+ if (alarm.alarmClock != null && mOnAlarmClockRemoved != null) {
+ mOnAlarmClockRemoved.run();
}
if (isTimeTickAlarm(alarm)) {
// This code path is not invoked when delivering alarms, only when removing
@@ -388,9 +380,4 @@
proto.end(token);
}
}
-
- @FunctionalInterface
- interface AlarmClockRemovalListener {
- void onRemoved();
- }
}
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java
new file mode 100644
index 0000000..8ca1446
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.alarm;
+
+import static com.android.server.alarm.AlarmManagerService.TAG;
+import static com.android.server.alarm.AlarmManagerService.dumpAlarmList;
+import static com.android.server.alarm.AlarmManagerService.isTimeTickAlarm;
+
+import android.app.AlarmManager;
+import android.util.IndentingPrintWriter;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.util.StatLogger;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.function.Predicate;
+
+/**
+ * Lazy implementation of an alarm store.
+ * This keeps the alarms in a sorted list, and only batches them at the time of delivery.
+ */
+public class LazyAlarmStore implements AlarmStore {
+
+ private final ArrayList<Alarm> mAlarms = new ArrayList<>();
+ private Runnable mOnAlarmClockRemoved;
+
+ interface Stats {
+ int GET_NEXT_DELIVERY_TIME = 0;
+ int GET_NEXT_WAKEUP_DELIVERY_TIME = 1;
+ }
+
+ final StatLogger mStatLogger = new StatLogger("LazyAlarmStore stats", new String[]{
+ "GET_NEXT_DELIVERY_TIME",
+ "GET_NEXT_WAKEUP_DELIVERY_TIME",
+ });
+
+ // Decreasing time order because it is more efficient to remove from the tail of an array list.
+ private static final Comparator<Alarm> sDecreasingTimeOrder = Comparator.comparingLong(
+ Alarm::getWhenElapsed).reversed();
+
+ @Override
+ public void add(Alarm a) {
+ int index = Collections.binarySearch(mAlarms, a, sDecreasingTimeOrder);
+ if (index < 0) {
+ index = 0 - index - 1;
+ }
+ mAlarms.add(index, a);
+ }
+
+ @Override
+ public void addAll(ArrayList<Alarm> alarms) {
+ if (alarms == null) {
+ return;
+ }
+ mAlarms.addAll(alarms);
+ Collections.sort(alarms, sDecreasingTimeOrder);
+ }
+
+ @Override
+ public ArrayList<Alarm> remove(Predicate<Alarm> whichAlarms) {
+ final ArrayList<Alarm> removedAlarms = new ArrayList<>();
+ for (int i = mAlarms.size() - 1; i >= 0; i--) {
+ if (whichAlarms.test(mAlarms.get(i))) {
+ final Alarm removed = mAlarms.remove(i);
+ if (removed.alarmClock != null && mOnAlarmClockRemoved != null) {
+ mOnAlarmClockRemoved.run();
+ }
+ if (isTimeTickAlarm(removed)) {
+ // This code path is not invoked when delivering alarms, only when removing
+ // alarms due to the caller cancelling it or getting uninstalled, etc.
+ Slog.wtf(TAG, "Removed TIME_TICK alarm");
+ }
+ removedAlarms.add(removed);
+ }
+ }
+ return removedAlarms;
+ }
+
+ @Override
+ public void setAlarmClockRemovalListener(Runnable listener) {
+ mOnAlarmClockRemoved = listener;
+ }
+
+ @Override
+ public Alarm getNextWakeFromIdleAlarm() {
+ for (int i = mAlarms.size() - 1; i >= 0; i--) {
+ final Alarm alarm = mAlarms.get(i);
+ if ((alarm.flags & AlarmManager.FLAG_WAKE_FROM_IDLE) != 0) {
+ return alarm;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public int size() {
+ return mAlarms.size();
+ }
+
+ @Override
+ public long getNextWakeupDeliveryTime() {
+ final long start = mStatLogger.getTime();
+ long nextWakeup = 0;
+ for (int i = mAlarms.size() - 1; i >= 0; i--) {
+ final Alarm a = mAlarms.get(i);
+ if (!a.wakeup) {
+ continue;
+ }
+ if (nextWakeup == 0) {
+ nextWakeup = a.getMaxWhenElapsed();
+ } else {
+ if (a.getWhenElapsed() > nextWakeup) {
+ break;
+ }
+ nextWakeup = Math.min(nextWakeup, a.getMaxWhenElapsed());
+ }
+ }
+ mStatLogger.logDurationStat(Stats.GET_NEXT_WAKEUP_DELIVERY_TIME, start);
+ return nextWakeup;
+ }
+
+ @Override
+ public long getNextDeliveryTime() {
+ final long start = mStatLogger.getTime();
+ final int n = mAlarms.size();
+ if (n == 0) {
+ return 0;
+ }
+ long nextDelivery = mAlarms.get(n - 1).getMaxWhenElapsed();
+ for (int i = n - 2; i >= 0; i--) {
+ final Alarm a = mAlarms.get(i);
+ if (a.getWhenElapsed() > nextDelivery) {
+ break;
+ }
+ nextDelivery = Math.min(nextDelivery, a.getMaxWhenElapsed());
+ }
+ mStatLogger.logDurationStat(Stats.GET_NEXT_DELIVERY_TIME, start);
+ return nextDelivery;
+ }
+
+ @Override
+ public ArrayList<Alarm> removePendingAlarms(long nowElapsed) {
+ final ArrayList<Alarm> pending = new ArrayList<>();
+ final ArrayList<Alarm> standAlones = new ArrayList<>();
+
+ for (int i = mAlarms.size() - 1; i >= 0; i--) {
+ final Alarm alarm = mAlarms.get(i);
+ if (alarm.getWhenElapsed() > nowElapsed) {
+ break;
+ }
+ pending.add(alarm);
+ if ((alarm.flags & AlarmManager.FLAG_STANDALONE) != 0) {
+ standAlones.add(alarm);
+ }
+ }
+ if (!standAlones.isEmpty()) {
+ // If there are deliverable standalone alarms, others must not go out yet.
+ mAlarms.removeAll(standAlones);
+ return standAlones;
+ }
+ mAlarms.removeAll(pending);
+ return pending;
+ }
+
+ @Override
+ public boolean updateAlarmDeliveries(AlarmDeliveryCalculator deliveryCalculator) {
+ boolean changed = false;
+ for (final Alarm alarm : mAlarms) {
+ changed |= deliveryCalculator.updateAlarmDelivery(alarm);
+ }
+ if (changed) {
+ Collections.sort(mAlarms, sDecreasingTimeOrder);
+ }
+ return changed;
+ }
+
+ @Override
+ public ArrayList<Alarm> asList() {
+ final ArrayList<Alarm> copy = new ArrayList<>(mAlarms);
+ Collections.reverse(copy);
+ return copy;
+ }
+
+ @Override
+ public void dump(IndentingPrintWriter ipw, long nowElapsed, SimpleDateFormat sdf) {
+ ipw.println(mAlarms.size() + " pending alarms: ");
+ ipw.increaseIndent();
+ dumpAlarmList(ipw, mAlarms, nowElapsed, sdf);
+ ipw.decreaseIndent();
+ mStatLogger.dump(ipw);
+ }
+
+ @Override
+ public void dumpProto(ProtoOutputStream pos, long nowElapsed) {
+ for (final Alarm a : mAlarms) {
+ a.dumpDebug(pos, AlarmManagerServiceDumpProto.PENDING_ALARMS, nowElapsed);
+ }
+ }
+}
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index b5e7224..fbda86f 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -54,6 +54,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -194,40 +195,38 @@
int numRecords = 0;
// Add in all the apps for every user/profile.
for (UserHandle userHandle : users) {
- List<PackageInfo> pi =
- pm.getInstalledPackagesAsUser(PackageManager.MATCH_UNINSTALLED_PACKAGES
- | PackageManager.MATCH_ANY_USER
- | PackageManager.MATCH_APEX,
- userHandle.getIdentifier());
- for (int j = 0; j < pi.size(); j++) {
- if (pi.get(j).applicationInfo != null) {
+ List<PackageInfo> packagesPlusApex = getAllPackagesWithApex(pm, userHandle);
+ for (int j = 0; j < packagesPlusApex.size(); j++) {
+ if (packagesPlusApex.get(j).applicationInfo != null) {
String installer;
try {
- installer = pm.getInstallerPackageName(pi.get(j).packageName);
+ installer = pm.getInstallerPackageName(
+ packagesPlusApex.get(j).packageName);
} catch (IllegalArgumentException e) {
installer = "";
}
long applicationInfoToken =
output.start(ProtoOutputStream.FIELD_TYPE_MESSAGE
| ProtoOutputStream.FIELD_COUNT_REPEATED
- | APPLICATION_INFO_FIELD_ID);
+ | APPLICATION_INFO_FIELD_ID);
output.write(ProtoOutputStream.FIELD_TYPE_INT32
- | ProtoOutputStream.FIELD_COUNT_SINGLE | UID_FIELD_ID,
- pi.get(j).applicationInfo.uid);
+ | ProtoOutputStream.FIELD_COUNT_SINGLE | UID_FIELD_ID,
+ packagesPlusApex.get(j).applicationInfo.uid);
output.write(ProtoOutputStream.FIELD_TYPE_INT64
- | ProtoOutputStream.FIELD_COUNT_SINGLE
- | VERSION_FIELD_ID, pi.get(j).getLongVersionCode());
+ | ProtoOutputStream.FIELD_COUNT_SINGLE
+ | VERSION_FIELD_ID,
+ packagesPlusApex.get(j).getLongVersionCode());
+ output.write(ProtoOutputStream.FIELD_TYPE_STRING
+ | ProtoOutputStream.FIELD_COUNT_SINGLE
+ | VERSION_STRING_FIELD_ID,
+ packagesPlusApex.get(j).versionName);
output.write(ProtoOutputStream.FIELD_TYPE_STRING
| ProtoOutputStream.FIELD_COUNT_SINGLE
- | VERSION_STRING_FIELD_ID,
- pi.get(j).versionName);
+ | PACKAGE_NAME_FIELD_ID, packagesPlusApex.get(j).packageName);
output.write(ProtoOutputStream.FIELD_TYPE_STRING
- | ProtoOutputStream.FIELD_COUNT_SINGLE
- | PACKAGE_NAME_FIELD_ID, pi.get(j).packageName);
- output.write(ProtoOutputStream.FIELD_TYPE_STRING
- | ProtoOutputStream.FIELD_COUNT_SINGLE
+ | ProtoOutputStream.FIELD_COUNT_SINGLE
| INSTALLER_FIELD_ID,
- installer == null ? "" : installer);
+ installer == null ? "" : installer);
numRecords++;
output.end(applicationInfoToken);
}
@@ -245,6 +244,26 @@
});
}
+ private static List<PackageInfo> getAllPackagesWithApex(PackageManager pm,
+ UserHandle userHandle) {
+ // We want all the uninstalled packages because uninstalled package uids can still be logged
+ // to statsd.
+ List<PackageInfo> allPackages = new ArrayList<>(
+ pm.getInstalledPackagesAsUser(PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_ANY_USER,
+ userHandle.getIdentifier()));
+ // We make a second query to package manager for the apex modules because package manager
+ // returns both installed and uninstalled apexes with
+ // PackageManager.MATCH_UNINSTALLED_PACKAGES flag. We only want active apexes because
+ // inactive apexes can conflict with active ones.
+ for (PackageInfo packageInfo : pm.getInstalledPackages(PackageManager.MATCH_APEX)) {
+ if (packageInfo.isApex) {
+ allPackages.add(packageInfo);
+ }
+ }
+ return allPackages;
+ }
+
private static class WakelockThread extends Thread {
private final PowerManager.WakeLock mWl;
private final Runnable mRunnable;
diff --git a/api/Android.bp b/api/Android.bp
index 21a7166..28b7594 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -16,25 +16,6 @@
default_visibility: ["//visibility:private"],
}
-// *-current.txt files for use by modules in other directories like cts
-filegroup {
- name: "frameworks-base-api-current.txt",
- srcs: ["current.txt"],
- visibility: ["//visibility:public"],
-}
-
-filegroup {
- name: "frameworks-base-api-system-current.txt",
- srcs: ["system-current.txt"],
- visibility: ["//visibility:public"],
-}
-
-filegroup {
- name: "frameworks-base-api-system-removed.txt",
- srcs: ["system-removed.txt"],
- visibility: ["//visibility:public"],
-}
-
genrule {
name: "current-api-xml",
tools: ["metalava"],
@@ -45,7 +26,7 @@
}
genrule {
- name: "frameworks-base-api-current-merged.txt",
+ name: "frameworks-base-api-current.txt",
srcs: [
":conscrypt.module.public.api{.public.api.txt}",
":framework-appsearch{.public.api.txt}",
@@ -74,10 +55,11 @@
dest: "android.txt",
},
],
+ visibility: ["//visibility:public"],
}
genrule {
- name: "frameworks-base-api-removed-merged.txt",
+ name: "frameworks-base-api-removed.txt",
srcs: [
":conscrypt.module.public.api{.public.removed-api.txt}",
":framework-appsearch{.public.removed-api.txt}",
@@ -104,7 +86,7 @@
}
genrule {
- name: "frameworks-base-api-system-current-merged.txt",
+ name: "frameworks-base-api-system-current.txt",
srcs: [
":framework-appsearch{.system.api.txt}",
":framework-graphics{.system.api.txt}",
@@ -132,10 +114,11 @@
dest: "android.txt",
},
],
+ visibility: ["//visibility:public"],
}
genrule {
- name: "frameworks-base-api-system-removed-merged.txt",
+ name: "frameworks-base-api-system-removed.txt",
srcs: [
":framework-appsearch{.system.removed-api.txt}",
":framework-graphics{.system.removed-api.txt}",
@@ -158,10 +141,11 @@
dest: "system-removed.txt",
},
],
+ visibility: ["//visibility:public"],
}
genrule {
- name: "frameworks-base-api-module-lib-current-merged.txt",
+ name: "frameworks-base-api-module-lib-current.txt",
srcs: [
":framework-appsearch{.module-lib.api.txt}",
":framework-graphics{.module-lib.api.txt}",
@@ -192,7 +176,7 @@
}
genrule {
- name: "frameworks-base-api-module-lib-removed-merged.txt",
+ name: "frameworks-base-api-module-lib-removed.txt",
srcs: [
":framework-appsearch{.module-lib.removed-api.txt}",
":framework-graphics{.module-lib.removed-api.txt}",
@@ -220,8 +204,8 @@
genrule {
name: "combined-removed-dex",
srcs: [
- ":frameworks-base-api-removed-merged.txt",
- ":frameworks-base-api-system-removed-merged.txt",
+ ":frameworks-base-api-removed.txt",
+ ":frameworks-base-api-system-removed.txt",
":android.car-stubs-docs{.removed-api.txt}",
":android.car-system-stubs-docs{.removed-api.txt}",
],
diff --git a/api/current.txt b/api/current.txt
index 6459eb4..93eb32c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5528,6 +5528,7 @@
field @Deprecated public static final String EXTRA_PEOPLE = "android.people";
field public static final String EXTRA_PEOPLE_LIST = "android.people.list";
field public static final String EXTRA_PICTURE = "android.picture";
+ field public static final String EXTRA_PICTURE_CONTENT_DESCRIPTION = "android.pictureContentDescription";
field public static final String EXTRA_PROGRESS = "android.progress";
field public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
field public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
@@ -5673,6 +5674,7 @@
method public android.app.Notification.BigPictureStyle bigLargeIcon(android.graphics.Bitmap);
method public android.app.Notification.BigPictureStyle bigLargeIcon(android.graphics.drawable.Icon);
method public android.app.Notification.BigPictureStyle bigPicture(android.graphics.Bitmap);
+ method @NonNull public android.app.Notification.BigPictureStyle bigPictureContentDescription(@Nullable CharSequence);
method public android.app.Notification.BigPictureStyle setBigContentTitle(CharSequence);
method public android.app.Notification.BigPictureStyle setSummaryText(CharSequence);
}
@@ -5972,6 +5974,7 @@
method public long[] getVibrationPattern();
method public boolean hasUserSetImportance();
method public boolean hasUserSetSound();
+ method public boolean isConversation();
method public boolean isDemoted();
method public boolean isImportantConversation();
method public void setAllowBubbles(boolean);
@@ -6138,6 +6141,7 @@
method public android.content.IntentSender getIntentSender();
method public static android.app.PendingIntent getService(android.content.Context, int, @NonNull android.content.Intent, int);
method @Deprecated public String getTargetPackage();
+ method public boolean isImmutable();
method @Nullable public static android.app.PendingIntent readPendingIntentOrNullFromParcel(@NonNull android.os.Parcel);
method public void send() throws android.app.PendingIntent.CanceledException;
method public void send(int) throws android.app.PendingIntent.CanceledException;
@@ -10679,8 +10683,6 @@
field public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED";
field public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED";
field public static final String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED";
- field public static final String ACTION_PACKAGE_STARTABLE = "android.intent.action.PACKAGE_STARTABLE";
- field public static final String ACTION_PACKAGE_UNSTARTABLE = "android.intent.action.PACKAGE_UNSTARTABLE";
field public static final String ACTION_PACKAGE_VERIFIED = "android.intent.action.PACKAGE_VERIFIED";
field public static final String ACTION_PASTE = "android.intent.action.PASTE";
field public static final String ACTION_PICK = "android.intent.action.PICK";
@@ -12308,9 +12310,6 @@
field public static final int SYNCHRONOUS = 2; // 0x2
field @Nullable public static final java.util.List<java.security.cert.Certificate> TRUST_ALL;
field @NonNull public static final java.util.List<java.security.cert.Certificate> TRUST_NONE;
- field public static final int UNSTARTABLE_REASON_CONNECTION_ERROR = 1; // 0x1
- field public static final int UNSTARTABLE_REASON_INSUFFICIENT_STORAGE = 2; // 0x2
- field public static final int UNSTARTABLE_REASON_UNKNOWN = 0; // 0x0
field public static final int VERIFICATION_ALLOW = 1; // 0x1
field public static final int VERIFICATION_REJECT = -1; // 0xffffffff
field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff
@@ -16427,6 +16426,7 @@
method public void getMetrics(@NonNull android.graphics.Paint, @Nullable android.graphics.Paint.FontMetrics);
method @NonNull public android.graphics.fonts.FontStyle getStyle();
method @IntRange(from=0) public int getTtcIndex();
+ method public boolean isSameSource(@NonNull android.graphics.fonts.Font);
}
public static final class Font.Builder {
@@ -25274,6 +25274,7 @@
public final class MediaCas implements java.lang.AutoCloseable {
ctor public MediaCas(int) throws android.media.MediaCasException.UnsupportedCasException;
ctor public MediaCas(@NonNull android.content.Context, int, @Nullable String, int) throws android.media.MediaCasException.UnsupportedCasException;
+ ctor public MediaCas(@NonNull android.content.Context, int, @Nullable String, int, @Nullable android.os.Handler, @Nullable android.media.MediaCas.EventListener) throws android.media.MediaCasException.UnsupportedCasException;
method public void close();
method public static android.media.MediaCas.PluginDescriptor[] enumeratePlugins();
method protected void finalize();
@@ -31405,6 +31406,7 @@
field @Deprecated public String FQDN;
field @Deprecated public static final int SECURITY_TYPE_EAP = 3; // 0x3
field @Deprecated public static final int SECURITY_TYPE_EAP_SUITE_B = 5; // 0x5
+ field @Deprecated public static final int SECURITY_TYPE_EAP_WPA3_ENTERPRISE = 9; // 0x9
field @Deprecated public static final int SECURITY_TYPE_OPEN = 0; // 0x0
field @Deprecated public static final int SECURITY_TYPE_OWE = 6; // 0x6
field @Deprecated public static final int SECURITY_TYPE_PSK = 2; // 0x2
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
deleted file mode 100644
index 8ca290f..0000000
--- a/api/module-lib-current.txt
+++ /dev/null
@@ -1,222 +0,0 @@
-// Signature format: 2.0
-package android.app {
-
- public class ActivityManager {
- method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void addHomeVisibilityListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.HomeVisibilityListener);
- method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void removeHomeVisibilityListener(@NonNull android.app.HomeVisibilityListener);
- }
-
- public class AppOpsManager {
- field public static final String OPSTR_NO_ISOLATED_STORAGE = "android:no_isolated_storage";
- }
-
- public abstract class HomeVisibilityListener {
- ctor public HomeVisibilityListener();
- method public abstract void onHomeVisibilityChanged(boolean);
- }
-
- public class NotificationManager {
- method public boolean hasEnabledNotificationListener(@NonNull String, @NonNull android.os.UserHandle);
- field public static final String ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED = "android.app.action.NOTIFICATION_LISTENER_ENABLED_CHANGED";
- }
-
- public class StatusBarManager {
- method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setExpansionDisabledForSimNetworkLock(boolean);
- }
-
-}
-
-package android.app.role {
-
- public final class RoleManager {
- method @Nullable public String getSmsRoleHolder(int);
- }
-
-}
-
-package android.content.rollback {
-
- public class RollbackManagerFrameworkInitializer {
- method public static void initialize();
- }
-
-}
-
-package android.graphics {
-
- public final class Compatibility {
- method public static void setTargetSdkVersion(int);
- }
-
- public final class ImageDecoder implements java.lang.AutoCloseable {
- method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(@NonNull android.content.ContentResolver, @NonNull android.net.Uri, @Nullable android.content.res.Resources);
- }
-
-}
-
-package android.media {
-
- public class AudioManager {
- method public void adjustStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
- method public void adjustSuggestedStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
- method public void setStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
- field public static final int FLAG_FROM_KEY = 4096; // 0x1000
- }
-
- public class MediaMetadataRetriever implements java.lang.AutoCloseable {
- field public static final int METADATA_KEY_VIDEO_CODEC_MIME_TYPE = 40; // 0x28
- }
-
- @Deprecated public final class MediaParceledListSlice<T extends android.os.Parcelable> implements android.os.Parcelable {
- ctor @Deprecated public MediaParceledListSlice(@NonNull java.util.List<T>);
- method @Deprecated public int describeContents();
- method @Deprecated @NonNull public static <T extends android.os.Parcelable> android.media.MediaParceledListSlice<T> emptyList();
- method @Deprecated public java.util.List<T> getList();
- method @Deprecated public void setInlineCountLimit(int);
- method @Deprecated public void writeToParcel(android.os.Parcel, int);
- field @Deprecated @NonNull public static final android.os.Parcelable.ClassLoaderCreator<android.media.MediaParceledListSlice> CREATOR;
- }
-
-}
-
-package android.media.session {
-
- public static final class MediaController.PlaybackInfo implements android.os.Parcelable {
- ctor public MediaController.PlaybackInfo(int, int, @IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.media.AudioAttributes, @Nullable String);
- }
-
- public final class MediaSession {
- field public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 65536; // 0x10000
- }
-
- public static final class MediaSession.Token implements android.os.Parcelable {
- method public int getUid();
- }
-
- public final class MediaSessionManager {
- method public void addOnActiveSessionsChangedListener(@NonNull android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, @Nullable android.content.ComponentName, int, @Nullable android.os.Handler);
- method public void dispatchMediaKeyEventAsSystemService(@NonNull android.view.KeyEvent);
- method public boolean dispatchMediaKeyEventToSessionAsSystemService(@NonNull android.view.KeyEvent, @NonNull android.media.session.MediaSession.Token);
- method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.view.KeyEvent, int);
- method public void dispatchVolumeKeyEventToSessionAsSystemService(@NonNull android.view.KeyEvent, @NonNull android.media.session.MediaSession.Token);
- field public static final int RESULT_MEDIA_KEY_HANDLED = 1; // 0x1
- field public static final int RESULT_MEDIA_KEY_NOT_HANDLED = 0; // 0x0
- }
-
- public final class PlaybackState implements android.os.Parcelable {
- method public boolean isActiveState();
- }
-
-}
-
-package android.net {
-
- public final class TetheringConstants {
- field public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
- field public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
- field public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
- field public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
- field public static final String EXTRA_SET_ALARM = "extraSetAlarm";
- }
-
- public class TetheringManager {
- ctor public TetheringManager(@NonNull android.content.Context, @NonNull java.util.function.Supplier<android.os.IBinder>);
- method public int getLastTetherError(@NonNull String);
- method @NonNull public String[] getTetherableBluetoothRegexs();
- method @NonNull public String[] getTetherableIfaces();
- method @NonNull public String[] getTetherableUsbRegexs();
- method @NonNull public String[] getTetherableWifiRegexs();
- method @NonNull public String[] getTetheredIfaces();
- method @NonNull public String[] getTetheringErroredIfaces();
- method public boolean isTetheringSupported();
- method public boolean isTetheringSupported(@NonNull String);
- method public void requestLatestTetheringEntitlementResult(int, @NonNull android.os.ResultReceiver, boolean);
- method @Deprecated public int setUsbTethering(boolean);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
- method @Deprecated public int tether(@NonNull String);
- method @Deprecated public int untether(@NonNull String);
- }
-
- public static interface TetheringManager.TetheringEventCallback {
- method public default void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
- }
-
- public static class TetheringManager.TetheringInterfaceRegexps {
- method @NonNull public java.util.List<java.lang.String> getTetherableBluetoothRegexs();
- method @NonNull public java.util.List<java.lang.String> getTetherableUsbRegexs();
- method @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
- }
-
-}
-
-package android.os {
-
- public class Binder implements android.os.IBinder {
- method public final void markVintfStability();
- }
-
- public interface Parcelable {
- method public default int getStability();
- }
-
- public class StatsFrameworkInitializer {
- method public static void registerServiceWrappers();
- method public static void setStatsServiceManager(@NonNull android.os.StatsServiceManager);
- }
-
- public class StatsServiceManager {
- method @NonNull public android.os.StatsServiceManager.ServiceRegisterer getStatsCompanionServiceRegisterer();
- method @NonNull public android.os.StatsServiceManager.ServiceRegisterer getStatsManagerServiceRegisterer();
- method @NonNull public android.os.StatsServiceManager.ServiceRegisterer getStatsdServiceRegisterer();
- }
-
- public static class StatsServiceManager.ServiceNotFoundException extends java.lang.Exception {
- ctor public StatsServiceManager.ServiceNotFoundException(@NonNull String);
- }
-
- public static final class StatsServiceManager.ServiceRegisterer {
- method @Nullable public android.os.IBinder get();
- method @Nullable public android.os.IBinder getOrThrow() throws android.os.StatsServiceManager.ServiceNotFoundException;
- }
-
-}
-
-package android.provider {
-
- public final class DeviceConfig {
- field public static final String NAMESPACE_ALARM_MANAGER = "alarm_manager";
- field public static final String NAMESPACE_APP_STANDBY = "app_standby";
- field public static final String NAMESPACE_DEVICE_IDLE = "device_idle";
- }
-
-}
-
-package android.telephony {
-
- public abstract class CellSignalStrength {
- method public static int getNumSignalStrengthLevels();
- }
-
- public class TelephonyManager {
- method @NonNull public static int[] getAllNetworkTypes();
- }
-
-}
-
-package android.util {
-
- public class AtomicFile {
- ctor public AtomicFile(@NonNull java.io.File, @Nullable android.util.SystemConfigFileCommitEventLogger);
- }
-
- public final class Log {
- method public static int logToRadioBuffer(int, @Nullable String, @Nullable String);
- }
-
- public class SystemConfigFileCommitEventLogger {
- ctor public SystemConfigFileCommitEventLogger(@NonNull String);
- method public void setStartTime(long);
- }
-
-}
-
diff --git a/api/module-lib-lint-baseline.txt b/api/module-lib-lint-baseline.txt
deleted file mode 100644
index 56f7a02..0000000
--- a/api/module-lib-lint-baseline.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-// Baseline format: 1.0
-ActionValue: android.net.TetheringConstants#EXTRA_ADD_TETHER_TYPE:
- Inconsistent extra value; expected `android.net.extra.ADD_TETHER_TYPE`, was `extraAddTetherType`
-ActionValue: android.net.TetheringConstants#EXTRA_PROVISION_CALLBACK:
- Inconsistent extra value; expected `android.net.extra.PROVISION_CALLBACK`, was `extraProvisionCallback`
-ActionValue: android.net.TetheringConstants#EXTRA_REM_TETHER_TYPE:
- Inconsistent extra value; expected `android.net.extra.REM_TETHER_TYPE`, was `extraRemTetherType`
-ActionValue: android.net.TetheringConstants#EXTRA_RUN_PROVISION:
- Inconsistent extra value; expected `android.net.extra.RUN_PROVISION`, was `extraRunProvision`
-ActionValue: android.net.TetheringConstants#EXTRA_SET_ALARM:
- Inconsistent extra value; expected `android.net.extra.SET_ALARM`, was `extraSetAlarm`
-ActionValue: android.net.TetheringManager#ACTION_TETHER_STATE_CHANGED:
- Inconsistent action value; expected `android.net.action.TETHER_STATE_CHANGED`, was `android.net.conn.TETHER_STATE_CHANGED`
-ActionValue: android.net.TetheringManager#EXTRA_ACTIVE_TETHER:
- Inconsistent extra value; expected `android.net.extra.ACTIVE_TETHER`, was `tetherArray`
-ActionValue: android.net.TetheringManager#EXTRA_AVAILABLE_TETHER:
- Inconsistent extra value; expected `android.net.extra.AVAILABLE_TETHER`, was `availableArray`
-ActionValue: android.net.TetheringManager#EXTRA_ERRORED_TETHER:
- Inconsistent extra value; expected `android.net.extra.ERRORED_TETHER`, was `erroredArray`
-
-
-ManagerConstructor: android.net.TetheringManager#TetheringManager(android.content.Context, java.util.function.Supplier<android.os.IBinder>):
- Managers must always be obtained from Context; no direct constructors
-
-
-PrivateSuperclass: android.location.GnssAntennaInfo.PhaseCenterVariationCorrections:
- Public class android.location.GnssAntennaInfo.PhaseCenterVariationCorrections extends private class android.location.GnssAntennaInfo.SphericalCorrections
-PrivateSuperclass: android.location.GnssAntennaInfo.SignalGainCorrections:
- Public class android.location.GnssAntennaInfo.SignalGainCorrections extends private class android.location.GnssAntennaInfo.SphericalCorrections
diff --git a/api/module-lib-removed.txt b/api/module-lib-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/api/module-lib-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/api/system-current.txt b/api/system-current.txt
index fa3c71c..115b4d8 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5090,6 +5090,7 @@
field public static final int INVALID_AV_SYNC_ID = -1; // 0xffffffff
field public static final int INVALID_FILTER_ID = -1; // 0xffffffff
field public static final long INVALID_FILTER_ID_64BIT = -1L; // 0xffffffffffffffffL
+ field public static final int INVALID_FIRST_MACROBLOCK_IN_SLICE = -1; // 0xffffffff
field public static final int INVALID_FRONTEND_SETTING_FREQUENCY = -1; // 0xffffffff
field public static final int INVALID_LTS_ID = -1; // 0xffffffff
field public static final int INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM = -1; // 0xffffffff
@@ -5390,6 +5391,7 @@
public class MmtpRecordEvent extends android.media.tv.tuner.filter.FilterEvent {
method public long getDataLength();
+ method public int getFirstMbInSlice();
method public int getMpuSequenceNumber();
method public long getPts();
method public int getScHevcIndexMask();
@@ -5430,9 +5432,14 @@
field public static final int SC_HEVC_INDEX_SLICE_TRAIL_CRA = 128; // 0x80
field public static final int SC_HEVC_INDEX_SPS = 1; // 0x1
field public static final int SC_INDEX_B_FRAME = 4; // 0x4
+ field public static final int SC_INDEX_B_SLICE = 64; // 0x40
field public static final int SC_INDEX_I_FRAME = 1; // 0x1
+ field public static final int SC_INDEX_I_SLICE = 16; // 0x10
field public static final int SC_INDEX_P_FRAME = 2; // 0x2
+ field public static final int SC_INDEX_P_SLICE = 32; // 0x20
field public static final int SC_INDEX_SEQUENCE = 8; // 0x8
+ field public static final int SC_INDEX_SI_SLICE = 128; // 0x80
+ field public static final int SC_INDEX_SP_SLICE = 256; // 0x100
field public static final int TS_INDEX_ADAPTATION_EXTENSION_FLAG = 4096; // 0x1000
field public static final int TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED = 8; // 0x8
field public static final int TS_INDEX_CHANGE_TO_NOT_SCRAMBLED = 4; // 0x4
@@ -5553,6 +5560,7 @@
public class TsRecordEvent extends android.media.tv.tuner.filter.FilterEvent {
method public long getDataLength();
+ method public int getFirstMbInSlice();
method public int getPacketId();
method public long getPts();
method public int getScIndexMask();
@@ -5878,6 +5886,7 @@
public class DvbsFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
method @NonNull public static android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder builder();
method @Nullable public android.media.tv.tuner.frontend.DvbsCodeRate getCodeRate();
+ method public boolean getCouldHandleDiseqcRxMessage();
method public int getInputStreamId();
method public int getModulation();
method public int getPilot();
@@ -5887,7 +5896,6 @@
method public int getSymbolRate();
method public int getType();
method public int getVcmMode();
- method public boolean isDiseqcRxMessage();
field public static final int MODULATION_AUTO = 1; // 0x1
field public static final int MODULATION_MOD_128APSK = 2048; // 0x800
field public static final int MODULATION_MOD_16APSK = 256; // 0x100
@@ -5931,7 +5939,7 @@
public static class DvbsFrontendSettings.Builder {
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings build();
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setCodeRate(@Nullable android.media.tv.tuner.frontend.DvbsCodeRate);
- method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setDiseqcRxMessage(boolean);
+ method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setCouldHandleDiseqcRxMessage(boolean);
method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setFrequency(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setInputStreamId(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setModulation(int);
@@ -6071,7 +6079,7 @@
}
public abstract class FrontendSettings {
- method public int getEndFrequency();
+ method @IntRange(from=1) public int getEndFrequency();
method public int getFrequency();
method public int getFrontendSpectralInversion();
method public abstract int getType();
@@ -6353,6 +6361,7 @@
public interface ScanCallback {
method public void onAnalogSifStandardReported(int);
method public void onAtsc3PlpInfosReported(@NonNull android.media.tv.tuner.frontend.Atsc3PlpInfo[]);
+ method public default void onDvbcAnnexReported(int);
method public void onDvbsStandardReported(int);
method public void onDvbtStandardReported(int);
method public void onFrequenciesReported(@NonNull int[]);
@@ -9485,6 +9494,7 @@
field public static final String NAMESPACE_PACKAGE_MANAGER_SERVICE = "package_manager_service";
field public static final String NAMESPACE_PERMISSIONS = "permissions";
field public static final String NAMESPACE_PRIVACY = "privacy";
+ field public static final String NAMESPACE_PROFCOLLECT_NATIVE_BOOT = "profcollect_native_boot";
field public static final String NAMESPACE_ROLLBACK = "rollback";
field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
field public static final String NAMESPACE_RUNTIME = "runtime";
@@ -12336,6 +12346,17 @@
package android.telephony.ims {
+ public final class AudioCodecAttributes implements android.os.Parcelable {
+ ctor public AudioCodecAttributes(float, @NonNull android.util.Range<java.lang.Float>, float, @NonNull android.util.Range<java.lang.Float>);
+ method public int describeContents();
+ method public float getBandwidthKhz();
+ method @NonNull public android.util.Range<java.lang.Float> getBandwidthRangeKhz();
+ method public float getBitrateKbps();
+ method @NonNull public android.util.Range<java.lang.Float> getBitrateRangeKbps();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.AudioCodecAttributes> CREATOR;
+ }
+
public final class ImsCallForwardInfo implements android.os.Parcelable {
ctor public ImsCallForwardInfo(int, int, int, int, @NonNull String, int);
method public int describeContents();
@@ -12704,6 +12725,7 @@
ctor public ImsStreamMediaProfile(int, int, int, int, int);
method public void copyFrom(android.telephony.ims.ImsStreamMediaProfile);
method public int describeContents();
+ method @Nullable public android.telephony.ims.AudioCodecAttributes getAudioCodecAttributes();
method public int getAudioDirection();
method public int getAudioQuality();
method public int getRttMode();
@@ -12711,6 +12733,7 @@
method public int getVideoQuality();
method public boolean isReceivingRttAudio();
method public boolean isRttCall();
+ method public void setAudioCodecAttributes(@NonNull android.telephony.ims.AudioCodecAttributes);
method public void setReceivingRttAudio(boolean);
method public void setRttMode(int);
method public void writeToParcel(android.os.Parcel, int);
diff --git a/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java b/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
index 8683ca1..a0361d0 100644
--- a/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
+++ b/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
@@ -294,9 +294,9 @@
" -a|--authority <AUTHORITY>\n" +
" App-standby related options\n" +
"\n" +
- " -f|--foreground (cause WORKING_SET, FREQUENT sync adapters" +
- " to run immediately)\n" +
- " -F|--top (cause even RARE sync adapters to run immediately)\n" +
+ " -f|--foreground (defeat app-standby job throttling," +
+ " but not battery saver)\n" +
+ " -F|--top (defeat app-standby job throttling and battery saver)\n" +
" ContentResolver extra options:\n" +
" --is|--ignore-settings: Add SYNC_EXTRAS_IGNORE_SETTINGS\n" +
" --ib|--ignore-backoff: Add SYNC_EXTRAS_IGNORE_BACKOFF\n" +
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index ac2a8e4..b270a52 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -502,6 +502,7 @@
MediametricsMediaParserReported mediametrics_mediaparser_reported = 316;
TlsHandshakeReported tls_handshake_reported = 317 [(module) = "conscrypt"];
TextClassifierApiUsageReported text_classifier_api_usage_reported = 318 [(module) = "textclassifier"];
+ KilledAppStatsReported killed_app_stats_reported = 319 [(module) = "carwatchdogd"];
// StatsdStats tracks platform atoms with ids upto 500.
// Update StatsdStats::kMaxPushedAtomId when atom ids here approach that value.
@@ -4280,9 +4281,16 @@
optional android.stats.sysui.NotificationImportance old_importance = 5;
// New importance setting
optional android.stats.sysui.NotificationImportance importance = 6;
+ // whether or not this channel represents a conversation
+ optional bool is_conversation = 7;
+ // Hash of app-assigned notification conversation id
+ optional int32 conversation_id_hash = 8;
+ // whether or not the user demoted this channel out of the conversation space
+ optional bool is_conversation_demoted = 9;
+ // whether this conversation is marked as being a priority
+ optional bool is_conversation_priority = 10;
}
-
/**
* Logs when a biometric acquire event occurs.
*
@@ -5304,6 +5312,11 @@
LAUNCHER_APP_CLOSE_TO_HOME = 10;
LAUNCHER_APP_CLOSE_TO_PIP = 11;
LAUNCHER_QUICK_SWITCH = 12;
+ SHADE_HEADS_UP_APPEAR = 13;
+ SHADE_HEADS_UP_DISAPPEAR = 14;
+ SHADE_NOTIFICATION_ADD = 15;
+ SHADE_NOTIFICATION_REMOVE = 16;
+ SHADE_APP_LAUNCH = 17;
}
optional InteractionType interaction_type = 1;
@@ -12067,3 +12080,143 @@
optional ResultType result_type = 2;
optional int64 latency_millis = 3;
}
+
+/**
+ * Logs the current state of an application before it is killed.
+ *
+ * Pushed from:
+ * packages/services/Car/watchdog/server/src/ApplicationTerminator.cpp
+ */
+message KilledAppStatsReported {
+ // Linux process uid for the package.
+ optional int32 uid = 1 [(is_uid) = true];
+
+ // Name of the package that was killed.
+ optional string package_name = 2;
+
+ // State of the application when it was killed.
+ enum AppState {
+ UNKNOWN_APP_STATE = 0;
+ BACKGROUND = 1;
+ FOREGROUND = 2;
+ }
+ optional AppState app_state = 3;
+
+ // System state indicating whether the system was in normal mode or garage mode.
+ enum SystemState {
+ UNKNOWN_SYSTEM_STATE = 0;
+ USER_INTERACTION_MODE = 1;
+ NO_USER_INTERACTION_MODE = 2;
+ }
+ optional SystemState system_state = 4;
+
+ // Reason for killing the application.
+ // Keep in sync between:
+ // packages/services/Car/watchdog/server/src/ApplicationTerminator.h
+ // frameworks/base/cmds/statsd/src/atoms.proto
+ enum KillReason {
+ UNKNOWN_KILL_REASON = 0;
+ KILLED_ON_ANR = 1;
+ KILLED_ON_IO_OVERUSE = 2;
+ KILLED_ON_MEMORY_OVERUSE = 3;
+ }
+ optional KillReason kill_reason = 5;
+
+ // Stats of the processes owned by the application when the application was killed.
+ // The process stack traces are not collected when the application was killed due to IO_OVERUSE.
+ optional ProcessStats process_stat = 6 [(log_mode) = MODE_BYTES];
+
+ // The application's I/O overuse stats logged only when the kill reason is KILLED_ON_IO_OVERUSE.
+ optional IoOveruseStats io_overuse_stats = 7 [(log_mode) = MODE_BYTES];
+}
+
+/**
+ * Logs I/O overuse stats for a package.
+ *
+ * Keep in sync between:
+ * packages/services/Car/watchdog/server/src/proto/statsd.proto
+ * frameworks/base/cmds/statsd/src/atoms.proto
+ *
+ * Logged from:
+ * packages/services/Car/watchdog/server/src/ApplicationTerminator.cpp
+ */
+message IoOveruseStats {
+ enum Period {
+ DAILY = 0;
+ WEEKLY = 1;
+ }
+
+ // Threshold and usage stats period.
+ optional Period period = 1;
+
+ // Threshold in-terms of write bytes defined for the package.
+ optional PerStateBytes threshold = 2;
+
+ // Number of write bytes in each state for the specified period.
+ optional PerStateBytes written_bytes = 3;
+};
+
+/**
+ * Logs bytes attributed to each application and system states.
+ *
+ * Keep in sync between:
+ * packages/services/Car/watchdog/server/src/proto/statsd.proto
+ * frameworks/base/cmds/statsd/src/atoms.proto
+ *
+ * Logged from:
+ * packages/services/Car/watchdog/server/src/ApplicationTerminator.cpp
+ */
+message PerStateBytes {
+ // Number of bytes attributed to the application foreground.
+ optional int64 foreground_bytes = 1;
+
+ // Number of bytes attributed to the application background.
+ optional int64 background_bytes = 2;
+
+ // Number of bytes attributed to the garage mode.
+ optional int64 garage_mode_bytes = 3;
+}
+
+/**
+ * Logs each ProcessStat in ProcessStats.
+ * Keep in sync between:
+ * packages/services/Car/watchdog/server/src/proto/statsd.proto
+ * frameworks/base/cmds/statsd/src/atoms.proto
+ * Logged from:
+ * packages/services/Car/watchdog/server/src/ApplicationTerminator.cpp
+ */
+message ProcessStats {
+ // Records the stats of the processes owned by an application.
+ repeated ProcessStat process_stat = 1;
+}
+
+/**
+ * Logs a process's stats.
+ * Keep in sync between:
+ * packages/services/Car/watchdog/server/src/proto/statsd.proto
+ * frameworks/base/cmds/statsd/src/atoms.proto
+ * Logged from:
+ * packages/services/Car/watchdog/server/src/ApplicationTerminator.cpp
+ */
+message ProcessStat {
+ // Command name of the process.
+ optional string process_name = 1;
+
+ // Process uptime.
+ optional uint64 uptime_milliseconds = 2;
+
+ // Number of major page faults caused by the process and its children.
+ optional uint64 major_page_faults = 3;
+
+ // Peak virtual memory size in kb.
+ optional uint64 vm_peak_kb = 4;
+
+ // Virtual memory size in kb.
+ optional uint64 vm_size_kb = 5;
+
+ // Peak resident set size (high water mark) in kb.
+ optional uint64 vm_hwm_kb = 6;
+
+ // Resident set size in kb.
+ optional uint64 vm_rss_kb = 7;
+}
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index d80f9db..acc12aa 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -90,61 +90,7 @@
mVersionStringsInReport = config.version_strings_in_metric_report();
mInstallerInReport = config.installer_in_metric_report();
- // Init allowed pushed atom uids.
- if (config.allowed_log_source_size() == 0) {
- mConfigValid = false;
- ALOGE("Log source allowlist is empty! This config won't get any data. Suggest adding at "
- "least AID_SYSTEM and AID_STATSD to the allowed_log_source field.");
- } else {
- for (const auto& source : config.allowed_log_source()) {
- auto it = UidMap::sAidToUidMapping.find(source);
- if (it != UidMap::sAidToUidMapping.end()) {
- mAllowedUid.push_back(it->second);
- } else {
- mAllowedPkg.push_back(source);
- }
- }
-
- if (mAllowedUid.size() + mAllowedPkg.size() > StatsdStats::kMaxLogSourceCount) {
- ALOGE("Too many log sources. This is likely to be an error in the config.");
- mConfigValid = false;
- } else {
- initLogSourceWhiteList();
- }
- }
-
- // Init default allowed pull atom uids.
- int numPullPackages = 0;
- for (const string& pullSource : config.default_pull_packages()) {
- auto it = UidMap::sAidToUidMapping.find(pullSource);
- if (it != UidMap::sAidToUidMapping.end()) {
- numPullPackages++;
- mDefaultPullUids.insert(it->second);
- } else {
- ALOGE("Default pull atom packages must be in sAidToUidMapping");
- mConfigValid = false;
- }
- }
- // Init per-atom pull atom packages.
- for (const PullAtomPackages& pullAtomPackages : config.pull_atom_packages()) {
- int32_t atomId = pullAtomPackages.atom_id();
- for (const string& pullPackage : pullAtomPackages.packages()) {
- numPullPackages++;
- auto it = UidMap::sAidToUidMapping.find(pullPackage);
- if (it != UidMap::sAidToUidMapping.end()) {
- mPullAtomUids[atomId].insert(it->second);
- } else {
- mPullAtomPackages[atomId].insert(pullPackage);
- }
- }
- }
- if (numPullPackages > StatsdStats::kMaxPullAtomPackages) {
- ALOGE("Too many sources in default_pull_packages and pull_atom_packages. This is likely to "
- "be an error in the config");
- mConfigValid = false;
- } else {
- initPullAtomSources();
- }
+ createAllLogSourcesFromConfig(config);
mPullerManager->RegisterPullUidProvider(mConfigKey, this);
// Store the sub-configs used.
@@ -241,10 +187,75 @@
mAllAnomalyTrackers = newAnomalyTrackers;
mAlertTrackerMap = newAlertTrackerMap;
mAllPeriodicAlarmTrackers = newPeriodicAlarmTrackers;
+
+ mAllowedUid.clear();
+ mAllowedPkg.clear();
+ mDefaultPullUids.clear();
+ mPullAtomUids.clear();
+ mPullAtomPackages.clear();
+ createAllLogSourcesFromConfig(config);
return mConfigValid;
}
-void MetricsManager::initLogSourceWhiteList() {
+void MetricsManager::createAllLogSourcesFromConfig(const StatsdConfig& config) {
+ // Init allowed pushed atom uids.
+ if (config.allowed_log_source_size() == 0) {
+ mConfigValid = false;
+ ALOGE("Log source allowlist is empty! This config won't get any data. Suggest adding at "
+ "least AID_SYSTEM and AID_STATSD to the allowed_log_source field.");
+ } else {
+ for (const auto& source : config.allowed_log_source()) {
+ auto it = UidMap::sAidToUidMapping.find(source);
+ if (it != UidMap::sAidToUidMapping.end()) {
+ mAllowedUid.push_back(it->second);
+ } else {
+ mAllowedPkg.push_back(source);
+ }
+ }
+
+ if (mAllowedUid.size() + mAllowedPkg.size() > StatsdStats::kMaxLogSourceCount) {
+ ALOGE("Too many log sources. This is likely to be an error in the config.");
+ mConfigValid = false;
+ } else {
+ initAllowedLogSources();
+ }
+ }
+
+ // Init default allowed pull atom uids.
+ int numPullPackages = 0;
+ for (const string& pullSource : config.default_pull_packages()) {
+ auto it = UidMap::sAidToUidMapping.find(pullSource);
+ if (it != UidMap::sAidToUidMapping.end()) {
+ numPullPackages++;
+ mDefaultPullUids.insert(it->second);
+ } else {
+ ALOGE("Default pull atom packages must be in sAidToUidMapping");
+ mConfigValid = false;
+ }
+ }
+ // Init per-atom pull atom packages.
+ for (const PullAtomPackages& pullAtomPackages : config.pull_atom_packages()) {
+ int32_t atomId = pullAtomPackages.atom_id();
+ for (const string& pullPackage : pullAtomPackages.packages()) {
+ numPullPackages++;
+ auto it = UidMap::sAidToUidMapping.find(pullPackage);
+ if (it != UidMap::sAidToUidMapping.end()) {
+ mPullAtomUids[atomId].insert(it->second);
+ } else {
+ mPullAtomPackages[atomId].insert(pullPackage);
+ }
+ }
+ }
+ if (numPullPackages > StatsdStats::kMaxPullAtomPackages) {
+ ALOGE("Too many sources in default_pull_packages and pull_atom_packages. This is likely to "
+ "be an error in the config");
+ mConfigValid = false;
+ } else {
+ initPullAtomSources();
+ }
+}
+
+void MetricsManager::initAllowedLogSources() {
std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
mAllowedLogSources.clear();
mAllowedLogSources.insert(mAllowedUid.begin(), mAllowedUid.end());
@@ -288,7 +299,7 @@
if (std::find(mAllowedPkg.begin(), mAllowedPkg.end(), apk) != mAllowedPkg.end()) {
// We will re-initialize the whole list because we don't want to keep the multi mapping of
// UID<->pkg inside MetricsManager to reduce the memory usage.
- initLogSourceWhiteList();
+ initAllowedLogSources();
}
for (const auto& it : mPullAtomPackages) {
@@ -309,7 +320,7 @@
if (std::find(mAllowedPkg.begin(), mAllowedPkg.end(), apk) != mAllowedPkg.end()) {
// We will re-initialize the whole list because we don't want to keep the multi mapping of
// UID<->pkg inside MetricsManager to reduce the memory usage.
- initLogSourceWhiteList();
+ initAllowedLogSources();
}
for (const auto& it : mPullAtomPackages) {
@@ -329,7 +340,7 @@
if (mAllowedPkg.size() == 0) {
return;
}
- initLogSourceWhiteList();
+ initAllowedLogSources();
}
void MetricsManager::onStatsdInitCompleted(const int64_t& eventTimeNs) {
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 27f3d51..23048ae 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -285,10 +285,14 @@
std::vector<int> mMetricIndexesWithActivation;
- void initLogSourceWhiteList();
+ void initAllowedLogSources();
void initPullAtomSources();
+ // Only called on config creation/update to initialize log sources from the config.
+ // Calls initAllowedLogSources and initPullAtomSources. Sets mConfigValid to false on error.
+ void createAllLogSourcesFromConfig(const StatsdConfig& config);
+
// The metrics that don't need to be uploaded or even reported.
std::set<int64_t> mNoReportMetricIds;
@@ -330,6 +334,7 @@
FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations);
FRIEND_TEST(MetricsManagerTest, TestLogSources);
+ FRIEND_TEST(MetricsManagerTest, TestLogSourcesOnConfigUpdate);
FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index 2dd774e..f05ec49 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <private/android_filesystem_config.h>
#include <stdio.h>
@@ -92,8 +93,12 @@
return config;
}
-bool isSubset(const set<int32_t>& set1, const set<int32_t>& set2) {
- return std::includes(set2.begin(), set2.end(), set1.begin(), set1.end());
+set<int32_t> unionSet(const vector<set<int32_t>> sets) {
+ set<int32_t> toRet;
+ for (const set<int32_t>& s : sets) {
+ toRet.insert(s.begin(), s.end());
+ }
+ return toRet;
}
} // anonymous namespace
@@ -110,9 +115,7 @@
pkgToUids[app2] = app2Uids;
pkgToUids[app3] = app3Uids;
- int32_t atom1 = 10;
- int32_t atom2 = 20;
- int32_t atom3 = 30;
+ int32_t atom1 = 10, atom2 = 20, atom3 = 30;
sp<MockUidMap> uidMap = new StrictMock<MockUidMap>();
EXPECT_CALL(*uidMap, getAppUid(_))
.Times(4)
@@ -150,42 +153,115 @@
MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap,
pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor);
-
EXPECT_TRUE(metricsManager.isConfigValid());
- ASSERT_EQ(metricsManager.mAllowedUid.size(), 1);
- EXPECT_EQ(metricsManager.mAllowedUid[0], AID_SYSTEM);
-
- ASSERT_EQ(metricsManager.mAllowedPkg.size(), 1);
- EXPECT_EQ(metricsManager.mAllowedPkg[0], app1);
-
- ASSERT_EQ(metricsManager.mAllowedLogSources.size(), 3);
- EXPECT_TRUE(isSubset({AID_SYSTEM}, metricsManager.mAllowedLogSources));
- EXPECT_TRUE(isSubset(app1Uids, metricsManager.mAllowedLogSources));
-
- ASSERT_EQ(metricsManager.mDefaultPullUids.size(), 2);
- EXPECT_TRUE(isSubset(defaultPullUids, metricsManager.mDefaultPullUids));
- ;
+ EXPECT_THAT(metricsManager.mAllowedUid, ElementsAre(AID_SYSTEM));
+ EXPECT_THAT(metricsManager.mAllowedPkg, ElementsAre(app1));
+ EXPECT_THAT(metricsManager.mAllowedLogSources,
+ ContainerEq(unionSet(vector<set<int32_t>>({app1Uids, {AID_SYSTEM}}))));
+ EXPECT_THAT(metricsManager.mDefaultPullUids, ContainerEq(defaultPullUids));
vector<int32_t> atom1Uids = metricsManager.getPullAtomUids(atom1);
- ASSERT_EQ(atom1Uids.size(), 5);
- set<int32_t> expectedAtom1Uids;
- expectedAtom1Uids.insert(defaultPullUids.begin(), defaultPullUids.end());
- expectedAtom1Uids.insert(app1Uids.begin(), app1Uids.end());
- expectedAtom1Uids.insert(app3Uids.begin(), app3Uids.end());
- EXPECT_TRUE(isSubset(expectedAtom1Uids, set<int32_t>(atom1Uids.begin(), atom1Uids.end())));
+ EXPECT_THAT(atom1Uids,
+ UnorderedElementsAreArray(unionSet({defaultPullUids, app1Uids, app3Uids})));
vector<int32_t> atom2Uids = metricsManager.getPullAtomUids(atom2);
- ASSERT_EQ(atom2Uids.size(), 4);
- set<int32_t> expectedAtom2Uids;
- expectedAtom1Uids.insert(defaultPullUids.begin(), defaultPullUids.end());
- expectedAtom1Uids.insert(app2Uids.begin(), app2Uids.end());
- expectedAtom1Uids.insert(AID_STATSD);
- EXPECT_TRUE(isSubset(expectedAtom2Uids, set<int32_t>(atom2Uids.begin(), atom2Uids.end())));
+ EXPECT_THAT(atom2Uids,
+ UnorderedElementsAreArray(unionSet({defaultPullUids, app2Uids, {AID_STATSD}})));
vector<int32_t> atom3Uids = metricsManager.getPullAtomUids(atom3);
- ASSERT_EQ(atom3Uids.size(), 2);
- EXPECT_TRUE(isSubset(defaultPullUids, set<int32_t>(atom3Uids.begin(), atom3Uids.end())));
+ EXPECT_THAT(atom3Uids, UnorderedElementsAreArray(defaultPullUids));
+}
+
+TEST(MetricsManagerTest, TestLogSourcesOnConfigUpdate) {
+ string app1 = "app1";
+ set<int32_t> app1Uids = {1111, 11111};
+ string app2 = "app2";
+ set<int32_t> app2Uids = {2222};
+ string app3 = "app3";
+ set<int32_t> app3Uids = {3333, 1111};
+
+ map<string, set<int32_t>> pkgToUids;
+ pkgToUids[app1] = app1Uids;
+ pkgToUids[app2] = app2Uids;
+ pkgToUids[app3] = app3Uids;
+
+ int32_t atom1 = 10, atom2 = 20, atom3 = 30;
+ sp<MockUidMap> uidMap = new StrictMock<MockUidMap>();
+ EXPECT_CALL(*uidMap, getAppUid(_))
+ .Times(8)
+ .WillRepeatedly(Invoke([&pkgToUids](const string& pkg) {
+ const auto& it = pkgToUids.find(pkg);
+ if (it != pkgToUids.end()) {
+ return it->second;
+ }
+ return set<int32_t>();
+ }));
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, RegisterPullUidProvider(kConfigKey, _)).Times(1);
+ EXPECT_CALL(*pullerManager, UnregisterPullUidProvider(kConfigKey, _)).Times(1);
+
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
+
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_SYSTEM");
+ config.add_allowed_log_source(app1);
+ config.add_default_pull_packages("AID_SYSTEM");
+ config.add_default_pull_packages("AID_ROOT");
+
+ PullAtomPackages* pullAtomPackages = config.add_pull_atom_packages();
+ pullAtomPackages->set_atom_id(atom1);
+ pullAtomPackages->add_packages(app1);
+ pullAtomPackages->add_packages(app3);
+
+ pullAtomPackages = config.add_pull_atom_packages();
+ pullAtomPackages->set_atom_id(atom2);
+ pullAtomPackages->add_packages(app2);
+ pullAtomPackages->add_packages("AID_STATSD");
+
+ MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap,
+ pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor);
+ EXPECT_TRUE(metricsManager.isConfigValid());
+
+ // Update with new allowed log sources.
+ StatsdConfig newConfig;
+ newConfig.add_allowed_log_source("AID_ROOT");
+ newConfig.add_allowed_log_source(app2);
+ newConfig.add_default_pull_packages("AID_SYSTEM");
+ newConfig.add_default_pull_packages("AID_STATSD");
+
+ pullAtomPackages = newConfig.add_pull_atom_packages();
+ pullAtomPackages->set_atom_id(atom2);
+ pullAtomPackages->add_packages(app1);
+ pullAtomPackages->add_packages(app3);
+
+ pullAtomPackages = newConfig.add_pull_atom_packages();
+ pullAtomPackages->set_atom_id(atom3);
+ pullAtomPackages->add_packages(app2);
+ pullAtomPackages->add_packages("AID_ADB");
+
+ metricsManager.updateConfig(newConfig, timeBaseSec, timeBaseSec, anomalyAlarmMonitor,
+ periodicAlarmMonitor);
+ EXPECT_TRUE(metricsManager.isConfigValid());
+
+ EXPECT_THAT(metricsManager.mAllowedUid, ElementsAre(AID_ROOT));
+ EXPECT_THAT(metricsManager.mAllowedPkg, ElementsAre(app2));
+ EXPECT_THAT(metricsManager.mAllowedLogSources,
+ ContainerEq(unionSet(vector<set<int32_t>>({app2Uids, {AID_ROOT}}))));
+ const set<int32_t> defaultPullUids = {AID_SYSTEM, AID_STATSD};
+ EXPECT_THAT(metricsManager.mDefaultPullUids, ContainerEq(defaultPullUids));
+
+ vector<int32_t> atom1Uids = metricsManager.getPullAtomUids(atom1);
+ EXPECT_THAT(atom1Uids, UnorderedElementsAreArray(defaultPullUids));
+
+ vector<int32_t> atom2Uids = metricsManager.getPullAtomUids(atom2);
+ EXPECT_THAT(atom2Uids,
+ UnorderedElementsAreArray(unionSet({defaultPullUids, app1Uids, app3Uids})));
+
+ vector<int32_t> atom3Uids = metricsManager.getPullAtomUids(atom3);
+ EXPECT_THAT(atom3Uids,
+ UnorderedElementsAreArray(unionSet({defaultPullUids, app2Uids, {AID_ADB}})));
}
TEST(MetricsManagerTest, TestCheckLogCredentialsWhitelistedAtom) {
diff --git a/core/api/current.txt b/core/api/current.txt
index 05b57af..9329e2a 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -5528,6 +5528,7 @@
field @Deprecated public static final String EXTRA_PEOPLE = "android.people";
field public static final String EXTRA_PEOPLE_LIST = "android.people.list";
field public static final String EXTRA_PICTURE = "android.picture";
+ field public static final String EXTRA_PICTURE_CONTENT_DESCRIPTION = "android.pictureContentDescription";
field public static final String EXTRA_PROGRESS = "android.progress";
field public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
field public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
@@ -5673,6 +5674,7 @@
method public android.app.Notification.BigPictureStyle bigLargeIcon(android.graphics.Bitmap);
method public android.app.Notification.BigPictureStyle bigLargeIcon(android.graphics.drawable.Icon);
method public android.app.Notification.BigPictureStyle bigPicture(android.graphics.Bitmap);
+ method @NonNull public android.app.Notification.BigPictureStyle bigPictureContentDescription(@Nullable CharSequence);
method public android.app.Notification.BigPictureStyle setBigContentTitle(CharSequence);
method public android.app.Notification.BigPictureStyle setSummaryText(CharSequence);
}
@@ -5972,6 +5974,7 @@
method public long[] getVibrationPattern();
method public boolean hasUserSetImportance();
method public boolean hasUserSetSound();
+ method public boolean isConversation();
method public boolean isDemoted();
method public boolean isImportantConversation();
method public void setAllowBubbles(boolean);
@@ -6138,6 +6141,7 @@
method public android.content.IntentSender getIntentSender();
method public static android.app.PendingIntent getService(android.content.Context, int, @NonNull android.content.Intent, int);
method @Deprecated public String getTargetPackage();
+ method public boolean isImmutable();
method @Nullable public static android.app.PendingIntent readPendingIntentOrNullFromParcel(@NonNull android.os.Parcel);
method public void send() throws android.app.PendingIntent.CanceledException;
method public void send(int) throws android.app.PendingIntent.CanceledException;
@@ -10679,8 +10683,6 @@
field public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED";
field public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED";
field public static final String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED";
- field public static final String ACTION_PACKAGE_STARTABLE = "android.intent.action.PACKAGE_STARTABLE";
- field public static final String ACTION_PACKAGE_UNSTARTABLE = "android.intent.action.PACKAGE_UNSTARTABLE";
field public static final String ACTION_PACKAGE_VERIFIED = "android.intent.action.PACKAGE_VERIFIED";
field public static final String ACTION_PASTE = "android.intent.action.PASTE";
field public static final String ACTION_PICK = "android.intent.action.PICK";
@@ -12308,9 +12310,6 @@
field public static final int SYNCHRONOUS = 2; // 0x2
field @Nullable public static final java.util.List<java.security.cert.Certificate> TRUST_ALL;
field @NonNull public static final java.util.List<java.security.cert.Certificate> TRUST_NONE;
- field public static final int UNSTARTABLE_REASON_CONNECTION_ERROR = 1; // 0x1
- field public static final int UNSTARTABLE_REASON_INSUFFICIENT_STORAGE = 2; // 0x2
- field public static final int UNSTARTABLE_REASON_UNKNOWN = 0; // 0x0
field public static final int VERIFICATION_ALLOW = 1; // 0x1
field public static final int VERIFICATION_REJECT = -1; // 0xffffffff
field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff
@@ -16409,6 +16408,7 @@
method public void getMetrics(@NonNull android.graphics.Paint, @Nullable android.graphics.Paint.FontMetrics);
method @NonNull public android.graphics.fonts.FontStyle getStyle();
method @IntRange(from=0) public int getTtcIndex();
+ method public boolean isSameSource(@NonNull android.graphics.fonts.Font);
}
public static final class Font.Builder {
@@ -25256,6 +25256,7 @@
public final class MediaCas implements java.lang.AutoCloseable {
ctor public MediaCas(int) throws android.media.MediaCasException.UnsupportedCasException;
ctor public MediaCas(@NonNull android.content.Context, int, @Nullable String, int) throws android.media.MediaCasException.UnsupportedCasException;
+ ctor public MediaCas(@NonNull android.content.Context, int, @Nullable String, int, @Nullable android.os.Handler, @Nullable android.media.MediaCas.EventListener) throws android.media.MediaCasException.UnsupportedCasException;
method public void close();
method public static android.media.MediaCas.PluginDescriptor[] enumeratePlugins();
method protected void finalize();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 96bbe15..1e3a2c0 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -5030,6 +5030,7 @@
field public static final int INVALID_AV_SYNC_ID = -1; // 0xffffffff
field public static final int INVALID_FILTER_ID = -1; // 0xffffffff
field public static final long INVALID_FILTER_ID_64BIT = -1L; // 0xffffffffffffffffL
+ field public static final int INVALID_FIRST_MACROBLOCK_IN_SLICE = -1; // 0xffffffff
field public static final int INVALID_FRONTEND_SETTING_FREQUENCY = -1; // 0xffffffff
field public static final int INVALID_LTS_ID = -1; // 0xffffffff
field public static final int INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM = -1; // 0xffffffff
@@ -5330,6 +5331,7 @@
public class MmtpRecordEvent extends android.media.tv.tuner.filter.FilterEvent {
method public long getDataLength();
+ method public int getFirstMbInSlice();
method public int getMpuSequenceNumber();
method public long getPts();
method public int getScHevcIndexMask();
@@ -5370,9 +5372,14 @@
field public static final int SC_HEVC_INDEX_SLICE_TRAIL_CRA = 128; // 0x80
field public static final int SC_HEVC_INDEX_SPS = 1; // 0x1
field public static final int SC_INDEX_B_FRAME = 4; // 0x4
+ field public static final int SC_INDEX_B_SLICE = 64; // 0x40
field public static final int SC_INDEX_I_FRAME = 1; // 0x1
+ field public static final int SC_INDEX_I_SLICE = 16; // 0x10
field public static final int SC_INDEX_P_FRAME = 2; // 0x2
+ field public static final int SC_INDEX_P_SLICE = 32; // 0x20
field public static final int SC_INDEX_SEQUENCE = 8; // 0x8
+ field public static final int SC_INDEX_SI_SLICE = 128; // 0x80
+ field public static final int SC_INDEX_SP_SLICE = 256; // 0x100
field public static final int TS_INDEX_ADAPTATION_EXTENSION_FLAG = 4096; // 0x1000
field public static final int TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED = 8; // 0x8
field public static final int TS_INDEX_CHANGE_TO_NOT_SCRAMBLED = 4; // 0x4
@@ -5493,6 +5500,7 @@
public class TsRecordEvent extends android.media.tv.tuner.filter.FilterEvent {
method public long getDataLength();
+ method public int getFirstMbInSlice();
method public int getPacketId();
method public long getPts();
method public int getScIndexMask();
@@ -5818,6 +5826,7 @@
public class DvbsFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
method @NonNull public static android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder builder();
method @Nullable public android.media.tv.tuner.frontend.DvbsCodeRate getCodeRate();
+ method public boolean getCouldHandleDiseqcRxMessage();
method public int getInputStreamId();
method public int getModulation();
method public int getPilot();
@@ -5827,7 +5836,6 @@
method public int getSymbolRate();
method public int getType();
method public int getVcmMode();
- method public boolean isDiseqcRxMessage();
field public static final int MODULATION_AUTO = 1; // 0x1
field public static final int MODULATION_MOD_128APSK = 2048; // 0x800
field public static final int MODULATION_MOD_16APSK = 256; // 0x100
@@ -5871,7 +5879,7 @@
public static class DvbsFrontendSettings.Builder {
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings build();
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setCodeRate(@Nullable android.media.tv.tuner.frontend.DvbsCodeRate);
- method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setDiseqcRxMessage(boolean);
+ method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setCouldHandleDiseqcRxMessage(boolean);
method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setFrequency(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setInputStreamId(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setModulation(int);
@@ -6011,7 +6019,7 @@
}
public abstract class FrontendSettings {
- method public int getEndFrequency();
+ method @IntRange(from=1) public int getEndFrequency();
method public int getFrequency();
method public int getFrontendSpectralInversion();
method public abstract int getType();
@@ -6293,6 +6301,7 @@
public interface ScanCallback {
method public void onAnalogSifStandardReported(int);
method public void onAtsc3PlpInfosReported(@NonNull android.media.tv.tuner.frontend.Atsc3PlpInfo[]);
+ method public default void onDvbcAnnexReported(int);
method public void onDvbsStandardReported(int);
method public void onDvbtStandardReported(int);
method public void onFrequenciesReported(@NonNull int[]);
@@ -8336,6 +8345,7 @@
field public static final String NAMESPACE_PACKAGE_MANAGER_SERVICE = "package_manager_service";
field public static final String NAMESPACE_PERMISSIONS = "permissions";
field public static final String NAMESPACE_PRIVACY = "privacy";
+ field public static final String NAMESPACE_PROFCOLLECT_NATIVE_BOOT = "profcollect_native_boot";
field public static final String NAMESPACE_ROLLBACK = "rollback";
field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
field public static final String NAMESPACE_RUNTIME = "runtime";
@@ -11178,6 +11188,17 @@
package android.telephony.ims {
+ public final class AudioCodecAttributes implements android.os.Parcelable {
+ ctor public AudioCodecAttributes(float, @NonNull android.util.Range<java.lang.Float>, float, @NonNull android.util.Range<java.lang.Float>);
+ method public int describeContents();
+ method public float getBandwidthKhz();
+ method @NonNull public android.util.Range<java.lang.Float> getBandwidthRangeKhz();
+ method public float getBitrateKbps();
+ method @NonNull public android.util.Range<java.lang.Float> getBitrateRangeKbps();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.AudioCodecAttributes> CREATOR;
+ }
+
public final class ImsCallForwardInfo implements android.os.Parcelable {
ctor public ImsCallForwardInfo(int, int, int, int, @NonNull String, int);
method public int describeContents();
@@ -11546,6 +11567,7 @@
ctor public ImsStreamMediaProfile(int, int, int, int, int);
method public void copyFrom(android.telephony.ims.ImsStreamMediaProfile);
method public int describeContents();
+ method @Nullable public android.telephony.ims.AudioCodecAttributes getAudioCodecAttributes();
method public int getAudioDirection();
method public int getAudioQuality();
method public int getRttMode();
@@ -11553,6 +11575,7 @@
method public int getVideoQuality();
method public boolean isReceivingRttAudio();
method public boolean isRttCall();
+ method public void setAudioCodecAttributes(@NonNull android.telephony.ims.AudioCodecAttributes);
method public void setReceivingRttAudio(boolean);
method public void setRttMode(int);
method public void writeToParcel(android.os.Parcel, int);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 2ac345d..29e407b 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -77,6 +77,7 @@
import android.os.Looper;
import android.os.Parcelable;
import android.os.PersistableBundle;
+import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager.ServiceNotFoundException;
@@ -8722,13 +8723,16 @@
* the activity is visible after the screen is turned on when the lockscreen is up. In addition,
* if this flag is set and the activity calls {@link
* KeyguardManager#requestDismissKeyguard(Activity, KeyguardManager.KeyguardDismissCallback)}
- * the screen will turn on.
+ * the screen will turn on. If the screen is off and device is not secured, this flag can turn
+ * screen on and dismiss keyguard to make this activity visible and resume, which can be used to
+ * replace {@link PowerManager#ACQUIRE_CAUSES_WAKEUP}
*
* @param turnScreenOn {@code true} to turn on the screen; {@code false} otherwise.
*
* @see #setShowWhenLocked(boolean)
* @see android.R.attr#turnScreenOn
* @see android.R.attr#showWhenLocked
+ * @see KeyguardManager#isDeviceSecure()
*/
public void setTurnScreenOn(boolean turnScreenOn) {
try {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index ec287fe..ba57370 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -16,6 +16,8 @@
package android.app;
+import static android.app.WindowConfiguration.activityTypeToString;
+import static android.app.WindowConfiguration.windowingModeToString;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
@@ -1693,6 +1695,13 @@
@Deprecated
public int affiliatedTaskId;
+ /**
+ * Information of organized child tasks.
+ *
+ * @hide
+ */
+ public ArrayList<RecentTaskInfo> childrenTaskInfos = new ArrayList<>();
+
public RecentTaskInfo() {
}
@@ -1708,6 +1717,7 @@
public void readFromParcel(Parcel source) {
id = source.readInt();
persistentId = source.readInt();
+ childrenTaskInfos = source.readArrayList(RecentTaskInfo.class.getClassLoader());
super.readFromParcel(source);
}
@@ -1715,6 +1725,7 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeInt(persistentId);
+ dest.writeList(childrenTaskInfos);
super.writeToParcel(dest, flags);
}
@@ -1732,11 +1743,6 @@
* @hide
*/
public void dump(PrintWriter pw, String indent) {
- final String activityType = WindowConfiguration.activityTypeToString(
- configuration.windowConfiguration.getActivityType());
- final String windowingMode = WindowConfiguration.activityTypeToString(
- configuration.windowConfiguration.getActivityType());
-
pw.println(); pw.print(" ");
pw.print(" id="); pw.print(persistentId);
pw.print(" stackId="); pw.print(stackId);
@@ -1762,8 +1768,8 @@
pw.print(" ");
pw.print(" isExcluded=");
pw.print(((baseIntent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0));
- pw.print(" activityType="); pw.print(activityType);
- pw.print(" windowingMode="); pw.print(windowingMode);
+ pw.print(" activityType="); pw.print(activityTypeToString(getActivityType()));
+ pw.print(" windowingMode="); pw.print(windowingModeToString(getWindowingMode()));
pw.print(" supportsSplitScreenMultiWindow=");
pw.println(supportsSplitScreenMultiWindow);
if (taskDescription != null) {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index e20ef7f..c89f16e 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -31,6 +31,7 @@
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -52,6 +53,7 @@
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserManager;
+import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LongSparseArray;
@@ -7590,8 +7592,9 @@
collectNotedOpForSelf(op, proxiedAttributionTag);
} else if (collectionMode == COLLECT_SYNC
// Only collect app-ops when the proxy is trusted
- && mContext.checkPermission(Manifest.permission.UPDATE_APP_OPS_STATS, -1,
- myUid) == PackageManager.PERMISSION_GRANTED) {
+ && (mContext.checkPermission(Manifest.permission.UPDATE_APP_OPS_STATS, -1,
+ myUid) == PackageManager.PERMISSION_GRANTED
+ || isTrustedVoiceServiceProxy(mContext.getOpPackageName(), op))) {
collectNotedOpSync(op, proxiedAttributionTag);
}
}
@@ -7602,6 +7605,28 @@
}
}
+ private boolean isTrustedVoiceServiceProxy(String packageName, int code) {
+ // This is a workaround for R QPR, new API change is not allowed. We only allow the current
+ // voice recognizer is also the voice interactor to noteproxy op.
+ if (code != OP_RECORD_AUDIO) {
+ return false;
+ }
+ final String voiceRecognitionComponent = Settings.Secure.getString(
+ mContext.getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE);
+ final String voiceInteractionComponent = Settings.Secure.getString(
+ mContext.getContentResolver(), Settings.Secure.VOICE_INTERACTION_SERVICE);
+
+ final String voiceRecognitionServicePackageName =
+ voiceRecognitionComponent != null ? ComponentName.unflattenFromString(
+ voiceRecognitionComponent).getPackageName() : "";
+ final String voiceInteractionServicePackageName =
+ voiceInteractionComponent != null ? ComponentName.unflattenFromString(
+ voiceInteractionComponent).getPackageName() : "";
+
+ return Objects.equals(packageName, voiceRecognitionServicePackageName) && Objects.equals(
+ voiceRecognitionServicePackageName, voiceInteractionServicePackageName);
+ }
+
/**
* Do a quick check for whether an application might be able to perform an operation.
* This is <em>not</em> a security check; you must use {@link #noteOp(String, int, String,
diff --git a/core/java/android/app/AsyncNotedAppOp.java b/core/java/android/app/AsyncNotedAppOp.java
index b0c2762c..db58c21 100644
--- a/core/java/android/app/AsyncNotedAppOp.java
+++ b/core/java/android/app/AsyncNotedAppOp.java
@@ -72,7 +72,7 @@
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -261,10 +261,10 @@
};
@DataClass.Generated(
- time = 1583866239013L,
- codegenVersion = "1.0.15",
+ time = 1604456255752L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/core/java/android/app/AsyncNotedAppOp.java",
- inputSignatures = "private final @android.annotation.IntRange(from=0L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mAttributionTag\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.CurrentTimeMillisLong long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nprivate void onConstructed()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
+ inputSignatures = "private final @android.annotation.IntRange int mOpCode\nprivate final @android.annotation.IntRange int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mAttributionTag\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.CurrentTimeMillisLong long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nprivate void onConstructed()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 879d437..560b5be 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -342,6 +342,7 @@
@UnsupportedAppUsage
void unregisterProcessObserver(in IProcessObserver observer);
boolean isIntentSenderTargetedToPackage(in IIntentSender sender);
+ boolean isIntentSenderImmutable(in IIntentSender sender);
@UnsupportedAppUsage
void updatePersistentConfiguration(in Configuration values);
void updatePersistentConfigurationWithAttribution(in Configuration values,
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index d798f22..a8ce73d 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -96,6 +96,8 @@
NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(String pkg, int uid, String groupId, boolean includeDeleted);
void updateNotificationChannelGroupForPackage(String pkg, int uid, in NotificationChannelGroup group);
void updateNotificationChannelForPackage(String pkg, int uid, in NotificationChannel channel);
+ void unlockNotificationChannel(String pkg, int uid, String channelId);
+ void unlockAllNotificationChannels();
NotificationChannel getNotificationChannel(String callingPkg, int userId, String pkg, String channelId);
NotificationChannel getConversationNotificationChannel(String callingPkg, int userId, String pkg, String channelId, boolean returnParentIfNoConversationChannel, String conversationId);
void createConversationNotificationChannelForPackage(String pkg, int uid, in NotificationChannel parentChannel, String conversationId);
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index b609462..4eef616 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -286,7 +286,7 @@
return mSecurityViolation;
}
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @UnsupportedAppUsage(trackingBug = 172409979)
public CompatibilityInfo getCompatibilityInfo() {
return mDisplayAdjustments.getCompatibilityInfo();
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index a1abe3d..8cafaa8 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1147,6 +1147,14 @@
public static final String EXTRA_PICTURE = "android.picture";
/**
+ * {@link #extras} key: this is a content description of the big picture supplied from
+ * {@link BigPictureStyle#bigPicture(Bitmap)}, supplied to
+ * {@link BigPictureStyle#bigPictureContentDescription(CharSequence)}.
+ */
+ public static final String EXTRA_PICTURE_CONTENT_DESCRIPTION =
+ "android.pictureContentDescription";
+
+ /**
* {@link #extras} key: An array of CharSequences to show in {@link InboxStyle} expanded
* notifications, each of which was supplied to {@link InboxStyle#addLine(CharSequence)}.
*/
@@ -6728,6 +6736,7 @@
private Bitmap mPicture;
private Icon mBigLargeIcon;
private boolean mBigLargeIconSet = false;
+ private CharSequence mPictureContentDescription;
public BigPictureStyle() {
}
@@ -6758,6 +6767,16 @@
}
/**
+ * Set the content description of the big picture.
+ */
+ @NonNull
+ public BigPictureStyle bigPictureContentDescription(
+ @Nullable CharSequence contentDescription) {
+ mPictureContentDescription = contentDescription;
+ return this;
+ }
+
+ /**
* @hide
*/
public Bitmap getBigPicture() {
@@ -6870,6 +6889,11 @@
}
contentView.setImageViewBitmap(R.id.big_picture, mPicture);
+
+ if (mPictureContentDescription != null) {
+ contentView.setContentDescription(R.id.big_picture, mPictureContentDescription);
+ }
+
return contentView;
}
@@ -6882,6 +6906,10 @@
if (mBigLargeIconSet) {
extras.putParcelable(EXTRA_LARGE_ICON_BIG, mBigLargeIcon);
}
+ if (mPictureContentDescription != null) {
+ extras.putCharSequence(EXTRA_PICTURE_CONTENT_DESCRIPTION,
+ mPictureContentDescription);
+ }
extras.putParcelable(EXTRA_PICTURE, mPicture);
}
@@ -6896,6 +6924,12 @@
mBigLargeIconSet = true;
mBigLargeIcon = extras.getParcelable(EXTRA_LARGE_ICON_BIG);
}
+
+ if (extras.containsKey(EXTRA_PICTURE_CONTENT_DESCRIPTION)) {
+ mPictureContentDescription =
+ extras.getCharSequence(EXTRA_PICTURE_CONTENT_DESCRIPTION);
+ }
+
mPicture = extras.getParcelable(EXTRA_PICTURE);
}
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index a06ffbd..080aac9 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -629,12 +629,20 @@
}
/**
+ * Whether or not this channel represents a conversation.
+ */
+ public boolean isConversation() {
+ return !TextUtils.isEmpty(getConversationId());
+ }
+
+
+ /**
* Whether or not notifications in this conversation are considered important.
*
* <p>Important conversations may get special visual treatment, and might be able to bypass DND.
*
- * <p>This is only valid for channels that represent conversations, that is, those with a valid
- * {@link #getConversationId() conversation id}.
+ * <p>This is only valid for channels that represent conversations, that is,
+ * where {@link #isConversation()} is true.
*/
public boolean isImportantConversation() {
return mImportantConvo;
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 21dfbbd..f76a757 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -1145,6 +1145,18 @@
}
/**
+ * Check if this PendingIntent is marked with {@link #FLAG_IMMUTABLE}.
+ */
+ public boolean isImmutable() {
+ try {
+ return ActivityManager.getService()
+ .isIntentSenderImmutable(mTarget);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* @hide
* Check whether this PendingIntent will launch an Activity.
*/
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 43b7722..5dfab6e 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -257,6 +257,18 @@
}
/** @hide */
+ @WindowConfiguration.WindowingMode
+ public int getWindowingMode() {
+ return configuration.windowConfiguration.getWindowingMode();
+ }
+
+ /** @hide */
+ @WindowConfiguration.ActivityType
+ public int getActivityType() {
+ return configuration.windowConfiguration.getActivityType();
+ }
+
+ /** @hide */
public void addLaunchCookie(IBinder cookie) {
if (cookie == null || launchCookies.contains(cookie)) return;
launchCookies.add(cookie);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 224e3a8..0ade5d2 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -525,7 +525,7 @@
* @hide
*/
public static final String ACTION_REMOTE_BUGREPORT_DISPATCH =
- "com.android.server.action.REMOTE_BUGREPORT_DISPATCH";
+ "android.intent.action.REMOTE_BUGREPORT_DISPATCH";
/**
* Extra for shared bugreport's SHA-256 hash.
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 0531359..44a4b78 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -21,10 +21,14 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -435,6 +439,17 @@
return false;
}
+
+ /**
+ * If this change is enabled, the {@code BACKUP} permission needed for
+ * {@code isBackupServiceActive()} will be enforced on the service end
+ * rather than client-side in {@link BackupManager}.
+ * @hide
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
+ public static final long IS_BACKUP_SERVICE_ACTIVE_ENFORCE_PERMISSION_IN_SERVICE = 158482162;
+
/**
* Report whether the backup mechanism is currently active.
* When it is inactive, the device will not perform any backup operations, nor will it
@@ -445,8 +460,11 @@
@SystemApi
@RequiresPermission(android.Manifest.permission.BACKUP)
public boolean isBackupServiceActive(UserHandle user) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "isBackupServiceActive");
+ if (!CompatChanges.isChangeEnabled(
+ IS_BACKUP_SERVICE_ACTIVE_ENFORCE_PERMISSION_IN_SERVICE)) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+ "isBackupServiceActive");
+ }
checkServiceBinder();
if (sService != null) {
try {
diff --git a/core/java/android/content/ClipDescription.java b/core/java/android/content/ClipDescription.java
index 73becb1..e3395e2 100644
--- a/core/java/android/content/ClipDescription.java
+++ b/core/java/android/content/ClipDescription.java
@@ -74,8 +74,8 @@
/**
* The MIME type for a shortcut. The ClipData must include intents with required extras
- * {@link #EXTRA_PENDING_INTENT} and {@link Intent#EXTRA_USER}, and an optional
- * {@link #EXTRA_ACTIVITY_OPTIONS}.
+ * {@link Intent#EXTRA_SHORTCUT_ID}, {@link Intent#EXTRA_PACKAGE_NAME} and
+ * {@link Intent#EXTRA_USER}, and an optional {@link #EXTRA_ACTIVITY_OPTIONS}.
* @hide
*/
public static final String MIMETYPE_APPLICATION_SHORTCUT = "application/vnd.android.shortcut";
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 782f0cd..a03bdf2 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2740,6 +2740,7 @@
* </ul>
*
* <p class="note">This is a protected intent that can only be sent by the system.
+ * @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGE_STARTABLE = "android.intent.action.PACKAGE_STARTABLE";
@@ -2757,6 +2758,7 @@
* </ul>
*
* <p class="note">This is a protected intent that can only be sent by the system.
+ * @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGE_UNSTARTABLE =
diff --git a/core/java/android/content/pm/OWNERS b/core/java/android/content/pm/OWNERS
new file mode 100644
index 0000000..a16bb4f
--- /dev/null
+++ b/core/java/android/content/pm/OWNERS
@@ -0,0 +1 @@
+per-file PackageParser.java = chiuwinson@google.com
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 596d39b..0fc9fad 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1356,7 +1356,9 @@
* Completely abandon this session, destroying all staged data and
* rendering it invalid. Abandoned sessions will be reported to
* {@link SessionCallback} listeners as failures. This is equivalent to
- * opening the session and calling {@link Session#abandon()}.
+ * {@link #abandonSession(int)}.
+ * <p>If the parent is abandoned, all children will also be abandoned. Any written data
+ * would be destroyed and the created {@link Session} information will be discarded.</p>
*/
public void abandon() {
try {
@@ -1419,7 +1421,8 @@
* when this session is committed.
*
* <p>If the parent is staged or has rollback enabled, all children must have
- * the same properties.
+ * the same properties.</p>
+ * <p>If the parent is abandoned, all children will also be abandoned.</p>
*
* @param sessionId the session ID to add to this multi-package session.
*/
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 946c634..a77d8b1 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3824,18 +3824,21 @@
* Unstartable state with no root cause specified. E.g., data loader seeing missing pages but
* unclear about the cause. This corresponds to a generic alert window shown to the user when
* the user attempts to launch the app.
+ * @hide
*/
public static final int UNSTARTABLE_REASON_UNKNOWN = 0;
/**
* Unstartable state due to connection issues that interrupt package loading.
* This corresponds to an alert window shown to the user indicating connection errors.
+ * @hide
*/
public static final int UNSTARTABLE_REASON_CONNECTION_ERROR = 1;
/**
* Unstartable state after encountering storage limitations.
* This corresponds to an alert window indicating limited storage.
+ * @hide
*/
public static final int UNSTARTABLE_REASON_INSUFFICIENT_STORAGE = 2;
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 118524d..1c90d23 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -141,8 +141,14 @@
* <li>All installations must contain a single base APK.
* </ul>
*
+ * @deprecated This class is mostly unused and no new changes should be added to it. Use
+ * {@link android.content.pm.parsing.ParsingPackageUtils} and related parsing v2 infrastructure in
+ * the core/services parsing subpackages. Or for a quick parse of a provided APK, use
+ * {@link PackageManager#getPackageArchiveInfo(String, int)}.
+ *
* @hide
*/
+@Deprecated
public class PackageParser {
public static final boolean DEBUG_JAR = false;
diff --git a/core/java/android/content/pm/parsing/OWNERS b/core/java/android/content/pm/parsing/OWNERS
new file mode 100644
index 0000000..8049d5c
--- /dev/null
+++ b/core/java/android/content/pm/parsing/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 36137
+
+chiuwinson@google.com
+patb@google.com
+toddke@google.com
diff --git a/core/java/android/content/pm/permission/SplitPermissionInfoParcelable.java b/core/java/android/content/pm/permission/SplitPermissionInfoParcelable.java
index e7a554a..aea69ad 100644
--- a/core/java/android/content/pm/permission/SplitPermissionInfoParcelable.java
+++ b/core/java/android/content/pm/permission/SplitPermissionInfoParcelable.java
@@ -59,14 +59,18 @@
- // Code below generated by codegen v1.0.0.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
//
// To regenerate run:
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/permission/SplitPermissionInfoParcelable.java
//
- // CHECKSTYLE:OFF Generated code
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
/**
* Creates a new SplitPermissionInfoParcelable.
@@ -154,7 +158,7 @@
@Override
@DataClass.Generated.Member
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
@@ -167,6 +171,32 @@
@DataClass.Generated.Member
public int describeContents() { return 0; }
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ protected SplitPermissionInfoParcelable(@NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ String splitPermission = in.readString();
+ List<String> newPermissions = new java.util.ArrayList<>();
+ in.readStringList(newPermissions);
+ int targetSdk = in.readInt();
+
+ this.mSplitPermission = splitPermission;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mSplitPermission);
+ this.mNewPermissions = newPermissions;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mNewPermissions);
+ this.mTargetSdk = targetSdk;
+ com.android.internal.util.AnnotationValidations.validate(
+ IntRange.class, null, mTargetSdk,
+ "from", 0);
+
+ onConstructed();
+ }
+
@DataClass.Generated.Member
public static final @NonNull Parcelable.Creator<SplitPermissionInfoParcelable> CREATOR
= new Parcelable.Creator<SplitPermissionInfoParcelable>() {
@@ -176,28 +206,21 @@
}
@Override
- @SuppressWarnings({"unchecked", "RedundantCast"})
- public SplitPermissionInfoParcelable createFromParcel(Parcel in) {
- // You can override field unparcelling by defining methods like:
- // static FieldType unparcelFieldName(Parcel in) { ... }
-
- String splitPermission = in.readString();
- List<String> newPermissions = new java.util.ArrayList<>();
- in.readStringList(newPermissions);
- int targetSdk = in.readInt();
- return new SplitPermissionInfoParcelable(
- splitPermission,
- newPermissions,
- targetSdk);
+ public SplitPermissionInfoParcelable createFromParcel(@NonNull Parcel in) {
+ return new SplitPermissionInfoParcelable(in);
}
};
@DataClass.Generated(
- time = 1567634390477L,
- codegenVersion = "1.0.0",
+ time = 1604456266666L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/core/java/android/content/pm/permission/SplitPermissionInfoParcelable.java",
- inputSignatures = "private final @android.annotation.NonNull java.lang.String mSplitPermission\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mNewPermissions\nprivate final @android.annotation.IntRange(from=0L) int mTargetSdk\nprivate void onConstructed()\nclass SplitPermissionInfoParcelable extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
+ inputSignatures = "private final @android.annotation.NonNull java.lang.String mSplitPermission\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mNewPermissions\nprivate final @android.annotation.IntRange int mTargetSdk\nprivate void onConstructed()\nclass SplitPermissionInfoParcelable extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
+
+ //@formatter:on
+ // End of generated code
+
}
diff --git a/core/java/android/content/rollback/IRollbackManager.aidl b/core/java/android/content/rollback/IRollbackManager.aidl
index cda0e98..c818e93 100644
--- a/core/java/android/content/rollback/IRollbackManager.aidl
+++ b/core/java/android/content/rollback/IRollbackManager.aidl
@@ -49,10 +49,6 @@
// NOTE: This call is synchronous.
int notifyStagedSession(int sessionId);
- // Used by the staging manager to notify the RollbackManager of the apk
- // session for a staged session.
- void notifyStagedApkSession(int originalSessionId, int apkSessionId);
-
// For test purposes only.
void blockRollbackManager(long millis);
}
diff --git a/core/java/android/hardware/display/VirtualDisplayConfig.java b/core/java/android/hardware/display/VirtualDisplayConfig.java
index 10e1c7c..71688c7c 100644
--- a/core/java/android/hardware/display/VirtualDisplayConfig.java
+++ b/core/java/android/hardware/display/VirtualDisplayConfig.java
@@ -93,7 +93,7 @@
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -477,10 +477,10 @@
}
@DataClass.Generated(
- time = 1585179350902L,
- codegenVersion = "1.0.15",
+ time = 1604456298440L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/core/java/android/hardware/display/VirtualDisplayConfig.java",
- inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange(from=1L) int mWidth\nprivate @android.annotation.IntRange(from=1L) int mHeight\nprivate @android.annotation.IntRange(from=1L) int mDensityDpi\nprivate int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate int mDisplayIdToMirror\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)")
+ inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate int mDisplayIdToMirror\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 9f322fb..75893d9 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -577,9 +577,17 @@
*/
@RequiresPermission(MANAGE_BIOMETRIC)
public List<Face> getEnrolledFaces(int userId) {
+ final List<FaceSensorPropertiesInternal> faceSensorProperties =
+ getSensorPropertiesInternal();
+ if (faceSensorProperties.isEmpty()) {
+ Slog.e(TAG, "No sensors");
+ return new ArrayList<>();
+ }
+
if (mService != null) {
try {
- return mService.getEnrolledFaces(userId, mContext.getOpPackageName());
+ return mService.getEnrolledFaces(faceSensorProperties.get(0).sensorId, userId,
+ mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -606,15 +614,7 @@
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
public boolean hasEnrolledTemplates() {
- if (mService != null) {
- try {
- return mService.hasEnrolledFaces(
- UserHandle.myUserId(), mContext.getOpPackageName());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- return false;
+ return hasEnrolledTemplates(UserHandle.myUserId());
}
/**
@@ -624,9 +624,17 @@
USE_BIOMETRIC_INTERNAL,
INTERACT_ACROSS_USERS})
public boolean hasEnrolledTemplates(int userId) {
+ final List<FaceSensorPropertiesInternal> faceSensorProperties =
+ getSensorPropertiesInternal();
+ if (faceSensorProperties.isEmpty()) {
+ Slog.e(TAG, "No sensors");
+ return false;
+ }
+
if (mService != null) {
try {
- return mService.hasEnrolledFaces(userId, mContext.getOpPackageName());
+ return mService.hasEnrolledFaces(faceSensorProperties.get(0).sensorId, userId,
+ mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -642,9 +650,17 @@
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
public boolean isHardwareDetected() {
+ final List<FaceSensorPropertiesInternal> faceSensorProperties =
+ getSensorPropertiesInternal();
+ if (faceSensorProperties.isEmpty()) {
+ Slog.e(TAG, "No sensors");
+ return false;
+ }
+
if (mService != null) {
try {
- return mService.isHardwareDetected(mContext.getOpPackageName());
+ return mService.isHardwareDetected(faceSensorProperties.get(0).sensorId,
+ mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -677,7 +693,7 @@
@NonNull
public List<FaceSensorPropertiesInternal> getSensorPropertiesInternal() {
try {
- if (mService == null || !mService.isHardwareDetected(mContext.getOpPackageName())) {
+ if (mService == null) {
return new ArrayList<>();
}
return mService.getSensorPropertiesInternal(mContext.getOpPackageName());
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 490c95b..27cdda7 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -44,12 +44,12 @@
// called from BiometricService. The additional uid, pid, userId arguments should be determined
// by BiometricService. To start authentication after the clients are ready, use
// startPreparedClient().
- void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId,
+ void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token, long operationId,
int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
int cookie, int callingUid, int callingPid, int callingUserId);
// Starts authentication with the previously prepared client.
- void startPreparedClient(int cookie);
+ void startPreparedClient(int sensorId, int cookie);
// Cancel authentication for the given sessionId
void cancelAuthentication(IBinder token, String opPackageName);
@@ -58,7 +58,7 @@
void cancelFaceDetect(IBinder token, String opPackageName);
// Same as above, with extra arguments.
- void cancelAuthenticationFromService(IBinder token, String opPackageName,
+ void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName,
int callingUid, int callingPid, int callingUserId);
// Start face enrollment
@@ -77,10 +77,10 @@
String opPackageName);
// Get the enrolled face for user.
- List<Face> getEnrolledFaces(int userId, String opPackageName);
+ List<Face> getEnrolledFaces(int sensorId, int userId, String opPackageName);
// Determine if HAL is loaded and ready
- boolean isHardwareDetected(String opPackageName);
+ boolean isHardwareDetected(int sensorId, String opPackageName);
// Get a pre-enrollment authentication token
void generateChallenge(IBinder token, int sensorId, int userId, IFaceServiceReceiver receiver, String opPackageName);
@@ -89,13 +89,13 @@
void revokeChallenge(IBinder token, int sensorId, int userId, String opPackageName, long challenge);
// Determine if a user has at least one enrolled face
- boolean hasEnrolledFaces(int userId, String opPackageName);
+ boolean hasEnrolledFaces(int sensorId, int userId, String opPackageName);
// Return the LockoutTracker status for the specified user
- int getLockoutModeForUser(int userId);
+ int getLockoutModeForUser(int sensorId, int userId);
// Gets the authenticator ID for face
- long getAuthenticatorId(int callingUserId);
+ long getAuthenticatorId(int sensorId, int callingUserId);
// Reset the lockout when user authenticates with strong auth (e.g. PIN, pattern or password)
void resetLockout(IBinder token, int sensorId, int userId, in byte [] hardwareAuthToken, String opPackageName);
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 4afe4b3..51e0eba 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -846,13 +846,7 @@
@Deprecated
@RequiresPermission(USE_FINGERPRINT)
public boolean hasEnrolledFingerprints() {
- if (mService != null) try {
- return mService.hasEnrolledFingerprints(
- mContext.getUserId(), mContext.getOpPackageName());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- return false;
+ return hasEnrolledFingerprints(UserHandle.myUserId());
}
/**
@@ -863,7 +857,7 @@
INTERACT_ACROSS_USERS})
public boolean hasEnrolledFingerprints(int userId) {
if (mService != null) try {
- return mService.hasEnrolledFingerprints(userId, mContext.getOpPackageName());
+ return mService.hasEnrolledFingerprintsDeprecated(userId, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -882,7 +876,7 @@
public boolean isHardwareDetected() {
if (mService != null) {
try {
- return mService.isHardwareDetected(mContext.getOpPackageName());
+ return mService.isHardwareDetectedDeprecated(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -900,7 +894,7 @@
@NonNull
public List<FingerprintSensorPropertiesInternal> getSensorPropertiesInternal() {
try {
- if (mService == null || !mService.isHardwareDetected(mContext.getOpPackageName())) {
+ if (mService == null) {
return new ArrayList<>();
}
return mService.getSensorPropertiesInternal(mContext.getOpPackageName());
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 5b14ef7..2128d67 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -53,12 +53,12 @@
// called from BiometricService. The additional uid, pid, userId arguments should be determined
// by BiometricService. To start authentication after the clients are ready, use
// startPreparedClient().
- void prepareForAuthentication(IBinder token, long operationId, int userId,
+ void prepareForAuthentication(int sensorId, IBinder token, long operationId, int userId,
IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie,
int callingUid, int callingPid, int callingUserId);
// Starts authentication with the previously prepared client.
- void startPreparedClient(int cookie);
+ void startPreparedClient(int sensorId, int cookie);
// Cancel authentication for the given sessionId
void cancelAuthentication(IBinder token, String opPackageName);
@@ -68,7 +68,7 @@
// Same as above, except this is protected by the MANAGE_BIOMETRIC signature permission. Takes
// an additional uid, pid, userid.
- void cancelAuthenticationFromService(IBinder token, String opPackageName,
+ void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName,
int callingUid, int callingPid, int callingUserId);
// Start fingerprint enrollment
@@ -88,8 +88,11 @@
// Get a list of enrolled fingerprints in the given userId.
List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName);
- // Determine if HAL is loaded and ready
- boolean isHardwareDetected(String opPackageName);
+ // Determine if the HAL is loaded and ready. Meant to support the deprecated FingerprintManager APIs
+ boolean isHardwareDetectedDeprecated(String opPackageName);
+
+ // Determine if the specified HAL is loaded and ready
+ boolean isHardwareDetected(int sensorId, String opPackageName);
// Get a pre-enrollment authentication token
void generateChallenge(IBinder token, int sensorId, int userId, IFingerprintServiceReceiver receiver, String opPackageName);
@@ -97,17 +100,20 @@
// Finish an enrollment sequence and invalidate the authentication token
void revokeChallenge(IBinder token, int sensorId, int userId, String opPackageName, long challenge);
- // Determine if a user has at least one enrolled fingerprint
- boolean hasEnrolledFingerprints(int userId, String opPackageName);
+ // Determine if a user has at least one enrolled fingerprint. Meant to support the deprecated FingerprintManager APIs
+ boolean hasEnrolledFingerprintsDeprecated(int userId, String opPackageName);
+
+ // Determine if a user has at least one enrolled fingerprint.
+ boolean hasEnrolledFingerprints(int sensorId, int userId, String opPackageName);
// Determine if a user has at least one enrolled fingerprint in any of the specified sensors
boolean hasEnrolledTemplatesForAnySensor(int userId, in List<FingerprintSensorPropertiesInternal> sensors, String opPackageName);
// Return the LockoutTracker status for the specified user
- int getLockoutModeForUser(int userId);
+ int getLockoutModeForUser(int sensorId, int userId);
// Gets the authenticator ID for fingerprint
- long getAuthenticatorId(int callingUserId);
+ long getAuthenticatorId(int sensorId, int callingUserId);
// Reset the timeout when user authenticates with strong auth (e.g. PIN, pattern or password)
void resetLockout(IBinder token, int sensorId, int userId, in byte[] hardwareAuthToken, String opPackageNAame);
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 401bb9d..bf32560 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -42,9 +42,11 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
+import java.util.stream.Collectors;
/**
* The {@link HdmiControlManager} class is used to send HDMI control messages
@@ -325,17 +327,17 @@
*
* @hide
*/
- public static final String HDMI_CEC_CONTROL_ENABLED = "1";
+ public static final int HDMI_CEC_CONTROL_ENABLED = 1;
/**
* HDMI CEC disabled.
*
* @hide
*/
- public static final String HDMI_CEC_CONTROL_DISABLED = "0";
+ public static final int HDMI_CEC_CONTROL_DISABLED = 0;
/**
* @hide
*/
- @StringDef({
+ @IntDef({
HDMI_CEC_CONTROL_ENABLED,
HDMI_CEC_CONTROL_DISABLED
})
@@ -401,17 +403,17 @@
*
* @hide
*/
- public static final String SYSTEM_AUDIO_MODE_MUTING_ENABLED = "1";
+ public static final int SYSTEM_AUDIO_MODE_MUTING_ENABLED = 1;
/**
* System Audio Mode muting disabled.
*
* @hide
*/
- public static final String SYSTEM_AUDIO_MODE_MUTING_DISABLED = "0";
+ public static final int SYSTEM_AUDIO_MODE_MUTING_DISABLED = 0;
/**
* @hide
*/
- @StringDef({
+ @IntDef({
SYSTEM_AUDIO_MODE_MUTING_ENABLED,
SYSTEM_AUDIO_MODE_MUTING_DISABLED
})
@@ -1317,24 +1319,51 @@
}
/**
- * Get a set of allowed values for a settings.
+ * Get a set of allowed values for a setting (string value-type).
*
* @param name name of the setting
* @return a set of allowed values for a settings. {@code null} on failure.
* @throws IllegalArgumentException when setting {@code name} does not exist.
+ * @throws IllegalArgumentException when setting {@code name} value type is invalid.
* @throws RuntimeException when the HdmiControlService is not available.
*
* @hide
*/
@NonNull
@RequiresPermission(android.Manifest.permission.HDMI_CEC)
- public List<String> getAllowedCecSettingValues(@NonNull @CecSettingName String name) {
+ public List<String> getAllowedCecSettingStringValues(@NonNull @CecSettingName String name) {
if (mService == null) {
Log.e(TAG, "HdmiControlService is not available");
throw new RuntimeException("HdmiControlService is not available");
}
try {
- return mService.getAllowedCecSettingValues(name);
+ return mService.getAllowedCecSettingStringValues(name);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get a set of allowed values for a setting (int value-type).
+ *
+ * @param name name of the setting
+ * @return a set of allowed values for a settings. {@code null} on failure.
+ * @throws IllegalArgumentException when setting {@code name} does not exist.
+ * @throws IllegalArgumentException when setting {@code name} value type is invalid.
+ * @throws RuntimeException when the HdmiControlService is not available.
+ *
+ * @hide
+ */
+ @NonNull
+ @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+ public List<Integer> getAllowedCecSettingIntValues(@NonNull @CecSettingName String name) {
+ if (mService == null) {
+ Log.e(TAG, "HdmiControlService is not available");
+ throw new RuntimeException("HdmiControlService is not available");
+ }
+ try {
+ int[] allowedValues = mService.getAllowedCecSettingIntValues(name);
+ return Arrays.stream(allowedValues).boxed().collect(Collectors.toList());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1350,13 +1379,13 @@
* @hide
*/
@RequiresPermission(android.Manifest.permission.HDMI_CEC)
- public void setHdmiCecEnabled(@NonNull @HdmiCecControl String value) {
+ public void setHdmiCecEnabled(@NonNull @HdmiCecControl int value) {
if (mService == null) {
Log.e(TAG, "HdmiControlService is not available");
throw new RuntimeException("HdmiControlService is not available");
}
try {
- mService.setCecSettingValue(CEC_SETTING_NAME_HDMI_CEC_ENABLED, value);
+ mService.setCecSettingIntValue(CEC_SETTING_NAME_HDMI_CEC_ENABLED, value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1373,13 +1402,13 @@
@NonNull
@HdmiCecControl
@RequiresPermission(android.Manifest.permission.HDMI_CEC)
- public String getHdmiCecEnabled() {
+ public int getHdmiCecEnabled() {
if (mService == null) {
Log.e(TAG, "HdmiControlService is not available");
throw new RuntimeException("HdmiControlService is not available");
}
try {
- return mService.getCecSettingValue(CEC_SETTING_NAME_HDMI_CEC_ENABLED);
+ return mService.getCecSettingIntValue(CEC_SETTING_NAME_HDMI_CEC_ENABLED);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1401,7 +1430,7 @@
throw new RuntimeException("HdmiControlService is not available");
}
try {
- mService.setCecSettingValue(CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP, value);
+ mService.setCecSettingStringValue(CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP, value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1424,7 +1453,7 @@
throw new RuntimeException("HdmiControlService is not available");
}
try {
- return mService.getCecSettingValue(CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP);
+ return mService.getCecSettingStringValue(CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1447,7 +1476,7 @@
throw new RuntimeException("HdmiControlService is not available");
}
try {
- mService.setCecSettingValue(
+ mService.setCecSettingStringValue(
CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST, value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1471,7 +1500,7 @@
throw new RuntimeException("HdmiControlService is not available");
}
try {
- return mService.getCecSettingValue(
+ return mService.getCecSettingStringValue(
CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1488,13 +1517,13 @@
* @hide
*/
@RequiresPermission(android.Manifest.permission.HDMI_CEC)
- public void setSystemAudioModeMuting(@NonNull @SystemAudioModeMuting String value) {
+ public void setSystemAudioModeMuting(@NonNull @SystemAudioModeMuting int value) {
if (mService == null) {
Log.e(TAG, "HdmiControlService is not available");
throw new RuntimeException("HdmiControlService is not available");
}
try {
- mService.setCecSettingValue(CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, value);
+ mService.setCecSettingIntValue(CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1511,13 +1540,13 @@
@NonNull
@SystemAudioModeMuting
@RequiresPermission(android.Manifest.permission.HDMI_CEC)
- public String getSystemAudioModeMuting() {
+ public int getSystemAudioModeMuting() {
if (mService == null) {
Log.e(TAG, "HdmiControlService is not available");
throw new RuntimeException("HdmiControlService is not available");
}
try {
- return mService.getCecSettingValue(CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING);
+ return mService.getCecSettingIntValue(CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
index 22d4640..fab56b8 100644
--- a/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
+++ b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
@@ -301,18 +301,33 @@
}
@Override
- public List<String> getAllowedCecSettingValues(String name) {
- return HdmiControlServiceWrapper.this.getAllowedCecSettingValues(name);
+ public List<String> getAllowedCecSettingStringValues(String name) {
+ return HdmiControlServiceWrapper.this.getAllowedCecSettingStringValues(name);
}
@Override
- public String getCecSettingValue(String name) {
- return HdmiControlServiceWrapper.this.getCecSettingValue(name);
+ public int[] getAllowedCecSettingIntValues(String name) {
+ return HdmiControlServiceWrapper.this.getAllowedCecSettingIntValues(name);
}
@Override
- public void setCecSettingValue(String name, String value) {
- HdmiControlServiceWrapper.this.setCecSettingValue(name, value);
+ public String getCecSettingStringValue(String name) {
+ return HdmiControlServiceWrapper.this.getCecSettingStringValue(name);
+ }
+
+ @Override
+ public void setCecSettingStringValue(String name, String value) {
+ HdmiControlServiceWrapper.this.setCecSettingStringValue(name, value);
+ }
+
+ @Override
+ public int getCecSettingIntValue(String name) {
+ return HdmiControlServiceWrapper.this.getCecSettingIntValue(name);
+ }
+
+ @Override
+ public void setCecSettingIntValue(String name, int value) {
+ HdmiControlServiceWrapper.this.setCecSettingIntValue(name, value);
}
};
@@ -494,15 +509,30 @@
}
/** @hide */
- public List<String> getAllowedCecSettingValues(String name) {
+ public List<String> getAllowedCecSettingStringValues(String name) {
return new ArrayList<>();
}
/** @hide */
- public String getCecSettingValue(String name) {
+ public int[] getAllowedCecSettingIntValues(String name) {
+ return new int[0];
+ }
+
+ /** @hide */
+ public String getCecSettingStringValue(String name) {
return "";
}
/** @hide */
- public void setCecSettingValue(String name, String value) {}
+ public void setCecSettingStringValue(String name, String value) {
+ }
+
+ /** @hide */
+ public int getCecSettingIntValue(String name) {
+ return 0;
+ }
+
+ /** @hide */
+ public void setCecSettingIntValue(String name, int value) {
+ }
}
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 6df164b..af9d3ac 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -88,7 +88,10 @@
void reportAudioStatus(int deviceType, int volume, int maxVolume, boolean isMute);
void setSystemAudioModeOnForAudioOnlySource();
List<String> getUserCecSettings();
- List<String> getAllowedCecSettingValues(String name);
- String getCecSettingValue(String name);
- void setCecSettingValue(String name, String value);
+ List<String> getAllowedCecSettingStringValues(String name);
+ int[] getAllowedCecSettingIntValues(String name);
+ String getCecSettingStringValue(String name);
+ void setCecSettingStringValue(String name, String value);
+ int getCecSettingIntValue(String name);
+ void setCecSettingIntValue(String name, int value);
}
diff --git a/core/java/android/hardware/usb/AccessoryFilter.java b/core/java/android/hardware/usb/AccessoryFilter.java
index 8345ff3..98e8c92 100644
--- a/core/java/android/hardware/usb/AccessoryFilter.java
+++ b/core/java/android/hardware/usb/AccessoryFilter.java
@@ -102,7 +102,7 @@
public boolean matches(UsbAccessory acc) {
if (mManufacturer != null && !acc.getManufacturer().equals(mManufacturer)) return false;
if (mModel != null && !acc.getModel().equals(mModel)) return false;
- return !(mVersion != null && !acc.getVersion().equals(mVersion));
+ return !(mVersion != null && !mVersion.equals(acc.getVersion()));
}
/**
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 32a8c0a..44640c4 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -46,6 +46,7 @@
import static android.inputmethodservice.InputMethodServiceProto.TOKEN;
import static android.inputmethodservice.InputMethodServiceProto.VIEWS_CREATED;
import static android.inputmethodservice.InputMethodServiceProto.WINDOW_VISIBLE;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowInsets.Type.navigationBars;
@@ -80,6 +81,7 @@
import android.os.IBinder;
import android.os.ResultReceiver;
import android.os.SystemClock;
+import android.os.Trace;
import android.provider.Settings;
import android.text.InputType;
import android.text.Layout;
@@ -645,7 +647,9 @@
@Override
public void startInput(InputConnection ic, EditorInfo attribute) {
if (DEBUG) Log.v(TAG, "startInput(): editor=" + attribute);
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.startInput");
doStartInput(ic, attribute, false);
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
/**
@@ -705,6 +709,8 @@
return;
}
final boolean wasVisible = isInputViewShown();
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.hideSoftInput");
+
applyVisibilityInInsetsConsumerIfNecessary(false /* setVisible */);
mShowInputFlags = 0;
mShowInputRequested = false;
@@ -717,6 +723,7 @@
: (wasVisible ? InputMethodManager.RESULT_UNCHANGED_SHOWN
: InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
}
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
/**
@@ -748,6 +755,13 @@
+ " Use requestShowSelf(int) itself");
return;
}
+
+ if (Trace.isEnabled()) {
+ Binder.enableTracing();
+ } else {
+ Binder.disableTracing();
+ }
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showSoftInput");
final boolean wasVisible = isInputViewShown();
if (dispatchOnShowInputRequested(flags, false)) {
@@ -764,6 +778,7 @@
: (wasVisible ? InputMethodManager.RESULT_UNCHANGED_SHOWN
: InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
}
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
/**
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 209a3fa..923b9b76 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -20,12 +20,13 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
-import android.net.util.LinkPropertiesUtils;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import com.android.net.module.util.LinkPropertiesUtils;
+
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index 049e9bc..c83c23a 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -20,13 +20,13 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
-import android.net.util.MacAddressUtils;
import android.net.wifi.WifiInfo;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.util.Preconditions;
+import com.android.net.module.util.MacAddressUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 2543aa3..5b6684a 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -21,11 +21,12 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
-import android.net.util.NetUtils;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.net.module.util.NetUtils;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.Inet4Address;
diff --git a/core/java/android/os/CombinedVibrationEffect.java b/core/java/android/os/CombinedVibrationEffect.java
index 77bfa57..f552aaa 100644
--- a/core/java/android/os/CombinedVibrationEffect.java
+++ b/core/java/android/os/CombinedVibrationEffect.java
@@ -17,7 +17,12 @@
package android.os;
import android.annotation.NonNull;
+import android.util.SparseArray;
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
/**
@@ -31,6 +36,8 @@
*/
public abstract class CombinedVibrationEffect implements Parcelable {
private static final int PARCEL_TOKEN_MONO = 1;
+ private static final int PARCEL_TOKEN_STEREO = 2;
+ private static final int PARCEL_TOKEN_SEQUENTIAL = 3;
/** @hide to prevent subclassing from outside of the framework */
public CombinedVibrationEffect() {
@@ -41,8 +48,8 @@
*
* A synced vibration effect should be performed by multiple vibrators at the same time.
*
- * @param effect The {@link VibrationEffect} to perform
- * @return The desired combined effect.
+ * @param effect The {@link VibrationEffect} to perform.
+ * @return The synced effect.
*/
@NonNull
public static CombinedVibrationEffect createSynced(@NonNull VibrationEffect effect) {
@@ -51,6 +58,30 @@
return combined;
}
+ /**
+ * Start creating a synced vibration effect.
+ *
+ * A synced vibration effect should be performed by multiple vibrators at the same time.
+ *
+ * @see CombinedVibrationEffect.SyncedCombination
+ */
+ @NonNull
+ public static SyncedCombination startSynced() {
+ return new SyncedCombination();
+ }
+
+ /**
+ * Start creating a sequential vibration effect.
+ *
+ * A sequential vibration effect should be performed by multiple vibrators in order.
+ *
+ * @see CombinedVibrationEffect.SequentialCombination
+ */
+ @NonNull
+ public static SequentialCombination startSequential() {
+ return new SequentialCombination();
+ }
+
@Override
public int describeContents() {
return 0;
@@ -60,6 +91,164 @@
public abstract void validate();
/**
+ * A combination of haptic effects that should be played in multiple vibrators in sync.
+ *
+ * @hide
+ * @see CombinedVibrationEffect#startSynced()
+ */
+ public static final class SyncedCombination {
+
+ private final SparseArray<VibrationEffect> mEffects = new SparseArray<>();
+
+ SyncedCombination() {
+ }
+
+ /**
+ * Add or replace a one shot vibration effect to be performed by the specified vibrator.
+ *
+ * @param vibratorId The id of the vibrator that should perform this effect.
+ * @param effect The effect this vibrator should play.
+ * @return The {@link CombinedVibrationEffect.SyncedCombination} object to enable adding
+ * multiple effects in one chain.
+ * @see VibrationEffect#createOneShot(long, int)
+ */
+ @NonNull
+ public SyncedCombination addVibrator(int vibratorId, VibrationEffect effect) {
+ mEffects.put(vibratorId, effect);
+ return this;
+ }
+
+ /**
+ * Combine all of the added effects into a combined effect.
+ *
+ * The {@link CombinedVibrationEffect.SyncedCombination} object is still valid after this
+ * call, so you can continue adding more effects to it and generating more
+ * {@link CombinedVibrationEffect}s by calling this method again.
+ *
+ * @return The {@link CombinedVibrationEffect} resulting from combining the added effects to
+ * be played in sync.
+ */
+ @NonNull
+ public CombinedVibrationEffect combine() {
+ if (mEffects.size() == 0) {
+ throw new IllegalStateException(
+ "Combination must have at least one element to combine.");
+ }
+ CombinedVibrationEffect combined = new Stereo(mEffects);
+ combined.validate();
+ return combined;
+ }
+ }
+
+ /**
+ * A combination of haptic effects that should be played in multiple vibrators in sequence.
+ *
+ * @hide
+ * @see CombinedVibrationEffect#startSequential()
+ */
+ public static final class SequentialCombination {
+
+ private final ArrayList<CombinedVibrationEffect> mEffects = new ArrayList<>();
+ private final ArrayList<Integer> mDelays = new ArrayList<>();
+
+ SequentialCombination() {
+ }
+
+ /**
+ * Add a single vibration effect to be performed next.
+ *
+ * Similar to {@link #addNext(int, VibrationEffect, int)}, but with no delay.
+ *
+ * @param vibratorId The id of the vibrator that should perform this effect.
+ * @param effect The effect this vibrator should play.
+ * @return The {@link CombinedVibrationEffect.SequentialCombination} object to enable adding
+ * multiple effects in one chain.
+ */
+ @NonNull
+ public SequentialCombination addNext(int vibratorId, @NonNull VibrationEffect effect) {
+ return addNext(vibratorId, effect, /* delay= */ 0);
+ }
+
+ /**
+ * Add a single vibration effect to be performed next.
+ *
+ * @param vibratorId The id of the vibrator that should perform this effect.
+ * @param effect The effect this vibrator should play.
+ * @param delay The amount of time, in milliseconds, to wait between playing the prior
+ * effect and this one.
+ * @return The {@link CombinedVibrationEffect.SequentialCombination} object to enable adding
+ * multiple effects in one chain.
+ */
+ @NonNull
+ public SequentialCombination addNext(int vibratorId, @NonNull VibrationEffect effect,
+ int delay) {
+ return addNext(
+ CombinedVibrationEffect.startSynced().addVibrator(vibratorId, effect).combine(),
+ delay);
+ }
+
+ /**
+ * Add a combined vibration effect to be performed next.
+ *
+ * Similar to {@link #addNext(CombinedVibrationEffect, int)}, but with no delay.
+ *
+ * @param effect The combined effect to be performed next.
+ * @return The {@link CombinedVibrationEffect.SequentialCombination} object to enable adding
+ * multiple effects in one chain.
+ * @see VibrationEffect#createOneShot(long, int)
+ */
+ @NonNull
+ public SequentialCombination addNext(@NonNull CombinedVibrationEffect effect) {
+ return addNext(effect, /* delay= */ 0);
+ }
+
+ /**
+ * Add a one shot vibration effect to be performed by the specified vibrator.
+ *
+ * @param effect The combined effect to be performed next.
+ * @param delay The amount of time, in milliseconds, to wait between playing the prior
+ * effect and this one.
+ * @return The {@link CombinedVibrationEffect.SequentialCombination} object to enable adding
+ * multiple effects in one chain.
+ */
+ @NonNull
+ public SequentialCombination addNext(@NonNull CombinedVibrationEffect effect, int delay) {
+ if (effect instanceof Sequential) {
+ Sequential sequentialEffect = (Sequential) effect;
+ int firstEffectIndex = mDelays.size();
+ mEffects.addAll(sequentialEffect.getEffects());
+ mDelays.addAll(sequentialEffect.getDelays());
+ mDelays.set(firstEffectIndex, delay + mDelays.get(firstEffectIndex));
+ } else {
+ mEffects.add(effect);
+ mDelays.add(delay);
+ }
+ return this;
+ }
+
+ /**
+ * Combine all of the added effects in sequence.
+ *
+ * The {@link CombinedVibrationEffect.SequentialCombination} object is still valid after
+ * this call, so you can continue adding more effects to it and generating more {@link
+ * CombinedVibrationEffect}s by calling this method again.
+ *
+ * @return The {@link CombinedVibrationEffect} resulting from combining the added effects to
+ * be played in sequence.
+ */
+ @NonNull
+ public CombinedVibrationEffect combine() {
+ if (mEffects.size() == 0) {
+ throw new IllegalStateException(
+ "Combination must have at least one element to combine.");
+ }
+ CombinedVibrationEffect combined = new Sequential(mEffects, mDelays);
+ combined.validate();
+ return combined;
+ }
+ }
+
+ /**
* Represents a single {@link VibrationEffect} that should be executed in all vibrators in sync.
*
* @hide
@@ -87,10 +276,10 @@
@Override
public boolean equals(Object o) {
- if (!(o instanceof CombinedVibrationEffect.Mono)) {
+ if (!(o instanceof Mono)) {
return false;
}
- CombinedVibrationEffect.Mono other = (CombinedVibrationEffect.Mono) o;
+ Mono other = (Mono) o;
return other.mEffect.equals(other.mEffect);
}
@@ -128,6 +317,206 @@
};
}
+ /**
+ * Represents a list of {@link VibrationEffect}s that should be executed in sync.
+ *
+ * @hide
+ */
+ public static final class Stereo extends CombinedVibrationEffect {
+
+ /** Mapping vibrator ids to effects. */
+ private final SparseArray<VibrationEffect> mEffects;
+
+ public Stereo(Parcel in) {
+ int size = in.readInt();
+ mEffects = new SparseArray<>(size);
+ for (int i = 0; i < size; i++) {
+ int vibratorId = in.readInt();
+ mEffects.put(vibratorId, VibrationEffect.CREATOR.createFromParcel(in));
+ }
+ }
+
+ public Stereo(@NonNull SparseArray<VibrationEffect> effects) {
+ mEffects = new SparseArray<>(effects.size());
+ for (int i = 0; i < effects.size(); i++) {
+ mEffects.put(effects.keyAt(i), effects.valueAt(i));
+ }
+ }
+
+ /** Effects to be performed in sync, where each key represents the vibrator id. */
+ public SparseArray<VibrationEffect> getEffects() {
+ return mEffects;
+ }
+
+ /** @hide */
+ @Override
+ public void validate() {
+ Preconditions.checkArgument(mEffects.size() > 0,
+ "There should be at least one effect set for a combined effect");
+ for (int i = 0; i < mEffects.size(); i++) {
+ mEffects.valueAt(i).validate();
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Stereo)) {
+ return false;
+ }
+ Stereo other = (Stereo) o;
+ if (mEffects.size() != other.mEffects.size()) {
+ return false;
+ }
+ for (int i = 0; i < mEffects.size(); i++) {
+ if (!mEffects.valueAt(i).equals(other.mEffects.get(mEffects.keyAt(i)))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mEffects);
+ }
+
+ @Override
+ public String toString() {
+ return "Stereo{mEffects=" + mEffects + '}';
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(PARCEL_TOKEN_STEREO);
+ out.writeInt(mEffects.size());
+ for (int i = 0; i < mEffects.size(); i++) {
+ out.writeInt(mEffects.keyAt(i));
+ mEffects.valueAt(i).writeToParcel(out, flags);
+ }
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<Stereo> CREATOR =
+ new Parcelable.Creator<Stereo>() {
+ @Override
+ public Stereo createFromParcel(@NonNull Parcel in) {
+ // Skip the type token
+ in.readInt();
+ return new Stereo(in);
+ }
+
+ @Override
+ @NonNull
+ public Stereo[] newArray(int size) {
+ return new Stereo[size];
+ }
+ };
+ }
+
+ /**
+ * Represents a list of {@link VibrationEffect}s that should be executed in sequence.
+ *
+ * @hide
+ */
+ public static final class Sequential extends CombinedVibrationEffect {
+ private final List<CombinedVibrationEffect> mEffects;
+ private final List<Integer> mDelays;
+
+ public Sequential(Parcel in) {
+ int size = in.readInt();
+ mEffects = new ArrayList<>(size);
+ mDelays = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ mDelays.add(in.readInt());
+ mEffects.add(CombinedVibrationEffect.CREATOR.createFromParcel(in));
+ }
+ }
+
+ public Sequential(@NonNull List<CombinedVibrationEffect> effects,
+ @NonNull List<Integer> delays) {
+ mEffects = new ArrayList<>(effects);
+ mDelays = new ArrayList<>(delays);
+ }
+
+ /** Effects to be performed in sequence. */
+ public List<CombinedVibrationEffect> getEffects() {
+ return mEffects;
+ }
+
+ /** Delay to be applied before each effect in {@link #getEffects()}. */
+ public List<Integer> getDelays() {
+ return mDelays;
+ }
+
+ /** @hide */
+ @Override
+ public void validate() {
+ Preconditions.checkArgument(mEffects.size() > 0,
+ "There should be at least one effect set for a combined effect");
+ Preconditions.checkArgument(mEffects.size() == mDelays.size(),
+ "Effect and delays should have equal length");
+ for (long delay : mDelays) {
+ if (delay < 0) {
+ throw new IllegalArgumentException("Delays must all be >= 0"
+ + " (delays=" + mDelays + ")");
+ }
+ }
+ for (CombinedVibrationEffect effect : mEffects) {
+ if (effect instanceof Sequential) {
+ throw new IllegalArgumentException(
+ "There should be no nested sequential effects in a combined effect");
+ }
+ effect.validate();
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Sequential)) {
+ return false;
+ }
+ Sequential other = (Sequential) o;
+ return mDelays.equals(other.mDelays) && mEffects.equals(other.mEffects);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mEffects);
+ }
+
+ @Override
+ public String toString() {
+ return "Sequential{mEffects=" + mEffects + ", mDelays=" + mDelays + '}';
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(PARCEL_TOKEN_SEQUENTIAL);
+ out.writeInt(mEffects.size());
+ for (int i = 0; i < mEffects.size(); i++) {
+ out.writeInt(mDelays.get(i));
+ mEffects.get(i).writeToParcel(out, flags);
+ }
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<Sequential> CREATOR =
+ new Parcelable.Creator<Sequential>() {
+ @Override
+ public Sequential createFromParcel(@NonNull Parcel in) {
+ // Skip the type token
+ in.readInt();
+ return new Sequential(in);
+ }
+
+ @Override
+ @NonNull
+ public Sequential[] newArray(int size) {
+ return new Sequential[size];
+ }
+ };
+ }
+
@NonNull
public static final Parcelable.Creator<CombinedVibrationEffect> CREATOR =
new Parcelable.Creator<CombinedVibrationEffect>() {
@@ -135,7 +524,11 @@
public CombinedVibrationEffect createFromParcel(Parcel in) {
int token = in.readInt();
if (token == PARCEL_TOKEN_MONO) {
- return new CombinedVibrationEffect.Mono(in);
+ return new Mono(in);
+ } else if (token == PARCEL_TOKEN_STEREO) {
+ return new Stereo(in);
+ } else if (token == PARCEL_TOKEN_SEQUENTIAL) {
+ return new Sequential(in);
} else {
throw new IllegalStateException(
"Unexpected combined vibration event type token in parcel.");
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 2edd322..aba1f28 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -4033,7 +4033,8 @@
* @return the {@link RemoveResult} code
* @hide
*/
- @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
+ Manifest.permission.CREATE_USERS})
public @RemoveResult int removeUserOrSetEphemeral(@UserIdInt int userId) {
try {
return mService.removeUserOrSetEphemeral(userId);
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 0a4e867..97c9f4b 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -251,6 +251,15 @@
public static final String NAMESPACE_PACKAGE_MANAGER_SERVICE = "package_manager_service";
/**
+ * Namespace for features related to the Profcollect native Service.
+ * These features are applied at reboot.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_PROFCOLLECT_NATIVE_BOOT = "profcollect_native_boot";
+
+ /**
* Namespace for Rollback flags that are applied immediately.
*
* @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cc3d92d..f31e70a 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9773,6 +9773,14 @@
public static final String DEVELOPMENT_USE_BLAST_ADAPTER_SV =
"use_blast_adapter_sv";
+ /**
+ * If {@code true}, vendor provided window manager display settings will be ignored.
+ * (0 = false, 1 = true)
+ * @hide
+ */
+ public static final String DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS =
+ "ignore_vendor_display_settings";
+
/**
* Whether user has enabled development settings.
*/
diff --git a/core/java/android/service/autofill/InlinePresentation.java b/core/java/android/service/autofill/InlinePresentation.java
index 6eb2a15..fbf23b6 100644
--- a/core/java/android/service/autofill/InlinePresentation.java
+++ b/core/java/android/service/autofill/InlinePresentation.java
@@ -77,7 +77,7 @@
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -259,10 +259,10 @@
};
@DataClass.Generated(
- time = 1596484869201L,
- codegenVersion = "1.0.15",
+ time = 1604456277638L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/core/java/android/service/autofill/InlinePresentation.java",
- inputSignatures = "private final @android.annotation.NonNull android.app.slice.Slice mSlice\nprivate final @android.annotation.NonNull android.widget.inline.InlinePresentationSpec mInlinePresentationSpec\nprivate final boolean mPinned\npublic @android.annotation.NonNull @android.annotation.Size(min=0L) java.lang.String[] getAutofillHints()\nclass InlinePresentation extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)")
+ inputSignatures = "private final @android.annotation.NonNull android.app.slice.Slice mSlice\nprivate final @android.annotation.NonNull android.widget.inline.InlinePresentationSpec mInlinePresentationSpec\nprivate final boolean mPinned\npublic @android.annotation.NonNull @android.annotation.Size java.lang.String[] getAutofillHints()\nclass InlinePresentation extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java b/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java
index 2a809b1..4ffffc6 100644
--- a/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java
+++ b/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java
@@ -46,12 +46,13 @@
* CarrierMessagingService.
* @hide
*/
-public abstract class CarrierMessagingServiceWrapper {
+public final class CarrierMessagingServiceWrapper {
// Populated by bindToCarrierMessagingService. bindToCarrierMessagingService must complete
// prior to calling disposeConnection so that mCarrierMessagingServiceConnection is initialized.
private volatile CarrierMessagingServiceConnection mCarrierMessagingServiceConnection;
private volatile ICarrierMessagingService mICarrierMessagingService;
+ private Runnable mOnServiceReadyCallback;
/**
* Binds to the carrier messaging service under package {@code carrierPackageName}. This method
@@ -63,12 +64,14 @@
* @hide
*/
public boolean bindToCarrierMessagingService(@NonNull Context context,
- @NonNull String carrierPackageName) {
+ @NonNull String carrierPackageName,
+ @NonNull Runnable onServiceReadyCallback) {
Preconditions.checkState(mCarrierMessagingServiceConnection == null);
Intent intent = new Intent(CarrierMessagingService.SERVICE_INTERFACE);
intent.setPackage(carrierPackageName);
mCarrierMessagingServiceConnection = new CarrierMessagingServiceConnection();
+ mOnServiceReadyCallback = onServiceReadyCallback;
return context.bindService(intent, mCarrierMessagingServiceConnection,
Context.BIND_AUTO_CREATE);
}
@@ -83,22 +86,17 @@
Preconditions.checkNotNull(mCarrierMessagingServiceConnection);
context.unbindService(mCarrierMessagingServiceConnection);
mCarrierMessagingServiceConnection = null;
+ mOnServiceReadyCallback = null;
}
/**
- * Implemented by subclasses to use the carrier messaging service once it is ready.
- * @hide
- */
- public abstract void onServiceReady();
-
- /**
* Called when connection with service is established.
*
* @param carrierMessagingService the carrier messaing service interface
*/
private void onServiceReady(ICarrierMessagingService carrierMessagingService) {
mICarrierMessagingService = carrierMessagingService;
- onServiceReady();
+ if (mOnServiceReadyCallback != null) mOnServiceReadyCallback.run();
}
/**
@@ -113,11 +111,11 @@
* @hide
*/
public void filterSms(@NonNull MessagePdu pdu, @NonNull String format, int destPort,
- int subId, @NonNull final CarrierMessagingCallbackWrapper callback) {
+ int subId, @NonNull final CarrierMessagingCallback callback) {
if (mICarrierMessagingService != null) {
try {
mICarrierMessagingService.filterSms(pdu, format, destPort, subId,
- new CarrierMessagingCallbackWrapperInternal(callback));
+ new CarrierMessagingCallbackInternal(callback));
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -137,11 +135,11 @@
* @hide
*/
public void sendTextSms(@NonNull String text, int subId, @NonNull String destAddress,
- int sendSmsFlag, @NonNull final CarrierMessagingCallbackWrapper callback) {
+ int sendSmsFlag, @NonNull final CarrierMessagingCallback callback) {
if (mICarrierMessagingService != null) {
try {
mICarrierMessagingService.sendTextSms(text, subId, destAddress, sendSmsFlag,
- new CarrierMessagingCallbackWrapperInternal(callback));
+ new CarrierMessagingCallbackInternal(callback));
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -163,11 +161,11 @@
*/
public void sendDataSms(@NonNull byte[] data, int subId, @NonNull String destAddress,
int destPort, int sendSmsFlag,
- @NonNull final CarrierMessagingCallbackWrapper callback) {
+ @NonNull final CarrierMessagingCallback callback) {
if (mICarrierMessagingService != null) {
try {
mICarrierMessagingService.sendDataSms(data, subId, destAddress, destPort,
- sendSmsFlag, new CarrierMessagingCallbackWrapperInternal(callback));
+ sendSmsFlag, new CarrierMessagingCallbackInternal(callback));
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -188,11 +186,11 @@
*/
public void sendMultipartTextSms(@NonNull List<String> parts, int subId,
@NonNull String destAddress, int sendSmsFlag,
- @NonNull final CarrierMessagingCallbackWrapper callback) {
+ @NonNull final CarrierMessagingCallback callback) {
if (mICarrierMessagingService != null) {
try {
mICarrierMessagingService.sendMultipartTextSms(parts, subId, destAddress,
- sendSmsFlag, new CarrierMessagingCallbackWrapperInternal(callback));
+ sendSmsFlag, new CarrierMessagingCallbackInternal(callback));
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -212,11 +210,11 @@
* @hide
*/
public void sendMms(@NonNull Uri pduUri, int subId, @NonNull Uri location,
- @NonNull final CarrierMessagingCallbackWrapper callback) {
+ @NonNull final CarrierMessagingCallback callback) {
if (mICarrierMessagingService != null) {
try {
mICarrierMessagingService.sendMms(pduUri, subId, location,
- new CarrierMessagingCallbackWrapperInternal(callback));
+ new CarrierMessagingCallbackInternal(callback));
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -235,11 +233,11 @@
* @hide
*/
public void downloadMms(@NonNull Uri pduUri, int subId, @NonNull Uri location,
- @NonNull final CarrierMessagingCallbackWrapper callback) {
+ @NonNull final CarrierMessagingCallback callback) {
if (mICarrierMessagingService != null) {
try {
mICarrierMessagingService.downloadMms(pduUri, subId, location,
- new CarrierMessagingCallbackWrapperInternal(callback));
+ new CarrierMessagingCallbackInternal(callback));
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -265,7 +263,7 @@
* {@link CarrierMessagingServiceWrapper}.
* @hide
*/
- public abstract static class CarrierMessagingCallbackWrapper {
+ public interface CarrierMessagingCallback {
/**
* Response callback for {@link CarrierMessagingServiceWrapper#filterSms}.
@@ -277,7 +275,7 @@
* {@see CarrierMessagingService#onReceiveTextSms}.
* @hide
*/
- public void onFilterComplete(int result) {
+ default void onFilterComplete(int result) {
}
@@ -291,7 +289,7 @@
* only if result is {@link CarrierMessagingService#SEND_STATUS_OK}.
* @hide
*/
- public void onSendSmsComplete(int result, int messageRef) {
+ default void onSendSmsComplete(int result, int messageRef) {
}
@@ -305,7 +303,7 @@
* {@link CarrierMessagingService#SEND_STATUS_OK}.
* @hide
*/
- public void onSendMultipartSmsComplete(int result, @Nullable int[] messageRefs) {
+ default void onSendMultipartSmsComplete(int result, @Nullable int[] messageRefs) {
}
@@ -319,7 +317,7 @@
* {@link CarrierMessagingService#SEND_STATUS_OK}.
* @hide
*/
- public void onSendMmsComplete(int result, @Nullable byte[] sendConfPdu) {
+ default void onSendMmsComplete(int result, @Nullable byte[] sendConfPdu) {
}
@@ -330,43 +328,43 @@
* and {@link CarrierMessagingService#SEND_STATUS_ERROR}.
* @hide
*/
- public void onDownloadMmsComplete(int result) {
+ default void onDownloadMmsComplete(int result) {
}
}
- private final class CarrierMessagingCallbackWrapperInternal
+ private final class CarrierMessagingCallbackInternal
extends ICarrierMessagingCallback.Stub {
- CarrierMessagingCallbackWrapper mCarrierMessagingCallbackWrapper;
+ CarrierMessagingCallback mCarrierMessagingCallback;
- CarrierMessagingCallbackWrapperInternal(CarrierMessagingCallbackWrapper callback) {
- mCarrierMessagingCallbackWrapper = callback;
+ CarrierMessagingCallbackInternal(CarrierMessagingCallback callback) {
+ mCarrierMessagingCallback = callback;
}
@Override
public void onFilterComplete(int result) throws RemoteException {
- mCarrierMessagingCallbackWrapper.onFilterComplete(result);
+ mCarrierMessagingCallback.onFilterComplete(result);
}
@Override
public void onSendSmsComplete(int result, int messageRef) throws RemoteException {
- mCarrierMessagingCallbackWrapper.onSendSmsComplete(result, messageRef);
+ mCarrierMessagingCallback.onSendSmsComplete(result, messageRef);
}
@Override
public void onSendMultipartSmsComplete(int result, int[] messageRefs)
throws RemoteException {
- mCarrierMessagingCallbackWrapper.onSendMultipartSmsComplete(result, messageRefs);
+ mCarrierMessagingCallback.onSendMultipartSmsComplete(result, messageRefs);
}
@Override
public void onSendMmsComplete(int result, byte[] sendConfPdu) throws RemoteException {
- mCarrierMessagingCallbackWrapper.onSendMmsComplete(result, sendConfPdu);
+ mCarrierMessagingCallback.onSendMmsComplete(result, sendConfPdu);
}
@Override
public void onDownloadMmsComplete(int result) throws RemoteException {
- mCarrierMessagingCallbackWrapper.onDownloadMmsComplete(result);
+ mCarrierMessagingCallback.onDownloadMmsComplete(result);
}
}
-}
+}
\ No newline at end of file
diff --git a/core/java/android/timezone/TzDataSetVersion.java b/core/java/android/timezone/TzDataSetVersion.java
index edcbbb3..4031ff8 100644
--- a/core/java/android/timezone/TzDataSetVersion.java
+++ b/core/java/android/timezone/TzDataSetVersion.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import com.android.i18n.timezone.TimeZoneDataFiles;
import com.android.internal.annotations.VisibleForTesting;
import java.io.IOException;
@@ -76,8 +77,7 @@
@NonNull
public static TzDataSetVersion read() throws IOException, TzDataSetException {
try {
- return new TzDataSetVersion(
- com.android.i18n.timezone.TzDataSetVersion.readTimeZoneModuleVersion());
+ return new TzDataSetVersion(TimeZoneDataFiles.readTimeZoneModuleVersion());
} catch (com.android.i18n.timezone.TzDataSetVersion.TzDataSetException e) {
throw new TzDataSetException(e.getMessage(), e);
}
diff --git a/core/java/android/uwb/AngleMeasurement.java b/core/java/android/uwb/AngleMeasurement.java
index c3e2ecc..33bc121 100644
--- a/core/java/android/uwb/AngleMeasurement.java
+++ b/core/java/android/uwb/AngleMeasurement.java
@@ -17,6 +17,10 @@
package android.uwb;
import android.annotation.FloatRange;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
/**
* Angle measurement
@@ -26,7 +30,7 @@
*
* @hide
*/
-public final class AngleMeasurement {
+public final class AngleMeasurement implements Parcelable {
private final double mRadians;
private final double mErrorRadians;
private final double mConfidenceLevel;
@@ -39,7 +43,7 @@
/**
* Angle measurement in radians
- *
+ *
* @return angle in radians
*/
@FloatRange(from = -Math.PI, to = +Math.PI)
@@ -74,6 +78,61 @@
}
/**
+ * @hide
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof AngleMeasurement) {
+ AngleMeasurement other = (AngleMeasurement) obj;
+ return mRadians == other.getRadians()
+ && mErrorRadians == other.getErrorRadians()
+ && mConfidenceLevel == other.getConfidenceLevel();
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(mRadians, mErrorRadians, mConfidenceLevel);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeDouble(mRadians);
+ dest.writeDouble(mErrorRadians);
+ dest.writeDouble(mConfidenceLevel);
+ }
+
+ public static final @android.annotation.NonNull Creator<AngleMeasurement> CREATOR =
+ new Creator<AngleMeasurement>() {
+ @Override
+ public AngleMeasurement createFromParcel(Parcel in) {
+ Builder builder = new Builder();
+ builder.setRadians(in.readDouble());
+ builder.setErrorRadians(in.readDouble());
+ builder.setConfidenceLevel(in.readDouble());
+ return builder.build();
+ }
+
+ @Override
+ public AngleMeasurement[] newArray(int size) {
+ return new AngleMeasurement[size];
+ }
+ };
+
+ /**
* Builder class for {@link AngleMeasurement}.
*/
public static final class Builder {
diff --git a/core/java/android/uwb/AngleOfArrivalMeasurement.java b/core/java/android/uwb/AngleOfArrivalMeasurement.java
index a7b5eae..cd5af69 100644
--- a/core/java/android/uwb/AngleOfArrivalMeasurement.java
+++ b/core/java/android/uwb/AngleOfArrivalMeasurement.java
@@ -18,13 +18,17 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
/**
* Represents an angle of arrival measurement between two devices using Ultra Wideband
*
* @hide
*/
-public final class AngleOfArrivalMeasurement {
+public final class AngleOfArrivalMeasurement implements Parcelable {
private final AngleMeasurement mAzimuthAngleMeasurement;
private final AngleMeasurement mAltitudeAngleMeasurement;
@@ -71,6 +75,63 @@
}
/**
+ * @hide
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof AngleOfArrivalMeasurement) {
+ AngleOfArrivalMeasurement other = (AngleOfArrivalMeasurement) obj;
+ return mAzimuthAngleMeasurement.equals(other.getAzimuth())
+ && mAltitudeAngleMeasurement.equals(other.getAltitude());
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(mAzimuthAngleMeasurement, mAltitudeAngleMeasurement);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mAzimuthAngleMeasurement, flags);
+ dest.writeParcelable(mAltitudeAngleMeasurement, flags);
+ }
+
+ public static final @android.annotation.NonNull Creator<AngleOfArrivalMeasurement> CREATOR =
+ new Creator<AngleOfArrivalMeasurement>() {
+ @Override
+ public AngleOfArrivalMeasurement createFromParcel(Parcel in) {
+ Builder builder = new Builder();
+
+ builder.setAzimuthAngleMeasurement(
+ in.readParcelable(AngleMeasurement.class.getClassLoader()));
+
+ builder.setAltitudeAngleMeasurement(
+ in.readParcelable(AngleMeasurement.class.getClassLoader()));
+
+ return builder.build();
+ }
+
+ @Override
+ public AngleOfArrivalMeasurement[] newArray(int size) {
+ return new AngleOfArrivalMeasurement[size];
+ }
+ };
+
+ /**
* Builder class for {@link AngleOfArrivalMeasurement}.
*/
public static final class Builder {
diff --git a/core/java/android/uwb/DistanceMeasurement.java b/core/java/android/uwb/DistanceMeasurement.java
index 4cd5d83..c959840 100644
--- a/core/java/android/uwb/DistanceMeasurement.java
+++ b/core/java/android/uwb/DistanceMeasurement.java
@@ -17,6 +17,11 @@
package android.uwb;
import android.annotation.FloatRange;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
/**
* A data point for the distance measurement
@@ -26,7 +31,7 @@
*
* @hide
*/
-public final class DistanceMeasurement {
+public final class DistanceMeasurement implements Parcelable {
private final double mMeters;
private final double mErrorMeters;
private final double mConfidenceLevel;
@@ -70,6 +75,61 @@
}
/**
+ * @hide
+ */
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof DistanceMeasurement) {
+ DistanceMeasurement other = (DistanceMeasurement) obj;
+ return mMeters == other.getMeters()
+ && mErrorMeters == other.getErrorMeters()
+ && mConfidenceLevel == other.getConfidenceLevel();
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(mMeters, mErrorMeters, mConfidenceLevel);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeDouble(mMeters);
+ dest.writeDouble(mErrorMeters);
+ dest.writeDouble(mConfidenceLevel);
+ }
+
+ public static final @android.annotation.NonNull Creator<DistanceMeasurement> CREATOR =
+ new Creator<DistanceMeasurement>() {
+ @Override
+ public DistanceMeasurement createFromParcel(Parcel in) {
+ Builder builder = new Builder();
+ builder.setMeters(in.readDouble());
+ builder.setErrorMeters(in.readDouble());
+ builder.setConfidenceLevel(in.readDouble());
+ return builder.build();
+ }
+
+ @Override
+ public DistanceMeasurement[] newArray(int size) {
+ return new DistanceMeasurement[size];
+ }
+ };
+
+ /**
* Builder to get a {@link DistanceMeasurement} object.
*/
public static final class Builder {
diff --git a/core/java/android/uwb/RangingMeasurement.java b/core/java/android/uwb/RangingMeasurement.java
index 33a34e3..f1c3162 100644
--- a/core/java/android/uwb/RangingMeasurement.java
+++ b/core/java/android/uwb/RangingMeasurement.java
@@ -20,17 +20,20 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.SystemClock;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
/**
* Representation of a ranging measurement between the local device and a remote device
*
* @hide
*/
-public final class RangingMeasurement {
+public final class RangingMeasurement implements Parcelable {
private final UwbAddress mRemoteDeviceAddress;
private final @Status int mStatus;
private final long mElapsedRealtimeNanos;
@@ -128,6 +131,71 @@
}
/**
+ * @hide
+ */
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof RangingMeasurement) {
+ RangingMeasurement other = (RangingMeasurement) obj;
+ return mRemoteDeviceAddress.equals(other.getRemoteDeviceAddress())
+ && mStatus == other.getStatus()
+ && mElapsedRealtimeNanos == other.getElapsedRealtimeNanos()
+ && mDistanceMeasurement.equals(other.getDistance())
+ && mAngleOfArrivalMeasurement.equals(other.getAngleOfArrival());
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(mRemoteDeviceAddress, mStatus, mElapsedRealtimeNanos,
+ mDistanceMeasurement, mAngleOfArrivalMeasurement);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mRemoteDeviceAddress, flags);
+ dest.writeInt(mStatus);
+ dest.writeLong(mElapsedRealtimeNanos);
+ dest.writeParcelable(mDistanceMeasurement, flags);
+ dest.writeParcelable(mAngleOfArrivalMeasurement, flags);
+ }
+
+ public static final @android.annotation.NonNull Creator<RangingMeasurement> CREATOR =
+ new Creator<RangingMeasurement>() {
+ @Override
+ public RangingMeasurement createFromParcel(Parcel in) {
+ Builder builder = new Builder();
+ builder.setRemoteDeviceAddress(
+ in.readParcelable(UwbAddress.class.getClassLoader()));
+ builder.setStatus(in.readInt());
+ builder.setElapsedRealtimeNanos(in.readLong());
+ builder.setDistanceMeasurement(
+ in.readParcelable(DistanceMeasurement.class.getClassLoader()));
+ builder.setAngleOfArrivalMeasurement(
+ in.readParcelable(AngleOfArrivalMeasurement.class.getClassLoader()));
+ return builder.build();
+ }
+
+ @Override
+ public RangingMeasurement[] newArray(int size) {
+ return new RangingMeasurement[size];
+ }
+ };
+
+ /**
* Builder for a {@link RangingMeasurement} object.
*/
public static final class Builder {
diff --git a/core/java/android/uwb/RangingParams.java b/core/java/android/uwb/RangingParams.java
index a50de3e6..f23d9ed 100644
--- a/core/java/android/uwb/RangingParams.java
+++ b/core/java/android/uwb/RangingParams.java
@@ -19,15 +19,18 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.PersistableBundle;
-import android.util.Duration;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
/**
@@ -36,7 +39,7 @@
*
* @hide
*/
-public final class RangingParams {
+public final class RangingParams implements Parcelable {
private final boolean mIsInitiator;
private final boolean mIsController;
private final Duration mSamplePeriod;
@@ -200,6 +203,99 @@
}
/**
+ * @hide
+ */
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof RangingParams) {
+ RangingParams other = (RangingParams) obj;
+
+ return mIsInitiator == other.mIsInitiator
+ && mIsController == other.mIsController
+ && mSamplePeriod.equals(other.mSamplePeriod)
+ && mLocalDeviceAddress.equals(other.mLocalDeviceAddress)
+ && mRemoteDeviceAddresses.equals(other.mRemoteDeviceAddresses)
+ && mChannelNumber == other.mChannelNumber
+ && mTransmitPreambleCodeIndex == other.mTransmitPreambleCodeIndex
+ && mReceivePreambleCodeIndex == other.mReceivePreambleCodeIndex
+ && mStsPhyPacketType == other.mStsPhyPacketType
+ && mSpecificationParameters.size() == other.mSpecificationParameters.size()
+ && mSpecificationParameters.kindofEquals(other.mSpecificationParameters);
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(mIsInitiator, mIsController, mSamplePeriod, mLocalDeviceAddress,
+ mRemoteDeviceAddresses, mChannelNumber, mTransmitPreambleCodeIndex,
+ mReceivePreambleCodeIndex, mStsPhyPacketType, mSpecificationParameters);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeBoolean(mIsInitiator);
+ dest.writeBoolean(mIsController);
+ dest.writeLong(mSamplePeriod.getSeconds());
+ dest.writeInt(mSamplePeriod.getNano());
+ dest.writeParcelable(mLocalDeviceAddress, flags);
+
+ UwbAddress[] remoteAddresses = new UwbAddress[mRemoteDeviceAddresses.size()];
+ mRemoteDeviceAddresses.toArray(remoteAddresses);
+ dest.writeParcelableArray(remoteAddresses, flags);
+
+ dest.writeInt(mChannelNumber);
+ dest.writeInt(mTransmitPreambleCodeIndex);
+ dest.writeInt(mReceivePreambleCodeIndex);
+ dest.writeInt(mStsPhyPacketType);
+ dest.writePersistableBundle(mSpecificationParameters);
+ }
+
+ public static final @android.annotation.NonNull Creator<RangingParams> CREATOR =
+ new Creator<RangingParams>() {
+ @Override
+ public RangingParams createFromParcel(Parcel in) {
+ Builder builder = new Builder();
+ builder.setIsInitiator(in.readBoolean());
+ builder.setIsController(in.readBoolean());
+ builder.setSamplePeriod(Duration.ofSeconds(in.readLong(), in.readInt()));
+ builder.setLocalDeviceAddress(
+ in.readParcelable(UwbAddress.class.getClassLoader()));
+
+ UwbAddress[] remoteAddresses =
+ in.readParcelableArray(null, UwbAddress.class);
+ for (UwbAddress remoteAddress : remoteAddresses) {
+ builder.addRemoteDeviceAddress(remoteAddress);
+ }
+
+ builder.setChannelNumber(in.readInt());
+ builder.setTransmitPreambleCodeIndex(in.readInt());
+ builder.setReceivePreambleCodeIndex(in.readInt());
+ builder.setStsPhPacketType(in.readInt());
+ builder.setSpecificationParameters(in.readPersistableBundle());
+
+ return builder.build();
+ }
+
+ @Override
+ public RangingParams[] newArray(int size) {
+ return new RangingParams[size];
+ }
+ };
+
+ /**
* Builder class for {@link RangingParams}.
*/
public static final class Builder {
diff --git a/core/java/android/uwb/RangingReport.java b/core/java/android/uwb/RangingReport.java
index 5aca12a..45180bf 100644
--- a/core/java/android/uwb/RangingReport.java
+++ b/core/java/android/uwb/RangingReport.java
@@ -17,16 +17,20 @@
package android.uwb;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* This class contains the UWB ranging data
*
* @hide
*/
-public final class RangingReport {
+public final class RangingReport implements Parcelable {
private final List<RangingMeasurement> mRangingMeasurements;
private RangingReport(@NonNull List<RangingMeasurement> rangingMeasurements) {
@@ -49,6 +53,56 @@
}
/**
+ * @hide
+ */
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof RangingReport) {
+ RangingReport other = (RangingReport) obj;
+ return mRangingMeasurements.equals(other.getMeasurements());
+ }
+
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(mRangingMeasurements);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeTypedList(mRangingMeasurements);
+ }
+
+ public static final @android.annotation.NonNull Creator<RangingReport> CREATOR =
+ new Creator<RangingReport>() {
+ @Override
+ public RangingReport createFromParcel(Parcel in) {
+ Builder builder = new Builder();
+ builder.addMeasurements(in.createTypedArrayList(RangingMeasurement.CREATOR));
+ return builder.build();
+ }
+
+ @Override
+ public RangingReport[] newArray(int size) {
+ return new RangingReport[size];
+ }
+ };
+
+ /**
* Builder for {@link RangingReport} object
*/
public static final class Builder {
diff --git a/core/java/android/uwb/TEST_MAPPING b/core/java/android/uwb/TEST_MAPPING
new file mode 100644
index 0000000..9e50bd6
--- /dev/null
+++ b/core/java/android/uwb/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "UwbManagerTests"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/core/java/android/uwb/UwbAddress.java b/core/java/android/uwb/UwbAddress.java
index 48fcb10e..828324c 100644
--- a/core/java/android/uwb/UwbAddress.java
+++ b/core/java/android/uwb/UwbAddress.java
@@ -18,16 +18,26 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
/**
* A class representing a UWB address
*
* @hide
*/
-public final class UwbAddress {
+public final class UwbAddress implements Parcelable {
public static final int SHORT_ADDRESS_BYTE_LENGTH = 2;
public static final int EXTENDED_ADDRESS_BYTE_LENGTH = 8;
+ private final byte[] mAddressBytes;
+
+ private UwbAddress(byte[] address) {
+ mAddressBytes = address;
+ }
+
/**
* Create a {@link UwbAddress} from a byte array.
*
@@ -37,12 +47,16 @@
*
* @param address a byte array to convert to a {@link UwbAddress}
* @return a {@link UwbAddress} created from the input byte array
- * @throw IllegableArumentException when the length is not one of
+ * @throws IllegalArgumentException when the length is not one of
* {@link #SHORT_ADDRESS_BYTE_LENGTH} or {@link #EXTENDED_ADDRESS_BYTE_LENGTH} bytes
*/
@NonNull
- public static UwbAddress fromBytes(byte[] address) throws IllegalArgumentException {
- throw new UnsupportedOperationException();
+ public static UwbAddress fromBytes(@NonNull byte[] address) throws IllegalArgumentException {
+ if (address.length != SHORT_ADDRESS_BYTE_LENGTH
+ && address.length != EXTENDED_ADDRESS_BYTE_LENGTH) {
+ throw new IllegalArgumentException("Invalid UwbAddress length " + address.length);
+ }
+ return new UwbAddress(address);
}
/**
@@ -52,7 +66,7 @@
*/
@NonNull
public byte[] toBytes() {
- throw new UnsupportedOperationException();
+ return mAddressBytes;
}
/**
@@ -61,22 +75,55 @@
* {@link #EXTENDED_ADDRESS_BYTE_LENGTH}.
*/
public int size() {
- throw new UnsupportedOperationException();
+ return mAddressBytes.length;
}
@NonNull
@Override
public String toString() {
- throw new UnsupportedOperationException();
+ StringBuilder builder = new StringBuilder("0x");
+ for (byte addressByte : mAddressBytes) {
+ builder.append(String.format("%02X", addressByte));
+ }
+ return builder.toString();
}
@Override
public boolean equals(@Nullable Object obj) {
- throw new UnsupportedOperationException();
+ if (obj instanceof UwbAddress) {
+ return Arrays.equals(mAddressBytes, ((UwbAddress) obj).toBytes());
+ }
+ return false;
}
@Override
public int hashCode() {
- throw new UnsupportedOperationException();
+ return Arrays.hashCode(mAddressBytes);
}
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mAddressBytes.length);
+ dest.writeByteArray(mAddressBytes);
+ }
+
+ public static final @android.annotation.NonNull Creator<UwbAddress> CREATOR =
+ new Creator<UwbAddress>() {
+ @Override
+ public UwbAddress createFromParcel(Parcel in) {
+ byte[] address = new byte[in.readInt()];
+ in.readByteArray(address);
+ return UwbAddress.fromBytes(address);
+ }
+
+ @Override
+ public UwbAddress[] newArray(int size) {
+ return new UwbAddress[size];
+ }
+ };
}
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index 5780d4f..f4d5a7b 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -16,6 +16,7 @@
package android.view;
+import static android.os.Trace.TRACE_TAG_VIEW;
import static android.view.ImeInsetsSourceConsumerProto.INSETS_SOURCE_CONSUMER;
import static android.view.ImeInsetsSourceConsumerProto.IS_REQUESTED_VISIBLE_AWAITING_CONTROL;
import static android.view.InsetsController.AnimationType;
@@ -24,6 +25,7 @@
import android.annotation.Nullable;
import android.inputmethodservice.InputMethodService;
import android.os.IBinder;
+import android.os.Trace;
import android.util.proto.ProtoOutputStream;
import android.view.SurfaceControl.Transaction;
import android.view.inputmethod.InputMethodManager;
@@ -105,6 +107,7 @@
@Override
void notifyHidden() {
getImm().notifyImeHidden(mController.getHost().getWindowToken());
+ Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.hideRequestFromApi", 0);
}
@Override
diff --git a/core/java/android/view/InputApplicationHandle.java b/core/java/android/view/InputApplicationHandle.java
index 108345e..4abffde 100644
--- a/core/java/android/view/InputApplicationHandle.java
+++ b/core/java/android/view/InputApplicationHandle.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.NonNull;
import android.os.IBinder;
/**
@@ -31,17 +32,20 @@
private long ptr;
// Application name.
- public String name;
+ public final @NonNull String name;
// Dispatching timeout.
- public long dispatchingTimeoutMillis;
+ public final long dispatchingTimeoutMillis;
- public final IBinder token;
+ public final @NonNull IBinder token;
private native void nativeDispose();
- public InputApplicationHandle(IBinder token) {
+ public InputApplicationHandle(@NonNull IBinder token, @NonNull String name,
+ long dispatchingTimeoutMillis) {
this.token = token;
+ this.name = name;
+ this.dispatchingTimeoutMillis = dispatchingTimeoutMillis;
}
public InputApplicationHandle(InputApplicationHandle handle) {
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index d1a9a05..5a34a92 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -37,7 +37,7 @@
private long ptr;
// The input application handle.
- public final InputApplicationHandle inputApplicationHandle;
+ public InputApplicationHandle inputApplicationHandle;
// The token associates input data with a window and its input channel. The client input
// channel and the server input channel will both contain this token.
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index b5bf084..fbee833 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -16,6 +16,7 @@
package android.view;
+import static android.os.Trace.TRACE_TAG_VIEW;
import static android.view.InsetsControllerProto.CONTROL;
import static android.view.InsetsControllerProto.STATE;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
@@ -829,6 +830,11 @@
public void show(@InsetsType int types, boolean fromIme) {
if (fromIme) {
ImeTracing.getInstance().triggerDump();
+ Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromApiToImeReady", 0);
+ Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.showRequestFromIme", 0);
+ } else {
+ Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.showRequestFromApi", 0);
+ Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.showRequestFromApiToImeReady", 0);
}
// Handle pending request ready in case there was one set.
if (fromIme && mPendingImeControlRequest != null) {
@@ -880,6 +886,9 @@
void hide(@InsetsType int types, boolean fromIme) {
if (fromIme) {
ImeTracing.getInstance().triggerDump();
+ Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.hideRequestFromIme", 0);
+ } else {
+ Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.hideRequestFromApi", 0);
}
int typesReady = 0;
final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
@@ -989,6 +998,7 @@
});
}
updateRequestedVisibility();
+ Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromApi", 0);
return;
}
@@ -1014,11 +1024,13 @@
cancellationSignal.setOnCancelListener(() -> {
cancelAnimation(runner, true /* invokeCallback */);
});
+ } else {
+ Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.pendingAnim", 0);
}
if (layoutInsetsDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN) {
- showDirectly(types);
+ showDirectly(types, fromIme);
} else {
- hideDirectly(types, false /* animationFinished */, animationType);
+ hideDirectly(types, false /* animationFinished */, animationType, fromIme);
}
updateRequestedVisibility();
}
@@ -1141,10 +1153,10 @@
cancelAnimation(runner, false /* invokeCallback */);
if (DEBUG) Log.d(TAG, "notifyFinished. shown: " + shown);
if (shown) {
- showDirectly(runner.getTypes());
+ showDirectly(runner.getTypes(), true /* fromIme */);
} else {
hideDirectly(runner.getTypes(), true /* animationFinished */,
- runner.getAnimationType());
+ runner.getAnimationType(), true /* fromIme */);
}
}
@@ -1314,11 +1326,11 @@
show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
!hasAnimationCallbacks /* useInsetsAnimationThread */);
-
}
private void hideDirectly(
- @InsetsType int types, boolean animationFinished, @AnimationType int animationType) {
+ @InsetsType int types, boolean animationFinished, @AnimationType int animationType,
+ boolean fromIme) {
if ((types & ime()) != 0) {
ImeTracing.getInstance().triggerDump();
}
@@ -1327,9 +1339,13 @@
getSourceConsumer(internalTypes.valueAt(i)).hide(animationFinished, animationType);
}
updateRequestedVisibility();
+
+ if (fromIme) {
+ Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.hideRequestFromIme", 0);
+ }
}
- private void showDirectly(@InsetsType int types) {
+ private void showDirectly(@InsetsType int types, boolean fromIme) {
if ((types & ime()) != 0) {
ImeTracing.getInstance().triggerDump();
}
@@ -1338,6 +1354,10 @@
getSourceConsumer(internalTypes.valueAt(i)).show(false /* fromIme */);
}
updateRequestedVisibility();
+
+ if (fromIme) {
+ Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromIme", 0);
+ }
}
/**
@@ -1374,7 +1394,7 @@
if (WARN) Log.w(TAG, "startAnimation canceled before preDraw");
return;
}
- Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW,
+ Trace.asyncTraceBegin(TRACE_TAG_VIEW,
"InsetsAnimation: " + WindowInsets.Type.toString(types), types);
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
RunningAnimation runningAnimation = mRunningAnimations.get(i);
@@ -1382,6 +1402,7 @@
runningAnimation.startDispatched = true;
}
}
+ Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.pendingAnim", 0);
mHost.dispatchWindowInsetsAnimationStart(animation, bounds);
mStartingAnimation = true;
controller.mReadyDispatched = true;
@@ -1392,7 +1413,7 @@
@VisibleForTesting
public void dispatchAnimationEnd(WindowInsetsAnimation animation) {
- Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW,
+ Trace.asyncTraceEnd(TRACE_TAG_VIEW,
"InsetsAnimation: " + WindowInsets.Type.toString(animation.getTypeMask()),
animation.getTypeMask());
mHost.dispatchWindowInsetsAnimationEnd(animation);
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index d37edaa..af31b81 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -548,6 +548,12 @@
public static final int METADATA_ACCESSIBILITY_ID = 5;
/**
+ * owner PID.
+ * @hide
+ */
+ public static final int METADATA_OWNER_PID = 6;
+
+ /**
* A wrapper around HardwareBuffer that contains extra information about how to
* interpret the screenshot HardwareBuffer.
*
diff --git a/core/java/android/view/VerifiedKeyEvent.java b/core/java/android/view/VerifiedKeyEvent.java
index dc5b7cc..77a7d09 100644
--- a/core/java/android/view/VerifiedKeyEvent.java
+++ b/core/java/android/view/VerifiedKeyEvent.java
@@ -137,11 +137,10 @@
// 3. add the "super" call for constructor that receives a Parcel
// 4. add the "super" call to the writeToParcel method
// 5. Update "equals" and "hashcode" methods to include VerifiedInputEvent fields
- // 6. Edit "inputSignatures" to ensure KeyEventAction is properly qualified
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -180,14 +179,13 @@
* this is the number of down/up pairs that have occurred.
* @hide
*/
- @DataClass.Generated.Member
public VerifiedKeyEvent(
int deviceId,
long eventTimeNanos,
int source,
int displayId,
@KeyEventAction int action,
- @SuppressLint({"MethodNameUnits"}) long downTimeNanos,
+ @SuppressLint({ "MethodNameUnits" }) long downTimeNanos,
int flags,
int keyCode,
int scanCode,
@@ -198,16 +196,11 @@
com.android.internal.util.AnnotationValidations.validate(
KeyEventAction.class, null, mAction);
this.mDownTimeNanos = downTimeNanos;
- com.android.internal.util.AnnotationValidations.validate(
- SuppressLint.class, null, mDownTimeNanos,
- "value", "MethodNameUnits");
this.mFlags = flags;
this.mKeyCode = keyCode;
this.mScanCode = scanCode;
this.mMetaState = metaState;
this.mRepeatCount = repeatCount;
-
- // onConstructed(); // You can define this method to get a callback
}
/**
@@ -229,7 +222,7 @@
* @see KeyEvent#getDownTime()
*/
@DataClass.Generated.Member
- public @SuppressLint({"MethodNameUnits"}) long getDownTimeNanos() {
+ public @SuppressLint({ "MethodNameUnits" }) long getDownTimeNanos() {
return mDownTimeNanos;
}
@@ -301,10 +294,7 @@
VerifiedKeyEvent that = (VerifiedKeyEvent) o;
//noinspection PointlessBooleanExpression
return true
- && getDeviceId() == that.getDeviceId()
- && getEventTimeNanos() == that.getEventTimeNanos()
- && getSource() == that.getSource()
- && getDisplayId() == that.getDisplayId()
+ && super.equals(that)
&& mAction == that.mAction
&& mDownTimeNanos == that.mDownTimeNanos
&& mFlags == that.mFlags
@@ -321,10 +311,7 @@
// int fieldNameHashCode() { ... }
int _hash = 1;
- _hash = 31 * _hash + getDeviceId();
- _hash = 31 * _hash + Long.hashCode(getEventTimeNanos());
- _hash = 31 * _hash + getSource();
- _hash = 31 * _hash + getDisplayId();
+ _hash = 31 * _hash + super.hashCode();
_hash = 31 * _hash + mAction;
_hash = 31 * _hash + Long.hashCode(mDownTimeNanos);
_hash = 31 * _hash + mFlags;
@@ -341,6 +328,7 @@
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
super.writeToParcel(dest, flags);
+
dest.writeInt(mAction);
dest.writeLong(mDownTimeNanos);
dest.writeInt(mFlags);
@@ -361,6 +349,7 @@
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
super(in, VERIFIED_KEY);
+
int action = in.readInt();
long downTimeNanos = in.readLong();
int flags = in.readInt();
@@ -373,9 +362,6 @@
com.android.internal.util.AnnotationValidations.validate(
KeyEventAction.class, null, mAction);
this.mDownTimeNanos = downTimeNanos;
- com.android.internal.util.AnnotationValidations.validate(
- SuppressLint.class, null, mDownTimeNanos,
- "value", "MethodNameUnits");
this.mFlags = flags;
this.mKeyCode = keyCode;
this.mScanCode = scanCode;
@@ -400,10 +386,10 @@
};
@DataClass.Generated(
- time = 1581107066890L,
- codegenVersion = "1.0.14",
+ time = 1604509197793L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/core/java/android/view/VerifiedKeyEvent.java",
- inputSignatures = "private static final java.lang.String TAG\nprivate @android.view.VerifiedKeyEvent.KeyEventAction int mAction\nprivate @android.annotation.SuppressLint({\"MethodNameUnits\"}) long mDownTimeNanos\nprivate int mFlags\nprivate int mKeyCode\nprivate int mScanCode\nprivate int mMetaState\nprivate int mRepeatCount\npublic @android.annotation.Nullable java.lang.Boolean getFlag(int)\nclass VerifiedKeyEvent extends android.view.VerifiedInputEvent implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genEqualsHashCode=true)")
+ inputSignatures = "private static final java.lang.String TAG\nprivate @android.view.VerifiedKeyEvent.KeyEventAction int mAction\nprivate @android.annotation.SuppressLint long mDownTimeNanos\nprivate int mFlags\nprivate int mKeyCode\nprivate int mScanCode\nprivate int mMetaState\nprivate int mRepeatCount\npublic @android.annotation.Nullable java.lang.Boolean getFlag(int)\nclass VerifiedKeyEvent extends android.view.VerifiedInputEvent implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/view/VerifiedMotionEvent.java b/core/java/android/view/VerifiedMotionEvent.java
index b4c5d24..7d83459 100644
--- a/core/java/android/view/VerifiedMotionEvent.java
+++ b/core/java/android/view/VerifiedMotionEvent.java
@@ -131,11 +131,10 @@
// 3. add the "super" call for constructor that receives a Parcel
// 4. add the "super" call to the writeToParcel method
// 5. Update "equals" and "hashcode" methods to include VerifiedInputEvent fields
- // 6. Edit "inputSignatures" to ensure MotionEventAction is properly qualified
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -174,7 +173,7 @@
float rawX,
float rawY,
@MotionEventAction int actionMasked,
- @SuppressLint({"MethodNameUnits"}) long downTimeNanos,
+ @SuppressLint({ "MethodNameUnits" }) long downTimeNanos,
int flags,
int metaState,
int buttonState) {
@@ -185,9 +184,6 @@
com.android.internal.util.AnnotationValidations.validate(
MotionEventAction.class, null, mActionMasked);
this.mDownTimeNanos = downTimeNanos;
- com.android.internal.util.AnnotationValidations.validate(
- SuppressLint.class, null, mDownTimeNanos,
- "value", "MethodNameUnits");
this.mFlags = flags;
this.mMetaState = metaState;
this.mButtonState = buttonState;
@@ -232,7 +228,7 @@
* @see MotionEvent#getDownTime()
*/
@DataClass.Generated.Member
- public @SuppressLint({"MethodNameUnits"}) long getDownTimeNanos() {
+ public @SuppressLint({ "MethodNameUnits" }) long getDownTimeNanos() {
return mDownTimeNanos;
}
@@ -280,10 +276,7 @@
VerifiedMotionEvent that = (VerifiedMotionEvent) o;
//noinspection PointlessBooleanExpression
return true
- && getDeviceId() == that.getDeviceId()
- && getEventTimeNanos() == that.getEventTimeNanos()
- && getSource() == that.getSource()
- && getDisplayId() == that.getDisplayId()
+ && super.equals(that)
&& mRawX == that.mRawX
&& mRawY == that.mRawY
&& mActionMasked == that.mActionMasked
@@ -300,10 +293,7 @@
// int fieldNameHashCode() { ... }
int _hash = 1;
- _hash = 31 * _hash + getDeviceId();
- _hash = 31 * _hash + Long.hashCode(getEventTimeNanos());
- _hash = 31 * _hash + getSource();
- _hash = 31 * _hash + getDisplayId();
+ _hash = 31 * _hash + super.hashCode();
_hash = 31 * _hash + Float.hashCode(mRawX);
_hash = 31 * _hash + Float.hashCode(mRawY);
_hash = 31 * _hash + mActionMasked;
@@ -320,6 +310,7 @@
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
super.writeToParcel(dest, flags);
+
dest.writeFloat(mRawX);
dest.writeFloat(mRawY);
dest.writeInt(mActionMasked);
@@ -340,6 +331,7 @@
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
super(in, VERIFIED_MOTION);
+
float rawX = in.readFloat();
float rawY = in.readFloat();
int actionMasked = in.readInt();
@@ -354,9 +346,6 @@
com.android.internal.util.AnnotationValidations.validate(
MotionEventAction.class, null, mActionMasked);
this.mDownTimeNanos = downTimeNanos;
- com.android.internal.util.AnnotationValidations.validate(
- SuppressLint.class, null, mDownTimeNanos,
- "value", "MethodNameUnits");
this.mFlags = flags;
this.mMetaState = metaState;
this.mButtonState = buttonState;
@@ -379,10 +368,10 @@
};
@DataClass.Generated(
- time = 1581107073238L,
- codegenVersion = "1.0.14",
+ time = 1604509199368L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/core/java/android/view/VerifiedMotionEvent.java",
- inputSignatures = "private static final java.lang.String TAG\nprivate float mRawX\nprivate float mRawY\nprivate @android.view.VerifiedMotionEvent.MotionEventAction int mActionMasked\nprivate @android.annotation.SuppressLint({\"MethodNameUnits\"}) long mDownTimeNanos\nprivate int mFlags\nprivate int mMetaState\nprivate int mButtonState\npublic @android.annotation.Nullable java.lang.Boolean getFlag(int)\nclass VerifiedMotionEvent extends android.view.VerifiedInputEvent implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genEqualsHashCode=true)")
+ inputSignatures = "private static final java.lang.String TAG\nprivate float mRawX\nprivate float mRawY\nprivate @android.view.VerifiedMotionEvent.MotionEventAction int mActionMasked\nprivate @android.annotation.SuppressLint long mDownTimeNanos\nprivate int mFlags\nprivate int mMetaState\nprivate int mButtonState\npublic @android.annotation.Nullable java.lang.Boolean getFlag(int)\nclass VerifiedMotionEvent extends android.view.VerifiedInputEvent implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 0e8cd54..9d24dff1 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1890,8 +1890,10 @@
mSurface.release();
mSurfaceControl.release();
- // We should probably add an explicit dispose.
- mBlastBufferQueue = null;
+ if (mBlastBufferQueue != null) {
+ mBlastBufferQueue.destroy();
+ mBlastBufferQueue = null;
+ }
}
/**
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index f7578ab..b4a841f 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -17,6 +17,27 @@
package android.view;
import static android.content.pm.ActivityInfo.COLOR_MODE_DEFAULT;
+import static android.view.View.STATUS_BAR_DISABLE_BACK;
+import static android.view.View.STATUS_BAR_DISABLE_CLOCK;
+import static android.view.View.STATUS_BAR_DISABLE_EXPAND;
+import static android.view.View.STATUS_BAR_DISABLE_HOME;
+import static android.view.View.STATUS_BAR_DISABLE_NOTIFICATION_ALERTS;
+import static android.view.View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS;
+import static android.view.View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER;
+import static android.view.View.STATUS_BAR_DISABLE_RECENT;
+import static android.view.View.STATUS_BAR_DISABLE_SEARCH;
+import static android.view.View.STATUS_BAR_DISABLE_SYSTEM_INFO;
+import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
+import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE;
+import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
+import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
+import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE;
+import static android.view.View.SYSTEM_UI_FLAG_VISIBLE;
import static android.view.WindowInsets.Side.BOTTOM;
import static android.view.WindowInsets.Side.LEFT;
import static android.view.WindowInsets.Side.RIGHT;
@@ -2725,6 +2746,38 @@
public int preferredDisplayModeId;
/**
+ * An internal annotation for flags that can be specified to {@link #systemUiVisibility}
+ * and {@link #subtreeSystemUiVisibility}.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "" }, value = {
+ SYSTEM_UI_FLAG_VISIBLE,
+ SYSTEM_UI_FLAG_LOW_PROFILE,
+ SYSTEM_UI_FLAG_HIDE_NAVIGATION,
+ SYSTEM_UI_FLAG_FULLSCREEN,
+ SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
+ SYSTEM_UI_FLAG_LAYOUT_STABLE,
+ SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION,
+ SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN,
+ SYSTEM_UI_FLAG_IMMERSIVE,
+ SYSTEM_UI_FLAG_IMMERSIVE_STICKY,
+ SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,
+ STATUS_BAR_DISABLE_EXPAND,
+ STATUS_BAR_DISABLE_NOTIFICATION_ICONS,
+ STATUS_BAR_DISABLE_NOTIFICATION_ALERTS,
+ STATUS_BAR_DISABLE_NOTIFICATION_TICKER,
+ STATUS_BAR_DISABLE_SYSTEM_INFO,
+ STATUS_BAR_DISABLE_HOME,
+ STATUS_BAR_DISABLE_BACK,
+ STATUS_BAR_DISABLE_CLOCK,
+ STATUS_BAR_DISABLE_RECENT,
+ STATUS_BAR_DISABLE_SEARCH,
+ })
+ public @interface SystemUiVisibilityFlags {}
+
+ /**
* Control the visibility of the status bar.
*
* @see View#STATUS_BAR_VISIBLE
@@ -2733,6 +2786,7 @@
* @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController}
* instead.
*/
+ @SystemUiVisibilityFlags
@Deprecated
public int systemUiVisibility;
@@ -2741,6 +2795,7 @@
* The ui visibility as requested by the views in this hierarchy.
* the combined value should be systemUiVisibility | subtreeSystemUiVisibility.
*/
+ @SystemUiVisibilityFlags
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public int subtreeSystemUiVisibility;
@@ -2754,7 +2809,6 @@
@UnsupportedAppUsage
public boolean hasSystemUiListeners;
-
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(
@@ -2921,6 +2975,19 @@
public static final int INPUT_FEATURE_DISABLE_USER_ACTIVITY = 0x00000004;
/**
+ * An internal annotation for flags that can be specified to {@link #inputFeatures}.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "INPUT_FEATURE_" }, value = {
+ INPUT_FEATURE_DISABLE_POINTER_GESTURES,
+ INPUT_FEATURE_NO_INPUT_CHANNEL,
+ INPUT_FEATURE_DISABLE_USER_ACTIVITY,
+ })
+ public @interface InputFeatureFlags {}
+
+ /**
* Control special features of the input subsystem.
*
* @see #INPUT_FEATURE_DISABLE_POINTER_GESTURES
@@ -2928,6 +2995,7 @@
* @see #INPUT_FEATURE_DISABLE_USER_ACTIVITY
* @hide
*/
+ @InputFeatureFlags
@UnsupportedAppUsage
public int inputFeatures;
diff --git a/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl b/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl
index 2343bf3..d0ab004 100644
--- a/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl
+++ b/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl
@@ -50,4 +50,14 @@
* @param sourceBounds The magnified bounds in screen coordinates.
*/
void onSourceBoundsChanged(int displayId, in Rect sourceBounds);
+
+ /**
+ * Called when the accessibility action of scale requests to be performed.
+ * It is invoked from System UI. And the action is provided by the mirror window.
+ *
+ * @param displayId The logical display id.
+ * @param scale the target scale, or {@link Float#NaN} to leave unchanged
+ */
+ void onPerformScaleAction(int displayId, float scale);
+
}
diff --git a/core/java/android/view/inputmethod/InlineSuggestionInfo.java b/core/java/android/view/inputmethod/InlineSuggestionInfo.java
index 1c703ec..73962d7 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionInfo.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionInfo.java
@@ -88,7 +88,7 @@
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -346,10 +346,10 @@
};
@DataClass.Generated(
- time = 1586992414034L,
- codegenVersion = "1.0.15",
+ time = 1604456249219L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionInfo.java",
- inputSignatures = "public static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_AUTOFILL\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_PLATFORM\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_SUGGESTION\npublic static final @android.annotation.SuppressLint({\"IntentName\"}) @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_ACTION\nprivate final @android.annotation.NonNull android.widget.inline.InlinePresentationSpec mInlinePresentationSpec\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String mSource\nprivate final @android.annotation.Nullable java.lang.String[] mAutofillHints\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String mType\nprivate final boolean mPinned\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(android.widget.inline.InlinePresentationSpec,java.lang.String,java.lang.String[],java.lang.String,boolean)\nclass InlineSuggestionInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)")
+ inputSignatures = "public static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_AUTOFILL\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_PLATFORM\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_SUGGESTION\npublic static final @android.annotation.SuppressLint @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_ACTION\nprivate final @android.annotation.NonNull android.widget.inline.InlinePresentationSpec mInlinePresentationSpec\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String mSource\nprivate final @android.annotation.Nullable java.lang.String[] mAutofillHints\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String mType\nprivate final boolean mPinned\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(android.widget.inline.InlinePresentationSpec,java.lang.String,java.lang.String[],java.lang.String,boolean)\nclass InlineSuggestionInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/window/DisplayAreaOrganizer.java b/core/java/android/window/DisplayAreaOrganizer.java
index 6ec093e..bc3e35c 100644
--- a/core/java/android/window/DisplayAreaOrganizer.java
+++ b/core/java/android/window/DisplayAreaOrganizer.java
@@ -88,9 +88,11 @@
public static final int FEATURE_VENDOR_FIRST = FEATURE_SYSTEM_LAST + 1;
/**
- * Registers a DisplayAreaOrganizer to manage display areas for a given feature.
+ * Registers a DisplayAreaOrganizer to manage display areas for a given feature. A feature can
+ * not be registered by multiple organizers at the same time.
*
* @return a list of display areas that should be managed by the organizer.
+ * @throws IllegalStateException if the feature has already been registered.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
@CallSuper
diff --git a/core/java/android/window/IDisplayAreaOrganizerController.aidl b/core/java/android/window/IDisplayAreaOrganizerController.aidl
index 8943847..edabcf8 100644
--- a/core/java/android/window/IDisplayAreaOrganizerController.aidl
+++ b/core/java/android/window/IDisplayAreaOrganizerController.aidl
@@ -24,9 +24,11 @@
interface IDisplayAreaOrganizerController {
/**
- * Registers a DisplayAreaOrganizer to manage display areas for a given feature.
+ * Registers a DisplayAreaOrganizer to manage display areas for a given feature. A feature can
+ * not be registered by multiple organizers at the same time.
*
* @return a list of display areas that should be managed by the organizer.
+ * @throws IllegalStateException if the feature has already been registered.
*/
ParceledListSlice<DisplayAreaAppearedInfo> registerOrganizer(in IDisplayAreaOrganizer organizer,
int displayAreaFeature);
diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
index f46626b..ffc7f05 100644
--- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
+++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
@@ -144,7 +144,7 @@
int HIDE_RECENTS_ANIMATION = 18;
/**
- * Hide soft input when {@link com.android.systemui.bubbles.BubbleController} is expanding,
+ * Hide soft input when {@link com.android.wm.shell.bubbles.BubbleController} is expanding,
* switching, or collapsing Bubbles.
*/
int HIDE_BUBBLES = 19;
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index 85dc2ae..c0d46f6 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -176,7 +176,7 @@
* Trigger the prefetto daemon.
*/
public void triggerPerfetto() {
- InteractionJankMonitor.getInstance().trigger();
+ InteractionJankMonitor.getInstance().trigger(mSession);
}
/**
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 3624f0d..137430b 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -22,7 +22,12 @@
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_RECENTS;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_QUICK_SWITCH;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_EXPAND_COLLAPSE_LOCK;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_HEADS_UP_APPEAR;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_HEADS_UP_DISAPPEAR;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_NOTIFICATION_ADD;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_NOTIFICATION_REMOVE;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_QS_EXPAND_COLLAPSE;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_QS_SCROLL_SWIPE;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_ROW_EXPAND;
@@ -67,6 +72,11 @@
public static final int CUJ_LAUNCHER_APP_CLOSE_TO_HOME = 9;
public static final int CUJ_LAUNCHER_APP_CLOSE_TO_PIP = 10;
public static final int CUJ_LAUNCHER_QUICK_SWITCH = 11;
+ public static final int CUJ_NOTIFICATION_HEADS_UP_APPEAR = 12;
+ public static final int CUJ_NOTIFICATION_HEADS_UP_DISAPPEAR = 13;
+ public static final int CUJ_NOTIFICATION_ADD = 14;
+ public static final int CUJ_NOTIFICATION_REMOVE = 15;
+ public static final int CUJ_NOTIFICATION_APP_START = 16;
private static final int NO_STATSD_LOGGING = -1;
@@ -87,6 +97,11 @@
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_PIP,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_QUICK_SWITCH,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_HEADS_UP_APPEAR,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_HEADS_UP_DISAPPEAR,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_NOTIFICATION_ADD,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_NOTIFICATION_REMOVE,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH,
};
private static volatile InteractionJankMonitor sInstance;
@@ -112,6 +127,11 @@
CUJ_LAUNCHER_APP_CLOSE_TO_HOME,
CUJ_LAUNCHER_APP_CLOSE_TO_PIP,
CUJ_LAUNCHER_QUICK_SWITCH,
+ CUJ_NOTIFICATION_HEADS_UP_APPEAR,
+ CUJ_NOTIFICATION_HEADS_UP_DISAPPEAR,
+ CUJ_NOTIFICATION_ADD,
+ CUJ_NOTIFICATION_REMOVE,
+ CUJ_NOTIFICATION_APP_START,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {}
@@ -319,11 +339,11 @@
* Trigger the perfetto daemon to collect and upload data.
*/
@VisibleForTesting
- public void trigger() {
+ public void trigger(Session session) {
synchronized (this) {
if (!mInitialized) return;
mWorker.getThreadHandler().post(
- () -> PerfettoTrigger.trigger(PerfettoTrigger.TRIGGER_TYPE_JANK));
+ () -> PerfettoTrigger.trigger(session.getPerfettoTrigger()));
}
}
@@ -350,9 +370,12 @@
return getStatsdInteractionType() != NO_STATSD_LOGGING;
}
+ public String getPerfettoTrigger() {
+ return String.format("interaction-jank-monitor-%d", mCujType);
+ }
+
public String getName() {
return "Cuj<" + getCuj() + ">";
}
}
-
}
diff --git a/core/java/com/android/internal/jank/PerfettoTrigger.java b/core/java/com/android/internal/jank/PerfettoTrigger.java
index 6c8d3cd..643d24a 100644
--- a/core/java/com/android/internal/jank/PerfettoTrigger.java
+++ b/core/java/com/android/internal/jank/PerfettoTrigger.java
@@ -17,15 +17,12 @@
//TODO (165884885): Make PerfettoTrigger more generic and move it to another package.
package com.android.internal.jank;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.util.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
/**
* A trigger implementation with perfetto backend.
@@ -35,23 +32,14 @@
private static final String TAG = PerfettoTrigger.class.getSimpleName();
private static final boolean DEBUG = false;
private static final String TRIGGER_COMMAND = "/system/bin/trigger_perfetto";
- private static final String[] TRIGGER_TYPE_NAMES = new String[] { "jank-tracker" };
- public static final int TRIGGER_TYPE_JANK = 0;
-
- /** @hide */
- @IntDef({
- TRIGGER_TYPE_JANK
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface TriggerType {}
/**
- * @param type the trigger type
+ * @param triggerName The name of the trigger. Must match the value defined in the AOT
+ * Perfetto config.
*/
- public static void trigger(@NonNull @TriggerType int type) {
+ public static void trigger(String triggerName) {
try {
- Token token = new Token(type, TRIGGER_TYPE_NAMES[type]);
- ProcessBuilder pb = new ProcessBuilder(TRIGGER_COMMAND, token.getName());
+ ProcessBuilder pb = new ProcessBuilder(TRIGGER_COMMAND, triggerName);
if (DEBUG) {
StringBuilder sb = new StringBuilder();
for (String arg : pb.command()) {
@@ -64,7 +52,7 @@
readConsoleOutput(process);
}
} catch (IOException | InterruptedException e) {
- Log.w(TAG, "Failed to trigger " + type, e);
+ Log.w(TAG, "Failed to trigger " + triggerName, e);
}
}
@@ -82,34 +70,4 @@
Log.d(TAG, "err message=" + errLine.toString());
}
}
-
- /**
- * Token which is used to trigger perfetto.
- */
- public static class Token {
- private int mType;
- private String mName;
-
- Token(@TriggerType int type, String name) {
- mType = type;
- mName = name;
- }
-
- /**
- * Get trigger type.
- * @return trigger type, should be @TriggerType
- */
- public int getType() {
- return mType;
- }
-
- /**
- * Get name of this token as the argument while triggering perfetto.
- * @return name
- */
- public String getName() {
- return mName;
- }
- }
-
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 1123f20..dd1c87b 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -204,6 +204,9 @@
],
shared_libs: [
+ "audioclient-types-aidl-unstable-cpp",
+ "audioflinger-aidl-unstable-cpp",
+ "av-types-aidl-unstable-cpp",
"libandroidicu",
"libbpf_android",
"libnetdbpf",
diff --git a/core/jni/android_hardware_input_InputApplicationHandle.cpp b/core/jni/android_hardware_input_InputApplicationHandle.cpp
index 7756a62..995bfa9 100644
--- a/core/jni/android_hardware_input_InputApplicationHandle.cpp
+++ b/core/jni/android_hardware_input_InputApplicationHandle.cpp
@@ -54,26 +54,28 @@
bool NativeInputApplicationHandle::updateInfo() {
JNIEnv* env = AndroidRuntime::getJNIEnv();
- jobject obj = env->NewLocalRef(mObjWeak);
- if (!obj) {
+ ScopedLocalRef<jobject> obj(env, env->NewLocalRef(mObjWeak));
+ if (!obj.get()) {
return false;
}
+ if (mInfo.token.get() != nullptr) {
+ // The java fields are immutable, so it doesn't need to update again.
+ return true;
+ }
- mInfo.name = getStringField(env, obj, gInputApplicationHandleClassInfo.name, "<null>");
+ mInfo.name = getStringField(env, obj.get(), gInputApplicationHandleClassInfo.name, "<null>");
mInfo.dispatchingTimeoutMillis =
- env->GetLongField(obj, gInputApplicationHandleClassInfo.dispatchingTimeoutMillis);
+ env->GetLongField(obj.get(), gInputApplicationHandleClassInfo.dispatchingTimeoutMillis);
- jobject tokenObj = env->GetObjectField(obj,
- gInputApplicationHandleClassInfo.token);
- if (tokenObj) {
- mInfo.token = ibinderForJavaObject(env, tokenObj);
- env->DeleteLocalRef(tokenObj);
+ ScopedLocalRef<jobject> tokenObj(env, env->GetObjectField(obj.get(),
+ gInputApplicationHandleClassInfo.token));
+ if (tokenObj.get()) {
+ mInfo.token = ibinderForJavaObject(env, tokenObj.get());
} else {
mInfo.token.clear();
}
- env->DeleteLocalRef(obj);
return mInfo.token.get() != nullptr;
}
diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp
index cbce38e..12d8bc6 100644
--- a/core/jni/android_view_KeyCharacterMap.cpp
+++ b/core/jni/android_view_KeyCharacterMap.cpp
@@ -162,7 +162,7 @@
static jint nativeGetKeyboardType(JNIEnv *env, jobject clazz, jlong ptr) {
NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
- return map->getMap()->getKeyboardType();
+ return static_cast<jint>(map->getMap()->getKeyboardType());
}
static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jlong ptr,
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 45f64f9..d46da87 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -779,6 +779,26 @@
// CATEGORY: SETTINGS
// OS: S
ACTION_COLUMBUS_ACTION_NOTIFICATION_SHADE = 1746;
+
+ // ACTION: Settings > System > Gestures > Double tap > Require harder taps
+ // CATEGORY: SETTINGS
+ // OS: S
+ ACTION_COLUMBUS_LOW_SENSITIVITY = 1747;
+
+ // OPEN: Columbus Gesture training intro in Settings
+ // CATEGORY: SETTINGS
+ // OS: S
+ SETTINGS_COLUMBUS_GESTURE_TRAINING_INTRO = 1748;
+
+ // OPEN: Columbus Gesture training enrolling in Settings
+ // CATEGORY: SETTINGS
+ // OS: S
+ SETTINGS_COLUMBUS_GESTURE_TRAINING_ENROLLING = 1749;
+
+ // OPEN: Columbus Gesture training finished in Settings
+ // CATEGORY: SETTINGS
+ // OS: S
+ SETTINGS_COLUMBUS_GESTURE_TRAINING_FINISHED = 1750;
}
/**
diff --git a/core/proto/android/server/alarm/alarmmanagerservice.proto b/core/proto/android/server/alarm/alarmmanagerservice.proto
index e1240245..8fe1bfc 100644
--- a/core/proto/android/server/alarm/alarmmanagerservice.proto
+++ b/core/proto/android/server/alarm/alarmmanagerservice.proto
@@ -144,6 +144,8 @@
repeated IdleDispatchEntryProto allow_while_idle_dispatches = 40;
repeated WakeupEventProto recent_wakeup_history = 41;
+
+ repeated AlarmProto pending_alarms = 42;
}
// This is a soft wrapper for alarm clock information. It is not representative
diff --git a/core/proto/android/stats/tls/enums.proto b/core/proto/android/stats/tls/enums.proto
index 0ae87ee..a64137d 100644
--- a/core/proto/android/stats/tls/enums.proto
+++ b/core/proto/android/stats/tls/enums.proto
@@ -20,11 +20,11 @@
// external/conscrypt/{android,platform}/src/main/java/org/conscrypt/Platform.java
enum Protocol {
UNKNOWN_PROTO = 0;
- SSLv3 = 1;
- TLSv1 = 2;
- TLSv1_1 = 3;
- TLSv1_2 = 4;
- TLSv1_3 = 5;
+ SSL_V3 = 1;
+ TLS_V1 = 2;
+ TLS_V1_1 = 3;
+ TLS_V1_2 = 4;
+ TLS_V1_3 = 5;
}
// Cipher suites' ids are based on IANA's database:
diff --git a/core/proto/android/view/windowlayoutparams.proto b/core/proto/android/view/windowlayoutparams.proto
index 64e6da8..4bb56f8 100644
--- a/core/proto/android/view/windowlayoutparams.proto
+++ b/core/proto/android/view/windowlayoutparams.proto
@@ -35,7 +35,7 @@
optional int32 height = 5;
optional float horizontal_margin = 6;
optional float vertical_margin = 7;
- optional int32 gravity = 8; // TODO (b/160129453): Add IntDef
+ optional int32 gravity = 8;
optional int32 soft_input_mode = 9 [(.android.typedef) = "android.view.WindowManager.LayoutParams.SoftInputModeFlags"];
optional .android.graphics.PixelFormatProto.Format format = 10;
optional int32 window_animations = 11;
@@ -54,14 +54,14 @@
optional float preferred_refresh_rate = 16;
optional int32 preferred_display_mode_id = 17;
optional bool has_system_ui_listeners = 18;
- optional uint32 input_feature_flags = 19; // TODO (b/160129453): Add IntDef
+ optional uint32 input_feature_flags = 19 [(.android.typedef) = "android.view.WindowManager.LayoutParams.InputFeatureFlags"];
optional int64 user_activity_timeout = 20;
optional DisplayProto.ColorMode color_mode = 23;
optional uint32 flags = 24 [(.android.typedef) = "android.view.WindowManager.LayoutParams.Flags"];
optional uint32 private_flags = 26 [(.android.typedef) = "android.view.WindowManager.LayoutParams.PrivateFlags"];
- optional uint32 system_ui_visibility_flags = 27; // TODO (b/160129453): Add IntDef
- optional uint32 subtree_system_ui_visibility_flags = 28; // TODO (b/160129453): Add IntDef
+ optional uint32 system_ui_visibility_flags = 27 [(.android.typedef) = "android.view.WindowManager.LayoutParams.SystemUiVisibilityFlags"];
+ optional uint32 subtree_system_ui_visibility_flags = 28 [(.android.typedef) = "android.view.WindowManager.LayoutParams.SystemUiVisibilityFlags"];
optional uint32 appearance = 29 [(.android.typedef) = "android.view.WindowInsetsController.Appearance"];
optional uint32 behavior = 30 [(.android.typedef) = "android.view.WindowInsetsController.Behavior"];
optional uint32 fit_insets_types = 31 [(.android.typedef) = "android.view.WindowInsets.Type.InsetsType"];
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4df7d58..a778f14 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -349,7 +349,6 @@
<protected-broadcast android:name="com.android.server.WifiManager.action.START_PNO" />
<protected-broadcast android:name="com.android.server.WifiManager.action.DELAYED_DRIVER_STOP" />
<protected-broadcast android:name="com.android.server.WifiManager.action.DEVICE_IDLE" />
- <protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_DISPATCH" />
<protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_ACCEPTED" />
<protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_DECLINED" />
<protected-broadcast android:name="com.android.internal.action.EUICC_FACTORY_RESET" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index df03ccc..082397e 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -817,6 +817,30 @@
<!-- B y-intercept --> <item>-0.198650895</item>
</string-array>
+ <string-array name="config_reduceBrightColorsCoefficientsNative">
+ <!-- R a-coefficient --> <item>-0.691218457</item>
+ <!-- R b-coefficient --> <item>0.050135153</item>
+ <!-- R y-intercept --> <item>0.917684143</item>
+ <!-- G a-coefficient --> <item>-0.691218457</item>
+ <!-- G b-coefficient --> <item>0.050135153</item>
+ <!-- G y-intercept --> <item>0.917684143</item>
+ <!-- B a-coefficient --> <item>-0.691218457</item>
+ <!-- B b-coefficient --> <item>0.050135153</item>
+ <!-- B y-intercept --> <item>0.917684143</item>
+ </string-array>
+
+ <string-array name="config_reduceBrightColorsCoefficients">
+ <!-- R a-coefficient --> <item>0.00000000000000154</item>
+ <!-- R b-coefficient --> <item>-1.0</item>
+ <!-- R y-intercept --> <item>1.045977011</item>
+ <!-- G a-coefficient --> <item>0.00000000000000224</item>
+ <!-- G b-coefficient --> <item>-1.0</item>
+ <!-- G y-intercept --> <item>1.045977011</item>
+ <!-- B a-coefficient --> <item>0.0000000000000022</item>
+ <!-- B b-coefficient --> <item>-1.0</item>
+ <!-- B y-intercept --> <item>1.045977011</item>
+ </string-array>
+
<!-- Boolean indicating whether display white balance is supported. -->
<bool name="config_displayWhiteBalanceAvailable">false</bool>
@@ -1694,7 +1718,7 @@
to be explicitly declared in this resource to be enabled.
* SDK level 28 makes the following algorithms mandatory : "cbc(aes)", "hmac(md5)",
"hmac(sha1)", "hmac(sha256)", "hmac(sha384)", "hmac(sha512)", "rfc4106(gcm(aes))"
- * SDK level 30 makes the following algorithms mandatory : "rfc3686(ctr(aes))",
+ * SDK level 31 makes the following algorithms mandatory : "rfc3686(ctr(aes))",
"xcbc(aes)", "rfc7539esp(chacha20,poly1305)"
-->
<string-array name="config_optionalIpSecAlgorithms" translatable="false">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a294c9d..4e4e3f8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3158,6 +3158,8 @@
<java-symbol type="integer" name="config_nightDisplayColorTemperatureMax" />
<java-symbol type="array" name="config_nightDisplayColorTemperatureCoefficients" />
<java-symbol type="array" name="config_nightDisplayColorTemperatureCoefficientsNative" />
+ <java-symbol type="array" name="config_reduceBrightColorsCoefficients" />
+ <java-symbol type="array" name="config_reduceBrightColorsCoefficientsNative" />
<java-symbol type="array" name="config_availableColorModes" />
<java-symbol type="integer" name="config_accessibilityColorMode" />
<java-symbol type="array" name="config_displayCompositionColorModes" />
diff --git a/core/tests/coretests/src/android/os/CombinedVibrationEffectTest.java b/core/tests/coretests/src/android/os/CombinedVibrationEffectTest.java
index faa67a8..1947c6c 100644
--- a/core/tests/coretests/src/android/os/CombinedVibrationEffectTest.java
+++ b/core/tests/coretests/src/android/os/CombinedVibrationEffectTest.java
@@ -26,22 +26,135 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import java.util.Arrays;
+
@Presubmit
@RunWith(JUnit4.class)
public class CombinedVibrationEffectTest {
+ private static final VibrationEffect VALID_EFFECT = VibrationEffect.createOneShot(10, 255);
+ private static final VibrationEffect INVALID_EFFECT = new VibrationEffect.OneShot(-1, -1);
+
@Test
public void testValidateMono() {
- CombinedVibrationEffect.createSynced(VibrationEffect.get(VibrationEffect.EFFECT_CLICK));
+ CombinedVibrationEffect.createSynced(VALID_EFFECT);
assertThrows(IllegalArgumentException.class,
- () -> CombinedVibrationEffect.createSynced(new VibrationEffect.OneShot(-1, -1)));
+ () -> CombinedVibrationEffect.createSynced(INVALID_EFFECT));
+ }
+
+ @Test
+ public void testValidateStereo() {
+ CombinedVibrationEffect.startSynced()
+ .addVibrator(0, VALID_EFFECT)
+ .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_TICK))
+ .combine();
+ CombinedVibrationEffect.startSynced()
+ .addVibrator(0, INVALID_EFFECT)
+ .addVibrator(0, VALID_EFFECT)
+ .combine();
+
+ assertThrows(IllegalArgumentException.class,
+ () -> CombinedVibrationEffect.startSynced()
+ .addVibrator(0, INVALID_EFFECT)
+ .combine());
+ }
+
+ @Test
+ public void testValidateSequential() {
+ CombinedVibrationEffect.startSequential()
+ .addNext(0, VALID_EFFECT)
+ .addNext(CombinedVibrationEffect.createSynced(VALID_EFFECT))
+ .combine();
+ CombinedVibrationEffect.startSequential()
+ .addNext(0, VALID_EFFECT)
+ .addNext(0, VALID_EFFECT, 100)
+ .combine();
+ CombinedVibrationEffect.startSequential()
+ .addNext(CombinedVibrationEffect.startSequential()
+ .addNext(0, VALID_EFFECT)
+ .combine())
+ .combine();
+
+ assertThrows(IllegalArgumentException.class,
+ () -> CombinedVibrationEffect.startSequential()
+ .addNext(0, VALID_EFFECT, -1)
+ .combine());
+ assertThrows(IllegalArgumentException.class,
+ () -> CombinedVibrationEffect.startSequential()
+ .addNext(0, INVALID_EFFECT)
+ .combine());
+ assertThrows(IllegalArgumentException.class,
+ () -> new CombinedVibrationEffect.Sequential(
+ Arrays.asList(CombinedVibrationEffect.startSequential()
+ .addNext(CombinedVibrationEffect.createSynced(VALID_EFFECT))
+ .combine()),
+ Arrays.asList(0))
+ .validate());
+ }
+
+ @Test
+ public void testNestedSequentialAccumulatesDelays() {
+ CombinedVibrationEffect.Sequential combined =
+ (CombinedVibrationEffect.Sequential) CombinedVibrationEffect.startSequential()
+ .addNext(CombinedVibrationEffect.startSequential()
+ .addNext(0, VALID_EFFECT, /* delay= */ 100)
+ .addNext(1, VALID_EFFECT, /* delay= */ 100)
+ .combine(),
+ /* delay= */ 10)
+ .addNext(CombinedVibrationEffect.startSequential()
+ .addNext(0, VALID_EFFECT, /* delay= */ 100)
+ .combine())
+ .addNext(CombinedVibrationEffect.startSequential()
+ .addNext(0, VALID_EFFECT)
+ .addNext(0, VALID_EFFECT, /* delay= */ 100)
+ .combine(),
+ /* delay= */ 10)
+ .combine();
+
+ assertEquals(Arrays.asList(110, 100, 100, 10, 100), combined.getDelays());
+ }
+
+ @Test
+ public void testCombineEmptyFails() {
+ assertThrows(IllegalStateException.class,
+ () -> CombinedVibrationEffect.startSynced().combine());
+ assertThrows(IllegalStateException.class,
+ () -> CombinedVibrationEffect.startSequential().combine());
}
@Test
public void testSerializationMono() {
- CombinedVibrationEffect original = CombinedVibrationEffect.createSynced(
- VibrationEffect.get(VibrationEffect.EFFECT_CLICK));
+ CombinedVibrationEffect original = CombinedVibrationEffect.createSynced(VALID_EFFECT);
+
+ Parcel parcel = Parcel.obtain();
+ original.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ CombinedVibrationEffect restored = CombinedVibrationEffect.CREATOR.createFromParcel(parcel);
+ assertEquals(original, restored);
+ }
+
+ @Test
+ public void testSerializationStereo() {
+ CombinedVibrationEffect original = CombinedVibrationEffect.startSynced()
+ .addVibrator(0, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
+ .addVibrator(1, VibrationEffect.createOneShot(10, 255))
+ .combine();
+
+ Parcel parcel = Parcel.obtain();
+ original.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ CombinedVibrationEffect restored = CombinedVibrationEffect.CREATOR.createFromParcel(parcel);
+ assertEquals(original, restored);
+ }
+
+ @Test
+ public void testSerializationSequential() {
+ CombinedVibrationEffect original = CombinedVibrationEffect.startSequential()
+ .addNext(0, VALID_EFFECT)
+ .addNext(CombinedVibrationEffect.createSynced(VALID_EFFECT))
+ .addNext(0, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), 100)
+ .combine();
Parcel parcel = Parcel.obtain();
original.writeToParcel(parcel, 0);
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
index cc68bb6..4094f83 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
@@ -381,17 +381,31 @@
}
@Override
- public List<String> getAllowedCecSettingValues(String name) {
+ public List<String> getAllowedCecSettingStringValues(String name) {
return new ArrayList<>();
}
@Override
- public String getCecSettingValue(String name) {
+ public int[] getAllowedCecSettingIntValues(String name) {
+ return new int[0];
+ }
+
+ @Override
+ public String getCecSettingStringValue(String name) {
return "";
}
@Override
- public void setCecSettingValue(String name, String value) {
+ public void setCecSettingStringValue(String name, String value) {
+ }
+
+ @Override
+ public int getCecSettingIntValue(String name) {
+ return 0;
+ }
+
+ @Override
+ public void setCecSettingIntValue(String name, int value) {
}
}
diff --git a/core/tests/uwbtests/Android.bp b/core/tests/uwbtests/Android.bp
new file mode 100644
index 0000000..c41c346
--- /dev/null
+++ b/core/tests/uwbtests/Android.bp
@@ -0,0 +1,28 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "UwbManagerTests",
+ static_libs: [
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+ ],
+ libs: [
+ "android.test.runner",
+ ],
+ srcs: ["src/**/*.java"],
+ platform_apis: true,
+ certificate: "platform",
+ test_suites: ["device-tests"],
+}
diff --git a/core/tests/uwbtests/AndroidManifest.xml b/core/tests/uwbtests/AndroidManifest.xml
new file mode 100644
index 0000000..dc991ff
--- /dev/null
+++ b/core/tests/uwbtests/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="android.uwb">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!-- This is a self-instrumenting test package. -->
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.uwb"
+ android:label="UWB Manager Tests">
+ </instrumentation>
+
+</manifest>
+
diff --git a/core/tests/uwbtests/AndroidTest.xml b/core/tests/uwbtests/AndroidTest.xml
new file mode 100644
index 0000000..ff4b668
--- /dev/null
+++ b/core/tests/uwbtests/AndroidTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="Config for UWB Manager test cases">
+ <option name="test-suite-tag" value="apct"/>
+ <option name="test-suite-tag" value="apct-instrumentation"/>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="UwbManagerTests.apk" />
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct"/>
+ <option name="test-tag" value="UwbManagerTests"/>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.uwb" />
+ <option name="hidden-api-checks" value="false"/>
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
+ </test>
+</configuration>
diff --git a/core/tests/uwbtests/src/android/uwb/AngleMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/AngleMeasurementTest.java
new file mode 100644
index 0000000..7769c28
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/AngleMeasurementTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.uwb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test of {@link AngleMeasurement}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AngleMeasurementTest {
+ private static final double EPSILON = 0.00000000001;
+
+ @Test
+ public void testBuilder() {
+ double radians = 0.1234;
+ double errorRadians = 0.5678;
+ double confidence = 0.5;
+
+ AngleMeasurement.Builder builder = new AngleMeasurement.Builder();
+ tryBuild(builder, false);
+
+ builder.setRadians(radians);
+ tryBuild(builder, false);
+
+ builder.setErrorRadians(errorRadians);
+ tryBuild(builder, false);
+
+ builder.setConfidenceLevel(confidence);
+ AngleMeasurement measurement = tryBuild(builder, true);
+
+ assertEquals(measurement.getRadians(), radians, 0);
+ assertEquals(measurement.getErrorRadians(), errorRadians, 0);
+ assertEquals(measurement.getConfidenceLevel(), confidence, 0);
+ }
+
+ private AngleMeasurement tryBuild(AngleMeasurement.Builder builder, boolean expectSuccess) {
+ AngleMeasurement measurement = null;
+ try {
+ measurement = builder.build();
+ if (!expectSuccess) {
+ fail("Expected AngleMeasurement.Builder.build() to fail, but it succeeded");
+ }
+ } catch (IllegalStateException e) {
+ if (expectSuccess) {
+ fail("Expected AngleMeasurement.Builder.build() to succeed, but it failed");
+ }
+ }
+ return measurement;
+ }
+
+ @Test
+ public void testParcel() {
+ Parcel parcel = Parcel.obtain();
+ AngleMeasurement measurement = UwbTestUtils.getAngleMeasurement();
+ measurement.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ AngleMeasurement fromParcel = AngleMeasurement.CREATOR.createFromParcel(parcel);
+ assertEquals(measurement, fromParcel);
+ }
+}
diff --git a/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java
new file mode 100644
index 0000000..077b08f
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.uwb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test of {@link AngleOfArrivalMeasurement}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AngleOfArrivalMeasurementTest {
+
+ @Test
+ public void testBuilder() {
+ AngleMeasurement azimuth = UwbTestUtils.getAngleMeasurement();
+ AngleMeasurement altitude = UwbTestUtils.getAngleMeasurement();
+
+ AngleOfArrivalMeasurement.Builder builder = new AngleOfArrivalMeasurement.Builder();
+ tryBuild(builder, false);
+
+ builder.setAltitudeAngleMeasurement(altitude);
+ tryBuild(builder, false);
+
+ builder.setAzimuthAngleMeasurement(azimuth);
+ AngleOfArrivalMeasurement measurement = tryBuild(builder, true);
+
+ assertEquals(azimuth, measurement.getAzimuth());
+ assertEquals(altitude, measurement.getAltitude());
+ }
+
+ private AngleMeasurement getAngleMeasurement(double radian, double error, double confidence) {
+ return new AngleMeasurement.Builder()
+ .setRadians(radian)
+ .setErrorRadians(error)
+ .setConfidenceLevel(confidence)
+ .build();
+ }
+
+ private AngleOfArrivalMeasurement tryBuild(AngleOfArrivalMeasurement.Builder builder,
+ boolean expectSuccess) {
+ AngleOfArrivalMeasurement measurement = null;
+ try {
+ measurement = builder.build();
+ if (!expectSuccess) {
+ fail("Expected AngleOfArrivalMeasurement.Builder.build() to fail");
+ }
+ } catch (IllegalStateException e) {
+ if (expectSuccess) {
+ fail("Expected AngleOfArrivalMeasurement.Builder.build() to succeed");
+ }
+ }
+ return measurement;
+ }
+
+ @Test
+ public void testParcel() {
+ Parcel parcel = Parcel.obtain();
+ AngleOfArrivalMeasurement measurement = UwbTestUtils.getAngleOfArrivalMeasurement();
+ measurement.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ AngleOfArrivalMeasurement fromParcel =
+ AngleOfArrivalMeasurement.CREATOR.createFromParcel(parcel);
+ assertEquals(measurement, fromParcel);
+ }
+}
diff --git a/core/tests/uwbtests/src/android/uwb/DistanceMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/DistanceMeasurementTest.java
new file mode 100644
index 0000000..439c884
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/DistanceMeasurementTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.uwb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test of {@link DistanceMeasurement}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DistanceMeasurementTest {
+ private static final double EPSILON = 0.00000000001;
+
+ @Test
+ public void testBuilder() {
+ double meters = 0.12;
+ double error = 0.54;
+ double confidence = 0.99;
+
+ DistanceMeasurement.Builder builder = new DistanceMeasurement.Builder();
+ tryBuild(builder, false);
+
+ builder.setMeters(meters);
+ tryBuild(builder, false);
+
+ builder.setErrorMeters(error);
+ tryBuild(builder, false);
+
+ builder.setConfidenceLevel(confidence);
+ DistanceMeasurement measurement = tryBuild(builder, true);
+
+ assertEquals(meters, measurement.getMeters(), 0);
+ assertEquals(error, measurement.getErrorMeters(), 0);
+ assertEquals(confidence, measurement.getConfidenceLevel(), 0);
+ }
+
+ private DistanceMeasurement tryBuild(DistanceMeasurement.Builder builder,
+ boolean expectSuccess) {
+ DistanceMeasurement measurement = null;
+ try {
+ measurement = builder.build();
+ if (!expectSuccess) {
+ fail("Expected DistanceMeasurement.Builder.build() to fail");
+ }
+ } catch (IllegalStateException e) {
+ if (expectSuccess) {
+ fail("Expected DistanceMeasurement.Builder.build() to succeed");
+ }
+ }
+ return measurement;
+ }
+
+ @Test
+ public void testParcel() {
+ Parcel parcel = Parcel.obtain();
+ DistanceMeasurement measurement = UwbTestUtils.getDistanceMeasurement();
+ measurement.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ DistanceMeasurement fromParcel =
+ DistanceMeasurement.CREATOR.createFromParcel(parcel);
+ assertEquals(measurement, fromParcel);
+ }
+}
diff --git a/core/tests/uwbtests/src/android/uwb/RangingMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/RangingMeasurementTest.java
new file mode 100644
index 0000000..a7559d8
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/RangingMeasurementTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.uwb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.os.Parcel;
+import android.os.SystemClock;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test of {@link RangingMeasurement}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RangingMeasurementTest {
+
+ @Test
+ public void testBuilder() {
+ int status = RangingMeasurement.RANGING_STATUS_SUCCESS;
+ UwbAddress address = UwbTestUtils.getUwbAddress(false);
+ long time = SystemClock.elapsedRealtimeNanos();
+ AngleOfArrivalMeasurement angleMeasurement = UwbTestUtils.getAngleOfArrivalMeasurement();
+ DistanceMeasurement distanceMeasurement = UwbTestUtils.getDistanceMeasurement();
+
+ RangingMeasurement.Builder builder = new RangingMeasurement.Builder();
+
+ builder.setStatus(status);
+ tryBuild(builder, false);
+
+ builder.setElapsedRealtimeNanos(time);
+ tryBuild(builder, false);
+
+ builder.setAngleOfArrivalMeasurement(angleMeasurement);
+ tryBuild(builder, false);
+
+ builder.setDistanceMeasurement(distanceMeasurement);
+ tryBuild(builder, false);
+
+ builder.setRemoteDeviceAddress(address);
+ RangingMeasurement measurement = tryBuild(builder, true);
+
+ assertEquals(status, measurement.getStatus());
+ assertEquals(address, measurement.getRemoteDeviceAddress());
+ assertEquals(time, measurement.getElapsedRealtimeNanos());
+ assertEquals(angleMeasurement, measurement.getAngleOfArrival());
+ assertEquals(distanceMeasurement, measurement.getDistance());
+ }
+
+ private RangingMeasurement tryBuild(RangingMeasurement.Builder builder,
+ boolean expectSuccess) {
+ RangingMeasurement measurement = null;
+ try {
+ measurement = builder.build();
+ if (!expectSuccess) {
+ fail("Expected RangingMeasurement.Builder.build() to fail");
+ }
+ } catch (IllegalStateException e) {
+ if (expectSuccess) {
+ fail("Expected DistanceMeasurement.Builder.build() to succeed");
+ }
+ }
+ return measurement;
+ }
+
+ @Test
+ public void testParcel() {
+ Parcel parcel = Parcel.obtain();
+ RangingMeasurement measurement = UwbTestUtils.getRangingMeasurement();
+ measurement.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ RangingMeasurement fromParcel = RangingMeasurement.CREATOR.createFromParcel(parcel);
+ assertEquals(measurement, fromParcel);
+ }
+}
diff --git a/core/tests/uwbtests/src/android/uwb/RangingParamsTest.java b/core/tests/uwbtests/src/android/uwb/RangingParamsTest.java
new file mode 100644
index 0000000..8095c99
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/RangingParamsTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.uwb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.os.PersistableBundle;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.time.Duration;
+
+/**
+ * Test of {@link RangingParams}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RangingParamsTest {
+
+ @Test
+ public void testParams_Build() {
+ UwbAddress local = UwbAddress.fromBytes(new byte[] {(byte) 0xA0, (byte) 0x57});
+ UwbAddress remote = UwbAddress.fromBytes(new byte[] {(byte) 0x4D, (byte) 0x8C});
+ int channel = 9;
+ int rxPreamble = 16;
+ int txPreamble = 21;
+ boolean isController = true;
+ boolean isInitiator = false;
+ @RangingParams.StsPhyPacketType int stsPhyType = RangingParams.STS_PHY_PACKET_TYPE_SP2;
+ Duration samplePeriod = Duration.ofSeconds(1, 234);
+ PersistableBundle specParams = new PersistableBundle();
+ specParams.putString("protocol", "some_protocol");
+
+ RangingParams params = new RangingParams.Builder()
+ .setChannelNumber(channel)
+ .setReceivePreambleCodeIndex(rxPreamble)
+ .setTransmitPreambleCodeIndex(txPreamble)
+ .setLocalDeviceAddress(local)
+ .addRemoteDeviceAddress(remote)
+ .setIsController(isController)
+ .setIsInitiator(isInitiator)
+ .setSamplePeriod(samplePeriod)
+ .setStsPhPacketType(stsPhyType)
+ .setSpecificationParameters(specParams)
+ .build();
+
+ assertEquals(params.getLocalDeviceAddress(), local);
+ assertEquals(params.getRemoteDeviceAddresses().size(), 1);
+ assertEquals(params.getRemoteDeviceAddresses().get(0), remote);
+ assertEquals(params.getChannelNumber(), channel);
+ assertEquals(params.isController(), isController);
+ assertEquals(params.isInitiator(), isInitiator);
+ assertEquals(params.getRxPreambleIndex(), rxPreamble);
+ assertEquals(params.getTxPreambleIndex(), txPreamble);
+ assertEquals(params.getStsPhyPacketType(), stsPhyType);
+ assertEquals(params.getSamplingPeriod(), samplePeriod);
+ assertTrue(params.getSpecificationParameters().kindofEquals(specParams));
+ }
+
+ @Test
+ public void testParcel() {
+ Parcel parcel = Parcel.obtain();
+ RangingParams params = new RangingParams.Builder()
+ .setChannelNumber(9)
+ .setReceivePreambleCodeIndex(16)
+ .setTransmitPreambleCodeIndex(21)
+ .setLocalDeviceAddress(UwbTestUtils.getUwbAddress(false))
+ .addRemoteDeviceAddress(UwbTestUtils.getUwbAddress(true))
+ .setIsController(false)
+ .setIsInitiator(true)
+ .setSamplePeriod(Duration.ofSeconds(2))
+ .setStsPhPacketType(RangingParams.STS_PHY_PACKET_TYPE_SP1)
+ .build();
+ params.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ RangingParams fromParcel = RangingParams.CREATOR.createFromParcel(parcel);
+ assertEquals(params, fromParcel);
+ }
+}
diff --git a/core/tests/uwbtests/src/android/uwb/RangingReportTest.java b/core/tests/uwbtests/src/android/uwb/RangingReportTest.java
new file mode 100644
index 0000000..64c48ba
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/RangingReportTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.uwb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+/**
+ * Test of {@link RangingReport}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RangingReportTest {
+
+ @Test
+ public void testBuilder() {
+ List<RangingMeasurement> measurements = UwbTestUtils.getRangingMeasurements(5);
+
+ RangingReport.Builder builder = new RangingReport.Builder();
+ builder.addMeasurements(measurements);
+ RangingReport report = tryBuild(builder, true);
+ verifyMeasurementsEqual(measurements, report.getMeasurements());
+
+
+ builder = new RangingReport.Builder();
+ for (RangingMeasurement measurement : measurements) {
+ builder.addMeasurement(measurement);
+ }
+ report = tryBuild(builder, true);
+ verifyMeasurementsEqual(measurements, report.getMeasurements());
+ }
+
+ private void verifyMeasurementsEqual(List<RangingMeasurement> expected,
+ List<RangingMeasurement> actual) {
+ assertEquals(expected.size(), actual.size());
+ for (int i = 0; i < expected.size(); i++) {
+ assertEquals(expected.get(i), actual.get(i));
+ }
+ }
+
+ private RangingReport tryBuild(RangingReport.Builder builder,
+ boolean expectSuccess) {
+ RangingReport report = null;
+ try {
+ report = builder.build();
+ if (!expectSuccess) {
+ fail("Expected RangingReport.Builder.build() to fail");
+ }
+ } catch (IllegalStateException e) {
+ if (expectSuccess) {
+ fail("Expected RangingReport.Builder.build() to succeed");
+ }
+ }
+ return report;
+ }
+
+ @Test
+ public void testParcel() {
+ Parcel parcel = Parcel.obtain();
+ RangingReport report = UwbTestUtils.getRangingReports(5);
+ report.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ RangingReport fromParcel = RangingReport.CREATOR.createFromParcel(parcel);
+ assertEquals(report, fromParcel);
+ }
+}
diff --git a/core/tests/uwbtests/src/android/uwb/UwbAddressTest.java b/core/tests/uwbtests/src/android/uwb/UwbAddressTest.java
new file mode 100644
index 0000000..ccc88a9
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/UwbAddressTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.uwb;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test of {@link UwbAddress}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class UwbAddressTest {
+
+ @Test
+ public void testFromBytes_Short() {
+ runFromBytes(UwbAddress.SHORT_ADDRESS_BYTE_LENGTH);
+ }
+
+ @Test
+ public void testFromBytes_Extended() {
+ runFromBytes(UwbAddress.EXTENDED_ADDRESS_BYTE_LENGTH);
+ }
+
+ private void runFromBytes(int len) {
+ byte[] addressBytes = getByteArray(len);
+ UwbAddress address = UwbAddress.fromBytes(addressBytes);
+ assertEquals(address.size(), len);
+ assertEquals(addressBytes, address.toBytes());
+ }
+
+ private byte[] getByteArray(int len) {
+ byte[] res = new byte[len];
+ for (int i = 0; i < len; i++) {
+ res[i] = (byte) i;
+ }
+ return res;
+ }
+
+ @Test
+ public void testParcel_Short() {
+ runParcel(true);
+ }
+
+ @Test
+ public void testParcel_Extended() {
+ runParcel(false);
+ }
+
+ private void runParcel(boolean useShortAddress) {
+ Parcel parcel = Parcel.obtain();
+ UwbAddress address = UwbTestUtils.getUwbAddress(useShortAddress);
+ address.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ UwbAddress fromParcel = UwbAddress.CREATOR.createFromParcel(parcel);
+ assertEquals(address, fromParcel);
+ }
+}
diff --git a/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java b/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
new file mode 100644
index 0000000..62e0b62
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.uwb;
+
+import android.os.SystemClock;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class UwbTestUtils {
+ private UwbTestUtils() {}
+
+ public static AngleMeasurement getAngleMeasurement() {
+ return new AngleMeasurement.Builder()
+ .setRadians(getDoubleInRange(-Math.PI, Math.PI))
+ .setErrorRadians(getDoubleInRange(0, Math.PI))
+ .setConfidenceLevel(getDoubleInRange(0, 1))
+ .build();
+ }
+
+ public static AngleOfArrivalMeasurement getAngleOfArrivalMeasurement() {
+ return new AngleOfArrivalMeasurement.Builder()
+ .setAltitudeAngleMeasurement(getAngleMeasurement())
+ .setAzimuthAngleMeasurement(getAngleMeasurement())
+ .build();
+ }
+
+ public static DistanceMeasurement getDistanceMeasurement() {
+ return new DistanceMeasurement.Builder()
+ .setMeters(getDoubleInRange(0, 100))
+ .setErrorMeters(getDoubleInRange(0, 10))
+ .setConfidenceLevel(getDoubleInRange(0, 1))
+ .build();
+ }
+
+ public static RangingMeasurement getRangingMeasurement() {
+ return getRangingMeasurement(getUwbAddress(false));
+ }
+
+ public static RangingMeasurement getRangingMeasurement(UwbAddress address) {
+ return new RangingMeasurement.Builder()
+ .setDistanceMeasurement(getDistanceMeasurement())
+ .setAngleOfArrivalMeasurement(getAngleOfArrivalMeasurement())
+ .setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos())
+ .setRemoteDeviceAddress(address != null ? address : getUwbAddress(false))
+ .setStatus(RangingMeasurement.RANGING_STATUS_SUCCESS)
+ .build();
+ }
+
+ public static List<RangingMeasurement> getRangingMeasurements(int num) {
+ List<RangingMeasurement> result = new ArrayList<>();
+ for (int i = 0; i < num; i++) {
+ result.add(getRangingMeasurement());
+ }
+ return result;
+ }
+
+ public static RangingReport getRangingReports(int numMeasurements) {
+ RangingReport.Builder builder = new RangingReport.Builder();
+ for (int i = 0; i < numMeasurements; i++) {
+ builder.addMeasurement(getRangingMeasurement());
+ }
+ return builder.build();
+ }
+
+ private static double getDoubleInRange(double min, double max) {
+ return min + (max - min) * Math.random();
+ }
+
+ public static UwbAddress getUwbAddress(boolean isShortAddress) {
+ byte[] addressBytes = new byte[isShortAddress ? UwbAddress.SHORT_ADDRESS_BYTE_LENGTH :
+ UwbAddress.EXTENDED_ADDRESS_BYTE_LENGTH];
+ for (int i = 0; i < addressBytes.length; i++) {
+ addressBytes[i] = (byte) getDoubleInRange(1, 255);
+ }
+ return UwbAddress.fromBytes(addressBytes);
+ }
+}
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index b143be7..441c163 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -327,7 +327,7 @@
* 1) Create Typeface from ttf file.
* <pre>
* <code>
- * Typeface.Builder buidler = new Typeface.Builder("your_font_file.ttf");
+ * Typeface.Builder builder = new Typeface.Builder("your_font_file.ttf");
* Typeface typeface = builder.build();
* </code>
* </pre>
@@ -335,7 +335,7 @@
* 2) Create Typeface from ttc file in assets directory.
* <pre>
* <code>
- * Typeface.Builder buidler = new Typeface.Builder(getAssets(), "your_font_file.ttc");
+ * Typeface.Builder builder = new Typeface.Builder(getAssets(), "your_font_file.ttc");
* builder.setTtcIndex(2); // Set index of font collection.
* Typeface typeface = builder.build();
* </code>
@@ -344,7 +344,7 @@
* 3) Create Typeface with variation settings.
* <pre>
* <code>
- * Typeface.Builder buidler = new Typeface.Builder("your_font_file.ttf");
+ * Typeface.Builder builder = new Typeface.Builder("your_font_file.ttf");
* builder.setFontVariationSettings("'wght' 700, 'slnt' 20, 'ital' 1");
* builder.setWeight(700); // Tell the system that this is a bold font.
* builder.setItalic(true); // Tell the system that this is an italic style font.
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index 586c512..c07b4bc 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -626,6 +626,51 @@
return mNativePtr;
}
+ /**
+ * Returns true if the given font is created from the same source data from this font.
+ *
+ * This method essentially compares {@link ByteBuffer} inside Font, but has some optimization
+ * for faster comparing. This method compares the internal object before going to one-by-one
+ * byte compare with {@link ByteBuffer}. This typically works efficiently if you compares the
+ * font that is created from {@link Builder#Builder(Font)}.
+ *
+ * This API is typically useful for checking if two fonts can be interpolated by font variation
+ * axes. For example, when you call {@link android.text.TextShaper} for the same
+ * string but different style, you may get two font objects which is created from the same
+ * source but have different parameters. You may want to animate between them by interpolating
+ * font variation settings if these fonts are created from the same source.
+ *
+ * @param other a font object to be compared.
+ * @return true if given font is created from the same source from this font. Otherwise false.
+ */
+ public boolean isSameSource(@NonNull Font other) {
+ Objects.requireNonNull(other);
+
+ // Shortcut for the same instance.
+ if (mBuffer == other.mBuffer) {
+ return true;
+ }
+
+ // Shortcut for different font buffer check by comparing size.
+ if (mBuffer.capacity() != other.mBuffer.capacity()) {
+ return false;
+ }
+
+ // ByteBuffer#equals compares all bytes which is not performant for e.g HashMap. Since
+ // underlying native font object holds buffer address, check if this buffer points exactly
+ // the same address as a shortcut of equality. For being compatible with of API30 or before,
+ // check buffer position even if the buffer points the same address.
+ if (nIsSameBufferAddress(mNativePtr, other.mNativePtr)
+ && mBuffer.position() == other.mBuffer.position()) {
+ return true;
+ }
+
+ // Unfortunately, need to compare bytes one-by-one since the buffer may be different font
+ // file but has the same file size, or two font has same content but they are allocated
+ // differently. For being compatible with API30 ore before, compare with ByteBuffer#equals.
+ return mBuffer.equals(other.mBuffer);
+ }
+
@Override
public boolean equals(@Nullable Object o) {
if (o == this) {
@@ -643,24 +688,7 @@
return false;
}
- // Shortcut for different font buffer check by comparing size.
- if (mBuffer.capacity() != f.mBuffer.capacity()) {
- return false;
- }
-
- // ByteBuffer#equals compares all bytes which is not performant for e.g HashMap. Since
- // underlying native font object holds buffer address, check if this buffer points exactly
- // the same address as a shortcut of equality. For being compatible with of API30 or before,
- // check buffer position even if the buffer points the same address.
- if (nIsSameBufferAddress(mNativePtr, f.mNativePtr)
- && mBuffer.position() == f.mBuffer.position()) {
- return true;
- }
-
- // Unfortunately, need to compare bytes one-by-one since the buffer may be different font
- // file but has the same file size, or two font has same content but they are allocated
- // differently. For being compatible with API30 ore before, compare with ByteBuffer#equals.
- return mBuffer.equals(f.mBuffer);
+ return isSameSource(f);
}
@Override
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 0defbd6..39e32c6 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -116,12 +116,15 @@
"res",
],
static_libs: [
+ "androidx.appcompat_appcompat",
+ "androidx.arch.core_core-runtime",
"androidx.dynamicanimation_dynamicanimation",
"kotlinx-coroutines-android",
"kotlinx-coroutines-core",
+ "iconloader_base",
"protolog-lib",
+ "SettingsLib",
"WindowManager-Shell-proto",
- "androidx.appcompat_appcompat",
],
kotlincflags: ["-Xjvm-default=enable"],
manifest: "AndroidManifest.xml",
diff --git a/packages/SystemUI/res/layout/bubble_view.xml b/libs/WindowManager/Shell/res/drawable/bubble_dismiss_circle.xml
similarity index 62%
copy from packages/SystemUI/res/layout/bubble_view.xml
copy to libs/WindowManager/Shell/res/drawable/bubble_dismiss_circle.xml
index 78f7cff..2104be4 100644
--- a/packages/SystemUI/res/layout/bubble_view.xml
+++ b/libs/WindowManager/Shell/res/drawable/bubble_dismiss_circle.xml
@@ -1,6 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2018 The Android Open Source Project
+ ~ Copyright (C) 2020 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -12,10 +11,18 @@
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
- ~ limitations under the License
+ ~ limitations under the License.
-->
-<com.android.systemui.bubbles.BadgedImageView
+<!--
+ The transparent circle outline that encircles the bubbles when they're in the dismiss target.
+-->
+<shape
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/bubble_view"
- android:layout_width="@dimen/individual_bubble_size"
- android:layout_height="@dimen/individual_bubble_size"/>
+ android:shape="oval">
+
+ <stroke
+ android:width="1dp"
+ android:color="#66FFFFFF" />
+
+ <solid android:color="#B3000000" />
+</shape>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/bubble_dismiss_icon.xml b/libs/WindowManager/Shell/res/drawable/bubble_dismiss_icon.xml
new file mode 100644
index 0000000..ff8fede
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/bubble_dismiss_icon.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<!-- The 'X' bubble dismiss icon. This is just ic_close with a stroke. -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M19.000000,6.400000l-1.400000,-1.400000 -5.600000,5.600000 -5.600000,-5.600000 -1.400000,1.400000 5.600000,5.600000 -5.600000,5.600000 1.400000,1.400000 5.600000,-5.600000 5.600000,5.600000 1.400000,-1.400000 -5.600000,-5.600000z"
+ android:fillColor="#FFFFFFFF"
+ android:strokeColor="#FF000000"/>
+</vector>
diff --git a/libs/WindowManager/Shell/res/drawable/bubble_ic_create_bubble.xml b/libs/WindowManager/Shell/res/drawable/bubble_ic_create_bubble.xml
new file mode 100644
index 0000000..920671a
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/bubble_ic_create_bubble.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT 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:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M23,5v8h-2V5H3v14h10v2v0H3c-1.1,0 -2,-0.9 -2,-2V5c0,-1.1 0.9,-2 2,-2h18C22.1,3 23,3.9 23,5zM10,8v2.59L5.71,6.29L4.29,7.71L8.59,12H6v2h6V8H10zM19,15c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,15 19,15z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_empty_bubble_overflow_dark.xml b/libs/WindowManager/Shell/res/drawable/bubble_ic_empty_overflow_dark.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_empty_bubble_overflow_dark.xml
rename to libs/WindowManager/Shell/res/drawable/bubble_ic_empty_overflow_dark.xml
diff --git a/packages/SystemUI/res/drawable/ic_empty_bubble_overflow_light.xml b/libs/WindowManager/Shell/res/drawable/bubble_ic_empty_overflow_light.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_empty_bubble_overflow_light.xml
rename to libs/WindowManager/Shell/res/drawable/bubble_ic_empty_overflow_light.xml
diff --git a/packages/SystemUI/res/drawable/ic_bubble_overflow_button.xml b/libs/WindowManager/Shell/res/drawable/bubble_ic_overflow_button.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_bubble_overflow_button.xml
rename to libs/WindowManager/Shell/res/drawable/bubble_ic_overflow_button.xml
diff --git a/libs/WindowManager/Shell/res/drawable/bubble_ic_stop_bubble.xml b/libs/WindowManager/Shell/res/drawable/bubble_ic_stop_bubble.xml
new file mode 100644
index 0000000..8609576
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/bubble_ic_stop_bubble.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT 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:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M11.29,14.71L7,10.41V13H5V7h6v2H8.41l4.29,4.29L11.29,14.71zM21,3H3C1.9,3 1,3.9 1,5v14c0,1.1 0.9,2 2,2h10v0v-2H3V5h18v8h2V5C23,3.9 22.1,3 21,3zM19,15c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,15 19,15z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/bubble_manage_menu_row.xml b/libs/WindowManager/Shell/res/drawable/bubble_manage_menu_row.xml
similarity index 95%
rename from packages/SystemUI/res/drawable/bubble_manage_menu_row.xml
rename to libs/WindowManager/Shell/res/drawable/bubble_manage_menu_row.xml
index a793680..c61ac1c 100644
--- a/packages/SystemUI/res/drawable/bubble_manage_menu_row.xml
+++ b/libs/WindowManager/Shell/res/drawable/bubble_manage_menu_row.xml
@@ -12,7 +12,7 @@
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
- ~ limitations under the License
+ ~ limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
diff --git a/packages/SystemUI/res/drawable/bubble_stack_user_education_bg.xml b/libs/WindowManager/Shell/res/drawable/bubble_stack_user_education_bg.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/bubble_stack_user_education_bg.xml
rename to libs/WindowManager/Shell/res/drawable/bubble_stack_user_education_bg.xml
diff --git a/packages/SystemUI/res/drawable/bubble_stack_user_education_bg_rtl.xml b/libs/WindowManager/Shell/res/drawable/bubble_stack_user_education_bg_rtl.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/bubble_stack_user_education_bg_rtl.xml
rename to libs/WindowManager/Shell/res/drawable/bubble_stack_user_education_bg_rtl.xml
diff --git a/libs/WindowManager/Shell/res/drawable/ic_remove_no_shadow.xml b/libs/WindowManager/Shell/res/drawable/ic_remove_no_shadow.xml
new file mode 100644
index 0000000..265c501
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/ic_remove_no_shadow.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT 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:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/textColorPrimary" >
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M13.41,12l5.29-5.29c0.39-0.39,0.39-1.02,0-1.41c-0.39-0.39-1.02-0.39-1.41,0L12,10.59L6.71,
+ 5.29c-0.39-0.39-1.02-0.39-1.41,0c-0.39,0.39-0.39,1.02,0,1.41L10.59,12l-5.29,5.29c-0.39,0.39-0.39,1.02,
+ 0,1.41c0.39,0.39,1.02,0.39,1.41,0L12,13.41l5.29,5.29c0.39,0.39,1.02,0.39,1.41,0c0.39-0.39,0.39-1.02,0-1.41L13.41,12z"/>
+</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/rounded_bg_full.xml b/libs/WindowManager/Shell/res/drawable/rounded_bg_full.xml
new file mode 100644
index 0000000..e957445
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/rounded_bg_full.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="?android:attr/colorBackgroundFloating" />
+ <corners
+ android:bottomLeftRadius="?android:attr/dialogCornerRadius"
+ android:topLeftRadius="?android:attr/dialogCornerRadius"
+ android:bottomRightRadius="?android:attr/dialogCornerRadius"
+ android:topRightRadius="?android:attr/dialogCornerRadius"
+ />
+</shape>
diff --git a/packages/SystemUI/res/layout/bubble_dismiss_target.xml b/libs/WindowManager/Shell/res/layout/bubble_dismiss_target.xml
similarity index 100%
rename from packages/SystemUI/res/layout/bubble_dismiss_target.xml
rename to libs/WindowManager/Shell/res/layout/bubble_dismiss_target.xml
diff --git a/packages/SystemUI/res/layout/bubble_expanded_view.xml b/libs/WindowManager/Shell/res/layout/bubble_expanded_view.xml
similarity index 80%
rename from packages/SystemUI/res/layout/bubble_expanded_view.xml
rename to libs/WindowManager/Shell/res/layout/bubble_expanded_view.xml
index db40c4f..54b08c6 100644
--- a/packages/SystemUI/res/layout/bubble_expanded_view.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_expanded_view.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2018 The Android Open Source Project
+ ~ Copyright (C) 2020 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -12,9 +12,9 @@
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
- ~ limitations under the License
+ ~ limitations under the License.
-->
-<com.android.systemui.bubbles.BubbleExpandedView
+<com.android.wm.shell.bubbles.BubbleExpandedView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="match_parent"
@@ -27,7 +27,7 @@
android:layout_height="@dimen/bubble_pointer_height"
/>
- <com.android.systemui.statusbar.AlphaOptimizedButton
+ <com.android.wm.shell.common.AlphaOptimizedButton
style="@android:style/Widget.Material.Button.Borderless"
android:id="@+id/settings_button"
android:layout_gravity="start"
@@ -35,7 +35,7 @@
android:layout_height="wrap_content"
android:focusable="true"
android:text="@string/manage_bubbles_text"
- android:textColor="?attr/wallpaperTextColor"
+ android:textColor="?android:attr/textColorPrimaryInverse"
/>
-</com.android.systemui.bubbles.BubbleExpandedView>
+</com.android.wm.shell.bubbles.BubbleExpandedView>
diff --git a/packages/SystemUI/res/layout/bubble_flyout.xml b/libs/WindowManager/Shell/res/layout/bubble_flyout.xml
similarity index 97%
rename from packages/SystemUI/res/layout/bubble_flyout.xml
rename to libs/WindowManager/Shell/res/layout/bubble_flyout.xml
index 22a8135..7fdf290 100644
--- a/packages/SystemUI/res/layout/bubble_flyout.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_flyout.xml
@@ -34,7 +34,7 @@
android:layout_height="30dp"
android:layout_marginEnd="@dimen/bubble_flyout_avatar_message_space"
android:scaleType="centerInside"
- android:src="@drawable/ic_create_bubble"/>
+ android:src="@drawable/bubble_ic_create_bubble"/>
<LinearLayout
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/bubble_manage_menu.xml b/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml
similarity index 95%
rename from packages/SystemUI/res/layout/bubble_manage_menu.xml
rename to libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml
index 8494882..3a6aa80 100644
--- a/packages/SystemUI/res/layout/bubble_manage_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml
@@ -35,7 +35,7 @@
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_remove_no_shadow"
- android:tint="@color/global_actions_text"/>
+ android:tint="@color/bubbles_icon_tint"/>
<TextView
android:layout_width="wrap_content"
@@ -59,8 +59,8 @@
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
- android:src="@drawable/ic_stop_bubble"
- android:tint="@color/global_actions_text"/>
+ android:src="@drawable/bubble_ic_stop_bubble"
+ android:tint="@color/bubbles_icon_tint"/>
<TextView
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/bubble_menu_view.xml b/libs/WindowManager/Shell/res/layout/bubble_menu_view.xml
similarity index 65%
rename from packages/SystemUI/res/layout/bubble_menu_view.xml
rename to libs/WindowManager/Shell/res/layout/bubble_menu_view.xml
index 24608d3..0c1d1a5 100644
--- a/packages/SystemUI/res/layout/bubble_menu_view.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_menu_view.xml
@@ -14,7 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.systemui.bubbles.BubbleMenuView
+<com.android.wm.shell.bubbles.BubbleMenuView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
@@ -30,14 +30,14 @@
<ImageView
android:id="@*android:id/icon"
- android:layout_width="@dimen/global_actions_grid_item_icon_width"
- android:layout_height="@dimen/global_actions_grid_item_icon_height"
- android:layout_marginTop="@dimen/global_actions_grid_item_icon_top_margin"
- android:layout_marginBottom="@dimen/global_actions_grid_item_icon_bottom_margin"
- android:layout_marginLeft="@dimen/global_actions_grid_item_icon_side_margin"
- android:layout_marginRight="@dimen/global_actions_grid_item_icon_side_margin"
+ android:layout_width="@dimen/bubble_grid_item_icon_width"
+ android:layout_height="@dimen/bubble_grid_item_icon_height"
+ android:layout_marginTop="@dimen/bubble_grid_item_icon_top_margin"
+ android:layout_marginBottom="@dimen/bubble_grid_item_icon_bottom_margin"
+ android:layout_marginLeft="@dimen/bubble_grid_item_icon_side_margin"
+ android:layout_marginRight="@dimen/bubble_grid_item_icon_side_margin"
android:scaleType="centerInside"
- android:tint="@color/global_actions_text"
+ android:tint="@color/bubbles_icon_tint"
/>
</FrameLayout>
-</com.android.systemui.bubbles.BubbleMenuView>
+</com.android.wm.shell.bubbles.BubbleMenuView>
diff --git a/packages/SystemUI/res/layout/bubble_overflow_activity.xml b/libs/WindowManager/Shell/res/layout/bubble_overflow_activity.xml
similarity index 100%
rename from packages/SystemUI/res/layout/bubble_overflow_activity.xml
rename to libs/WindowManager/Shell/res/layout/bubble_overflow_activity.xml
diff --git a/packages/SystemUI/res/layout/bubble_overflow_button.xml b/libs/WindowManager/Shell/res/layout/bubble_overflow_button.xml
similarity index 89%
rename from packages/SystemUI/res/layout/bubble_overflow_button.xml
rename to libs/WindowManager/Shell/res/layout/bubble_overflow_button.xml
index 8f0fd4f..61000fe 100644
--- a/packages/SystemUI/res/layout/bubble_overflow_button.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_overflow_button.xml
@@ -14,9 +14,9 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<com.android.systemui.bubbles.BadgedImageView
+<com.android.wm.shell.bubbles.BadgedImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/bubble_overflow_button"
android:layout_width="@dimen/individual_bubble_size"
android:layout_height="@dimen/individual_bubble_size"
- android:src="@drawable/ic_bubble_overflow_button"/>
+ android:src="@drawable/bubble_ic_overflow_button"/>
diff --git a/packages/SystemUI/res/layout/bubble_overflow_view.xml b/libs/WindowManager/Shell/res/layout/bubble_overflow_view.xml
similarity index 96%
rename from packages/SystemUI/res/layout/bubble_overflow_view.xml
rename to libs/WindowManager/Shell/res/layout/bubble_overflow_view.xml
index 1218fba..c1f67bd 100644
--- a/packages/SystemUI/res/layout/bubble_overflow_view.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_overflow_view.xml
@@ -21,7 +21,7 @@
android:layout_height="wrap_content"
android:orientation="vertical">
- <com.android.systemui.bubbles.BadgedImageView
+ <com.android.wm.shell.bubbles.BadgedImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/bubble_view"
android:layout_gravity="center"
diff --git a/packages/SystemUI/res/layout/bubble_stack_user_education.xml b/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml
similarity index 100%
rename from packages/SystemUI/res/layout/bubble_stack_user_education.xml
rename to libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml
diff --git a/packages/SystemUI/res/layout/bubble_view.xml b/libs/WindowManager/Shell/res/layout/bubble_view.xml
similarity index 94%
rename from packages/SystemUI/res/layout/bubble_view.xml
rename to libs/WindowManager/Shell/res/layout/bubble_view.xml
index 78f7cff..a28bd678 100644
--- a/packages/SystemUI/res/layout/bubble_view.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_view.xml
@@ -14,7 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<com.android.systemui.bubbles.BadgedImageView
+<com.android.wm.shell.bubbles.BadgedImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/bubble_view"
android:layout_width="@dimen/individual_bubble_size"
diff --git a/packages/SystemUI/res/layout/bubbles_manage_button_education.xml b/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml
similarity index 92%
rename from packages/SystemUI/res/layout/bubbles_manage_button_education.xml
rename to libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml
index b51dc93..8de06c7 100644
--- a/packages/SystemUI/res/layout/bubbles_manage_button_education.xml
+++ b/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml
@@ -64,7 +64,7 @@
android:id="@+id/button_layout"
android:orientation="horizontal" >
- <com.android.systemui.statusbar.AlphaOptimizedButton
+ <com.android.wm.shell.common.AlphaOptimizedButton
style="@android:style/Widget.Material.Button.Borderless"
android:id="@+id/manage"
android:layout_gravity="start"
@@ -73,10 +73,10 @@
android:focusable="true"
android:clickable="false"
android:text="@string/manage_bubbles_text"
- android:textColor="?attr/wallpaperTextColor"
+ android:textColor="?android:attr/textColorPrimaryInverse"
/>
- <com.android.systemui.statusbar.AlphaOptimizedButton
+ <com.android.wm.shell.common.AlphaOptimizedButton
style="@android:style/Widget.Material.Button.Borderless"
android:id="@+id/got_it"
android:layout_gravity="start"
@@ -84,7 +84,7 @@
android:layout_height="wrap_content"
android:focusable="true"
android:text="@string/bubbles_user_education_got_it"
- android:textColor="?attr/wallpaperTextColor"
+ android:textColor="?android:attr/textColorPrimaryInverse"
/>
</LinearLayout>
</LinearLayout>
diff --git a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
index bee9f41..6342c00 100644
--- a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
+++ b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
@@ -79,12 +79,6 @@
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/splitscreen\/SplitScreenTaskListener.java"
},
- "-712674749": {
- "message": "Clip description: %s",
- "level": "VERBOSE",
- "group": "WM_SHELL_DRAG_AND_DROP",
- "at": "com\/android\/wm\/shell\/draganddrop\/DragAndDropController.java"
- },
"-710770147": {
"message": "Add target: %s",
"level": "VERBOSE",
@@ -121,6 +115,12 @@
"group": "WM_SHELL_DRAG_AND_DROP",
"at": "com\/android\/wm\/shell\/draganddrop\/DropOutlineDrawable.java"
},
+ "375908576": {
+ "message": "Clip description: handlingDrag=%b itemCount=%d mimeTypes=%s",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_DRAG_AND_DROP",
+ "at": "com\/android\/wm\/shell\/draganddrop\/DragAndDropController.java"
+ },
"481673835": {
"message": "addListenerForTaskId taskId=%s",
"level": "VERBOSE",
@@ -169,12 +169,6 @@
"group": "WM_SHELL_DRAG_AND_DROP",
"at": "com\/android\/wm\/shell\/draganddrop\/DragLayout.java"
},
- "1842752748": {
- "message": "Clip description: handlingDrag=%b mimeTypes=%s",
- "level": "VERBOSE",
- "group": "WM_SHELL_DRAG_AND_DROP",
- "at": "com\/android\/wm\/shell\/draganddrop\/DragAndDropController.java"
- },
"1862198614": {
"message": "Drag event: action=%s x=%f y=%f xOffset=%f yOffset=%f",
"level": "VERBOSE",
diff --git a/libs/WindowManager/Shell/res/values-land/dimens.xml b/libs/WindowManager/Shell/res/values-land/dimens.xml
index 77a601d..aafba58 100644
--- a/libs/WindowManager/Shell/res/values-land/dimens.xml
+++ b/libs/WindowManager/Shell/res/values-land/dimens.xml
@@ -18,4 +18,8 @@
<resources>
<dimen name="docked_divider_handle_width">2dp</dimen>
<dimen name="docked_divider_handle_height">16dp</dimen>
+
+ <!-- Padding between status bar and bubbles when displayed in expanded state, smaller
+ value in landscape since we have limited vertical space-->
+ <dimen name="bubble_padding_top">4dp</dimen>
</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/bubble_manage_menu_row.xml b/libs/WindowManager/Shell/res/values-night/colors.xml
similarity index 69%
copy from packages/SystemUI/res/drawable/bubble_manage_menu_row.xml
copy to libs/WindowManager/Shell/res/values-night/colors.xml
index a793680..24b3640 100644
--- a/packages/SystemUI/res/drawable/bubble_manage_menu_row.xml
+++ b/libs/WindowManager/Shell/res/values-night/colors.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 The Android Open Source Project
~
@@ -12,10 +11,10 @@
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
- ~ limitations under the License
+ ~ limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true">
- <ripple android:color="#99999999" />
- </item>
-</selector>
\ No newline at end of file
+
+<resources>
+ <!-- Bubbles -->
+ <color name="bubbles_icon_tint">@color/GM2_grey_200</color>
+</resources>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index cc3bf2a..1674d0b 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -25,4 +25,14 @@
<!-- Background for the various drop targets when handling drag and drop. -->
<color name="drop_outline_background">#330000FF</color>
+
+ <!-- Bubbles -->
+ <color name="bubbles_light">#FFFFFF</color>
+ <color name="bubbles_dark">@color/GM2_grey_800</color>
+ <color name="bubbles_icon_tint">@color/GM2_grey_700</color>
+
+ <!-- GM2 colors -->
+ <color name="GM2_grey_200">#E8EAED</color>
+ <color name="GM2_grey_700">#5F6368</color>
+ <color name="GM2_grey_800">#3C4043</color>
</resources>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index b87a642..8a60aaf 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -75,4 +75,94 @@
<!-- The amount to inset the drop target regions from the edge of the display -->
<dimen name="drop_layout_display_margin">16dp</dimen>
+
+ <!-- The menu grid size for bubble menu. -->
+ <dimen name="bubble_grid_item_icon_width">20dp</dimen>
+ <dimen name="bubble_grid_item_icon_height">20dp</dimen>
+ <dimen name="bubble_grid_item_icon_top_margin">12dp</dimen>
+ <dimen name="bubble_grid_item_icon_bottom_margin">4dp</dimen>
+ <dimen name="bubble_grid_item_icon_side_margin">22dp</dimen>
+
+ <!-- How much each bubble is elevated. -->
+ <dimen name="bubble_elevation">1dp</dimen>
+ <!-- How much the bubble flyout text container is elevated. -->
+ <dimen name="bubble_flyout_elevation">4dp</dimen>
+ <!-- How much padding is around the left and right sides of the flyout text. -->
+ <dimen name="bubble_flyout_padding_x">12dp</dimen>
+ <!-- How much padding is around the top and bottom of the flyout text. -->
+ <dimen name="bubble_flyout_padding_y">10dp</dimen>
+ <!-- Size of the triangle that points from the flyout to the bubble stack. -->
+ <dimen name="bubble_flyout_pointer_size">6dp</dimen>
+ <!-- How much space to leave between the flyout (tip of the arrow) and the bubble stack. -->
+ <dimen name="bubble_flyout_space_from_bubble">8dp</dimen>
+ <!-- How much space to leave between the flyout text and the avatar displayed in the flyout. -->
+ <dimen name="bubble_flyout_avatar_message_space">6dp</dimen>
+ <!-- Padding between status bar and bubbles when displayed in expanded state -->
+ <dimen name="bubble_padding_top">16dp</dimen>
+ <!-- Size of individual bubbles. -->
+ <dimen name="individual_bubble_size">60dp</dimen>
+ <!-- Size of bubble bitmap. -->
+ <dimen name="bubble_bitmap_size">52dp</dimen>
+ <!-- Size of bubble icon bitmap. -->
+ <dimen name="bubble_overflow_icon_bitmap_size">24dp</dimen>
+ <!-- Extra padding added to the touchable rect for bubbles so they are easier to grab. -->
+ <dimen name="bubble_touch_padding">12dp</dimen>
+ <!-- Size of the circle around the bubbles when they're in the dismiss target. -->
+ <dimen name="bubble_dismiss_encircle_size">52dp</dimen>
+ <!-- Padding around the view displayed when the bubble is expanded -->
+ <dimen name="bubble_expanded_view_padding">4dp</dimen>
+ <!-- This should be at least the size of bubble_expanded_view_padding; it is used to include
+ a slight touch slop around the expanded view. -->
+ <dimen name="bubble_expanded_view_slop">8dp</dimen>
+ <!-- Default (and minimum) height of the expanded view shown when the bubble is expanded -->
+ <dimen name="bubble_expanded_default_height">180dp</dimen>
+ <!-- Default height of bubble overflow -->
+ <dimen name="bubble_overflow_height">480dp</dimen>
+ <!-- Bubble overflow padding when there are no bubbles -->
+ <dimen name="bubble_overflow_empty_state_padding">16dp</dimen>
+ <!-- Padding of container for overflow bubbles -->
+ <dimen name="bubble_overflow_padding">15dp</dimen>
+ <!-- Padding of label for bubble overflow view -->
+ <dimen name="bubble_overflow_text_padding">7dp</dimen>
+ <!-- Height of bubble overflow empty state illustration -->
+ <dimen name="bubble_empty_overflow_image_height">200dp</dimen>
+ <!-- Padding of bubble overflow empty state subtitle -->
+ <dimen name="bubble_empty_overflow_subtitle_padding">50dp</dimen>
+ <!-- Height of the triangle that points to the expanded bubble -->
+ <dimen name="bubble_pointer_height">8dp</dimen>
+ <!-- Width of the triangle that points to the expanded bubble -->
+ <dimen name="bubble_pointer_width">12dp</dimen>
+ <!-- Extra padding around the dismiss target for bubbles -->
+ <dimen name="bubble_dismiss_slop">16dp</dimen>
+ <!-- Height of button allowing users to adjust settings for bubbles. -->
+ <dimen name="bubble_manage_button_height">48dp</dimen>
+ <!-- Max width of the message bubble-->
+ <dimen name="bubble_message_max_width">144dp</dimen>
+ <!-- Min width of the message bubble -->
+ <dimen name="bubble_message_min_width">32dp</dimen>
+ <!-- Interior padding of the message bubble -->
+ <dimen name="bubble_message_padding">4dp</dimen>
+ <!-- Offset between bubbles in their stacked position. -->
+ <dimen name="bubble_stack_offset">10dp</dimen>
+ <!-- Offset between stack y and animation y for bubble swap. -->
+ <dimen name="bubble_swap_animation_offset">15dp</dimen>
+ <!-- How far offscreen the bubble stack rests. Cuts off padding and part of icon bitmap. -->
+ <dimen name="bubble_stack_offscreen">9dp</dimen>
+ <!-- How far down the screen the stack starts. -->
+ <dimen name="bubble_stack_starting_offset_y">120dp</dimen>
+ <!-- Space between the pointer triangle and the bubble expanded view -->
+ <dimen name="bubble_pointer_margin">8dp</dimen>
+ <!-- Padding applied to the bubble dismiss target. Touches in this padding cause the bubbles to
+ snap to the dismiss target. -->
+ <dimen name="bubble_dismiss_target_padding_x">40dp</dimen>
+ <dimen name="bubble_dismiss_target_padding_y">20dp</dimen>
+ <dimen name="bubble_manage_menu_elevation">4dp</dimen>
+
+ <!-- Bubbles user education views -->
+ <dimen name="bubbles_manage_education_width">160dp</dimen>
+ <!-- The inset from the top bound of the manage button to place the user education. -->
+ <dimen name="bubbles_manage_education_top_inset">65dp</dimen>
+ <!-- Size of padding for the user education cling, this should at minimum be larger than
+ individual_bubble_size + some padding. -->
+ <dimen name="bubble_stack_user_education_side_inset">72dp</dimen>
</resources>
diff --git a/libs/WindowManager/Shell/res/values/ids.xml b/libs/WindowManager/Shell/res/values/ids.xml
index fb89238..434a000 100644
--- a/libs/WindowManager/Shell/res/values/ids.xml
+++ b/libs/WindowManager/Shell/res/values/ids.xml
@@ -23,4 +23,21 @@
<item type="id" name="action_move_tl_50" />
<item type="id" name="action_move_tl_30" />
<item type="id" name="action_move_rb_full" />
+
+ <!-- For saving PhysicsAnimationLayout animations/animators as view tags. -->
+ <item type="id" name="translation_x_dynamicanimation_tag"/>
+ <item type="id" name="translation_y_dynamicanimation_tag"/>
+ <item type="id" name="translation_z_dynamicanimation_tag"/>
+ <item type="id" name="alpha_dynamicanimation_tag"/>
+ <item type="id" name="scale_x_dynamicanimation_tag"/>
+ <item type="id" name="scale_y_dynamicanimation_tag"/>
+ <item type="id" name="physics_animator_tag"/>
+ <item type="id" name="target_animator_tag" />
+ <item type="id" name="reorder_animator_tag"/>
+
+ <!-- Accessibility actions for bubbles. -->
+ <item type="id" name="action_move_top_left"/>
+ <item type="id" name="action_move_top_right"/>
+ <item type="id" name="action_move_bottom_left"/>
+ <item type="id" name="action_move_bottom_right"/>
</resources>
diff --git a/libs/WindowManager/Shell/res/values/integers.xml b/libs/WindowManager/Shell/res/values/integers.xml
new file mode 100644
index 0000000..583bf33
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values/integers.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources>
+ <!-- Maximum number of bubbles to render and animate at one time. While the animations used are
+ lightweight translation animations, this number can be reduced on lower end devices if any
+ performance issues arise. -->
+ <integer name="bubbles_max_rendered">5</integer>
+ <!-- Number of columns in bubble overflow. -->
+ <integer name="bubbles_overflow_columns">4</integer>
+ <!-- Maximum number of bubbles we allow in overflow before we dismiss the oldest one. -->
+ <integer name="bubbles_max_overflow">16</integer>
+</resources>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index da5965d..30ef72c 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -97,4 +97,53 @@
<string name="accessibility_action_start_one_handed">Start one-handed mode</string>
<!-- Accessibility description for stop one-handed mode [CHAR LIMIT=NONE] -->
<string name="accessibility_action_stop_one_handed">Exit one-handed mode</string>
+
+ <!-- Text used for content description of settings button in the header of expanded bubble
+ view. [CHAR_LIMIT=NONE] -->
+ <string name="bubbles_settings_button_description">Settings for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g> bubbles</string>
+ <!-- Content description for button that shows bubble overflow on click [CHAR LIMIT=NONE] -->
+ <string name="bubble_overflow_button_content_description">Overflow</string>
+ <!-- Action to add overflow bubble back to stack. [CHAR LIMIT=NONE] -->
+ <string name="bubble_accessibility_action_add_back">Add back to stack</string>
+ <!-- Content description when a bubble is focused. [CHAR LIMIT=NONE] -->
+ <string name="bubble_content_description_single"><xliff:g id="notification_title" example="some title">%1$s</xliff:g> from <xliff:g id="app_name" example="YouTube">%2$s</xliff:g></string>
+ <!-- Content description when the stack of bubbles is focused. [CHAR LIMIT=NONE] -->
+ <string name="bubble_content_description_stack"><xliff:g id="notification_title" example="some title">%1$s</xliff:g> from <xliff:g id="app_name" example="YouTube">%2$s</xliff:g> and <xliff:g id="bubble_count" example="4">%3$d</xliff:g> more</string>
+ <!-- Action in accessibility menu to move the stack of bubbles to the top left of the screen. [CHAR LIMIT=30] -->
+ <string name="bubble_accessibility_action_move_top_left">Move top left</string>
+ <!-- Action in accessibility menu to move the stack of bubbles to the top right of the screen. [CHAR LIMIT=30] -->
+ <string name="bubble_accessibility_action_move_top_right">Move top right</string>
+ <!-- Action in accessibility menu to move the stack of bubbles to the bottom left of the screen. [CHAR LIMIT=30]-->
+ <string name="bubble_accessibility_action_move_bottom_left">Move bottom left</string>
+ <!-- Action in accessibility menu to move the stack of bubbles to the bottom right of the screen. [CHAR LIMIT=30]-->
+ <string name="bubble_accessibility_action_move_bottom_right">Move bottom right</string>
+ <!-- Label for the button that takes the user to the notification settings for the given app. -->
+ <string name="bubbles_app_settings"><xliff:g id="notification_title" example="Android Messages">%1$s</xliff:g> settings</string>
+ <!-- Text used for the bubble dismiss area. Bubbles dragged to, or flung towards, this area will go away. [CHAR LIMIT=30] -->
+ <string name="bubble_dismiss_text">Dismiss bubble</string>
+ <!-- Button text to stop a conversation from bubbling [CHAR LIMIT=60]-->
+ <string name="bubbles_dont_bubble_conversation">Don\u2019t bubble conversation</string>
+ <!-- Title text for the bubbles feature education cling shown when a bubble is on screen for the first time. [CHAR LIMIT=60]-->
+ <string name="bubbles_user_education_title">Chat using bubbles</string>
+ <!-- Descriptive text for the bubble feature education cling shown when a bubble is on screen for the first time. [CHAR LIMIT=NONE] -->
+ <string name="bubbles_user_education_description">New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it.</string>
+ <!-- Title text for the bubble "manage" button tool tip highlighting where users can go to control bubble settings. [CHAR LIMIT=60]-->
+ <string name="bubbles_user_education_manage_title">Control bubbles anytime</string>
+ <!-- Descriptive text for the bubble "manage" button tool tip highlighting where users can go to control bubble settings. [CHAR LIMIT=80]-->
+ <string name="bubbles_user_education_manage">Tap Manage to turn off bubbles from this app</string>
+ <!-- Button text for dismissing the bubble "manage" button tool tip [CHAR LIMIT=20]-->
+ <string name="bubbles_user_education_got_it">Got it</string>
+ <!-- [CHAR LIMIT=NONE] Empty overflow title -->
+ <string name="bubble_overflow_empty_title">No recent bubbles</string>
+ <!-- [CHAR LIMIT=NONE] Empty overflow subtitle -->
+ <string name="bubble_overflow_empty_subtitle">Recent bubbles and dismissed bubbles will appear here</string>
+
+ <!-- [CHAR LIMIT=100] Notification Importance title -->
+ <string name="notification_bubble_title">Bubble</string>
+
+ <!-- The text for the manage bubbles link. [CHAR LIMIT=NONE] -->
+ <string name="manage_bubbles_text">Manage</string>
+
+ <!-- Content description to tell the user a bubble has been dismissed. -->
+ <string name="accessibility_bubble_dismissed">Bubble dismissed.</string>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/bubbles/TaskView.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
index 0a2cfbf..59a765d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/TaskView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
@@ -30,26 +30,23 @@
import android.content.pm.ShortcutInfo;
import android.graphics.Rect;
import android.os.Binder;
+import android.util.CloseGuard;
import android.view.SurfaceControl;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import com.android.wm.shell.ShellTaskOrganizer;
-
-import dalvik.system.CloseGuard;
-
import java.io.PrintWriter;
import java.util.concurrent.Executor;
/**
* View that can display a task.
*/
-// TODO: Place in com.android.wm.shell vs. com.android.wm.shell.bubbles on shell migration.
public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
ShellTaskOrganizer.TaskListener {
+ /** Callback for listening task state. */
public interface Listener {
/** Called when the container is ready for launching activities. */
default void onInitialized() {}
@@ -70,7 +67,7 @@
default void onBackPressedOnTaskRoot(int taskId) {}
}
- private final CloseGuard mGuard = CloseGuard.get();
+ private final CloseGuard mGuard = new CloseGuard();
private final ShellTaskOrganizer mTaskOrganizer;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
index a3b720c..8aca01d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
@@ -56,4 +56,10 @@
* Interpolator to be used when animating a move based on a click. Pair with enough duration.
*/
public static final Interpolator TOUCH_RESPONSE = new PathInterpolator(0.3f, 0f, 0.1f, 1f);
+
+ /**
+ * Interpolator to be used when animating a panel closing.
+ */
+ public static final Interpolator PANEL_CLOSE_ACCELERATED =
+ new PathInterpolator(0.3f, 0, 0.5f, 1);
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
index 8bcffc8..4d06c03 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
+
+import static android.graphics.Paint.DITHER_FLAG;
+import static android.graphics.Paint.FILTER_BITMAP_FLAG;
import android.annotation.Nullable;
import android.content.Context;
@@ -28,14 +31,11 @@
import android.widget.ImageView;
import com.android.launcher3.icons.DotRenderer;
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
+import com.android.wm.shell.R;
+import com.android.wm.shell.animation.Interpolators;
import java.util.EnumSet;
-import static android.graphics.Paint.DITHER_FLAG;
-import static android.graphics.Paint.FILTER_BITMAP_FLAG;
-
/**
* View that displays an adaptive icon with an app-badge and a dot.
*
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 09d9e03..93ed395 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.os.AsyncTask.Status.FINISHED;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 598a604..05acb55 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
@@ -22,8 +22,8 @@
import static android.view.View.VISIBLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
@@ -59,8 +59,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.bubbles.dagger.BubbleModule;
-import com.android.systemui.dagger.qualifiers.Main;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.FloatingContentCoordinator;
@@ -165,7 +163,7 @@
private boolean mIsStatusBarShade = true;
/**
- * Injected constructor. See {@link BubbleModule}.
+ * Injected constructor.
*/
public static BubbleController create(Context context,
@Nullable BubbleStackView.SurfaceSynchronizer synchronizer,
@@ -175,7 +173,7 @@
WindowManagerShellWrapper windowManagerShellWrapper,
LauncherApps launcherApps,
UiEventLogger uiEventLogger,
- @Main Handler mainHandler,
+ Handler mainHandler,
ShellTaskOrganizer organizer) {
BubbleLogger logger = new BubbleLogger(uiEventLogger);
return new BubbleController(context,
@@ -903,7 +901,7 @@
}
if (!mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
if (!mBubbleData.hasOverflowBubbleWithKey(bubble.getKey())
- && (!bubble.showInShade()
+ && (!bubble.showInShade()
|| reason == DISMISS_NOTIF_CANCEL
|| reason == DISMISS_GROUP_CANCELLED)) {
// The bubble is now gone & the notification is hidden from the shade, so
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index 8cacc8f..b6a97e2 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
-import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_DATA;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_DATA;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import android.annotation.NonNull;
import android.app.PendingIntent;
@@ -33,8 +33,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
-import com.android.systemui.R;
-import com.android.systemui.bubbles.Bubbles.DismissReason;
+import com.android.wm.shell.R;
+import com.android.wm.shell.bubbles.Bubbles.DismissReason;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
index 2ab9e87..fc565f1 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles
+package com.android.wm.shell.bubbles
import android.annotation.SuppressLint
import android.annotation.UserIdInt
@@ -24,9 +24,9 @@
import android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER
import android.os.UserHandle
import android.util.Log
-import com.android.systemui.bubbles.storage.BubbleEntity
-import com.android.systemui.bubbles.storage.BubblePersistentRepository
-import com.android.systemui.bubbles.storage.BubbleVolatileRepository
+import com.android.wm.shell.bubbles.storage.BubbleEntity
+import com.android.wm.shell.bubbles.storage.BubblePersistentRepository
+import com.android.wm.shell.bubbles.storage.BubbleVolatileRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java
index 3937422..53f4e87 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import android.content.Context;
import android.provider.Settings;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleEntry.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEntry.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/bubbles/BubbleEntry.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEntry.java
index a0d3391..ff68861 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleEntry.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEntry.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import static android.app.Notification.FLAG_BUBBLE;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index ae3c683..74521c7 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_EXPANDED_VIEW;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.systemui.bubbles.BubbleOverflowActivity.EXTRA_BUBBLE_CONTROLLER;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_EXPANDED_VIEW;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.wm.shell.bubbles.BubbleOverflowActivity.EXTRA_BUBBLE_CONTROLLER;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
@@ -54,10 +54,11 @@
import androidx.annotation.Nullable;
import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.systemui.R;
-import com.android.systemui.recents.TriangleShape;
-import com.android.systemui.statusbar.AlphaOptimizedButton;
+import com.android.wm.shell.R;
+import com.android.wm.shell.TaskView;
+import com.android.wm.shell.common.AlphaOptimizedButton;
import com.android.wm.shell.common.HandlerExecutor;
+import com.android.wm.shell.common.TriangleShape;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
index d8b3250..460e0e7 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,12 +14,13 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import static android.graphics.Paint.ANTI_ALIAS_FLAG;
import static android.graphics.Paint.FILTER_BITMAP_FLAG;
-import static com.android.systemui.Interpolators.ALPHA_IN;
-import static com.android.systemui.Interpolators.ALPHA_OUT;
+
+import static com.android.wm.shell.animation.Interpolators.ALPHA_IN;
+import static com.android.wm.shell.animation.Interpolators.ALPHA_OUT;
import android.animation.ArgbEvaluator;
import android.content.Context;
@@ -47,8 +48,8 @@
import androidx.annotation.Nullable;
-import com.android.systemui.R;
-import com.android.systemui.recents.TriangleShape;
+import com.android.wm.shell.R;
+import com.android.wm.shell.common.TriangleShape;
/**
* Flyout view that appears as a 'chat bubble' alongside the bubble stack. The flyout can visually
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleIconFactory.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleIconFactory.java
index 371e849..2d9da21 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleIconFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,14 +26,13 @@
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import com.android.launcher3.icons.BaseIconFactory;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.ShadowGenerator;
-import com.android.systemui.R;
+import com.android.wm.shell.R;
/**
* Factory for creating normalized bubble icons.
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/bubbles/BubbleLogger.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
index a24f5c2..3361c4c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEvent;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
index 297144a..686d2d4 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles
+package com.android.wm.shell.bubbles
import android.app.ActivityTaskManager.INVALID_TASK_ID
import android.content.Context
@@ -31,7 +31,7 @@
import android.view.LayoutInflater
import android.view.View
import android.widget.FrameLayout
-import com.android.systemui.R
+import com.android.wm.shell.R
class BubbleOverflow(
private val context: Context,
@@ -72,7 +72,7 @@
updateResources()
expandedView.applyThemeAttrs()
// Apply inset and new style to fresh icon drawable.
- overflowBtn.setImageResource(R.drawable.ic_bubble_overflow_button)
+ overflowBtn.setImageResource(R.drawable.bubble_ic_overflow_button)
updateBtnTheme()
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowActivity.java
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowActivity.java
index bc84173..2759b59 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowActivity.java
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
-import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_OVERFLOW;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_OVERFLOW;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import android.app.Activity;
import android.content.Context;
@@ -43,13 +43,12 @@
import androidx.recyclerview.widget.RecyclerView;
import com.android.internal.util.ContrastColorUtil;
-import com.android.systemui.R;
+import com.android.wm.shell.R;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
-
/**
* Activity for showing aged out bubbles.
* Must be public to be accessible to androidx...AppComponentFactory
@@ -168,8 +167,8 @@
final boolean isNightMode = (mode == Configuration.UI_MODE_NIGHT_YES);
mEmptyStateImage.setImageDrawable(isNightMode
- ? res.getDrawable(R.drawable.ic_empty_bubble_overflow_dark)
- : res.getDrawable(R.drawable.ic_empty_bubble_overflow_light));
+ ? res.getDrawable(R.drawable.bubble_ic_empty_overflow_dark)
+ : res.getDrawable(R.drawable.bubble_ic_empty_overflow_light));
findViewById(android.R.id.content)
.setBackgroundColor(isNightMode
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/bubbles/BubblePositioner.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 029caee..eccd009 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import android.content.Context;
import android.content.res.Configuration;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 69ed5b7..155f342 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_STACK_VIEW;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_STACK_VIEW;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -71,13 +71,13 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
-import com.android.systemui.bubbles.animation.AnimatableScaleMatrix;
-import com.android.systemui.bubbles.animation.ExpandedAnimationController;
-import com.android.systemui.bubbles.animation.PhysicsAnimationLayout;
-import com.android.systemui.bubbles.animation.StackAnimationController;
+import com.android.wm.shell.R;
+import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.animation.PhysicsAnimator;
+import com.android.wm.shell.bubbles.animation.AnimatableScaleMatrix;
+import com.android.wm.shell.bubbles.animation.ExpandedAnimationController;
+import com.android.wm.shell.bubbles.animation.PhysicsAnimationLayout;
+import com.android.wm.shell.bubbles.animation.StackAnimationController;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
@@ -2661,14 +2661,17 @@
.floatValue();
}
+ /** Set the start position of the bubble stack. */
public void setStackStartPosition(RelativeStackPosition position) {
mStackAnimationController.setStackStartPosition(position);
}
+ /** @return the position of the bubble stack. */
public PointF getStackPosition() {
return mStackAnimationController.getStackPosition();
}
+ /** @return the relative position of the bubble stack. */
public RelativeStackPosition getRelativeStackPosition() {
return mStackAnimationController.getRelativeStackPosition();
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
index a3e6a1e..0b68306 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
-import static com.android.systemui.bubbles.BadgedImageView.DEFAULT_PATH_SIZE;
-import static com.android.systemui.bubbles.BadgedImageView.WHITE_SCRIM_ALPHA;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.wm.shell.bubbles.BadgedImageView.DEFAULT_PATH_SIZE;
+import static com.android.wm.shell.bubbles.BadgedImageView.WHITE_SCRIM_ALPHA;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import android.annotation.NonNull;
import android.content.Context;
@@ -42,7 +42,7 @@
import com.android.internal.graphics.ColorUtils;
import com.android.launcher3.icons.BitmapInfo;
-import com.android.systemui.R;
+import com.android.wm.shell.R;
import java.lang.ref.WeakReference;
import java.util.Objects;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewProvider.java
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewProvider.java
index 5890172..ec900be 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewProvider.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import android.graphics.Bitmap;
import android.graphics.Path;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/bubbles/Bubbles.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 415edb1..79c42d8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/DismissView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt
similarity index 81%
rename from packages/SystemUI/src/com/android/systemui/bubbles/DismissView.kt
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt
index b3c552d..04b5ad6 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/DismissView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt
@@ -1,4 +1,20 @@
-package com.android.systemui.bubbles
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.bubbles
import android.content.Context
import android.graphics.drawable.TransitionDrawable
@@ -9,9 +25,9 @@
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_LOW_BOUNCY
import androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW
-import com.android.systemui.R
-import com.android.wm.shell.common.DismissCircleView
+import com.android.wm.shell.R
import com.android.wm.shell.animation.PhysicsAnimator
+import com.android.wm.shell.common.DismissCircleView
/*
* View that handles interactions between DismissCircleView and BubbleStackView.
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt
index 3db07c2..4cc6702 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles
+package com.android.wm.shell.bubbles
import android.content.Context
import android.graphics.Color
@@ -24,8 +24,8 @@
import android.widget.LinearLayout
import android.widget.TextView
import com.android.internal.util.ContrastColorUtil
-import com.android.systemui.Interpolators
-import com.android.systemui.R
+import com.android.wm.shell.R
+import com.android.wm.shell.animation.Interpolators
/**
* User education view to highlight the manage button that allows a user to configure the settings
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/ObjectWrapper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ObjectWrapper.java
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/bubbles/ObjectWrapper.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ObjectWrapper.java
index f054122..528907f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/ObjectWrapper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ObjectWrapper.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import android.os.Binder;
import android.os.IBinder;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/RelativeTouchListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/bubbles/RelativeTouchListener.kt
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt
index b1291a5..b347329 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/RelativeTouchListener.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles
+package com.android.wm.shell.bubbles
import android.graphics.PointF
import android.os.Handler
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt
index 216df2e..04c4dfb 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles
+package com.android.wm.shell.bubbles
import android.content.Context
import android.graphics.Color
@@ -23,8 +23,8 @@
import android.widget.LinearLayout
import android.widget.TextView
import com.android.internal.util.ContrastColorUtil
-import com.android.systemui.Interpolators
-import com.android.systemui.R
+import com.android.wm.shell.R
+import com.android.wm.shell.animation.Interpolators
/**
* User education view to highlight the collapsed stack of bubbles.
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/AnimatableScaleMatrix.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/AnimatableScaleMatrix.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/bubbles/animation/AnimatableScaleMatrix.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/AnimatableScaleMatrix.java
index 07acb71..2612b81 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/AnimatableScaleMatrix.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/AnimatableScaleMatrix.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles.animation;
+package com.android.wm.shell.bubbles.animation;
import android.graphics.Matrix;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
index 5a70401..61fbf81 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles.animation;
+package com.android.wm.shell.bubbles.animation;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -28,10 +28,10 @@
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringForce;
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
-import com.android.systemui.bubbles.BubblePositioner;
+import com.android.wm.shell.R;
+import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.animation.PhysicsAnimator;
+import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
import com.google.android.collect.Sets;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/OneTimeEndListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/OneTimeEndListener.java
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/bubbles/animation/OneTimeEndListener.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/OneTimeEndListener.java
index 4e0abc8..37355c4 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/OneTimeEndListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/OneTimeEndListener.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles.animation;
+package com.android.wm.shell.bubbles.animation;
import androidx.dynamicanimation.animation.DynamicAnimation;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java
index 0a596d5..0618d5d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles.animation;
+package com.android.wm.shell.bubbles.animation;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -35,7 +35,7 @@
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
-import com.android.systemui.R;
+import com.android.wm.shell.R;
import java.util.ArrayList;
import java.util.HashMap;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
index 43893f2..d7f2e4b 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles.animation;
+package com.android.wm.shell.bubbles.animation;
import android.content.ContentResolver;
import android.content.res.Resources;
@@ -34,11 +34,11 @@
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
-import com.android.systemui.R;
-import com.android.systemui.bubbles.BadgedImageView;
-import com.android.systemui.bubbles.BubblePositioner;
-import com.android.systemui.bubbles.BubbleStackView;
+import com.android.wm.shell.R;
import com.android.wm.shell.animation.PhysicsAnimator;
+import com.android.wm.shell.bubbles.BadgedImageView;
+import com.android.wm.shell.bubbles.BubblePositioner;
+import com.android.wm.shell.bubbles.BubbleStackView;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt
index 24768cd..aeba302 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
+package com.android.wm.shell.bubbles.storage
import android.annotation.DimenRes
import android.annotation.UserIdInt
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepository.kt
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepository.kt
index ce0786d..66a75af 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepository.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
+package com.android.wm.shell.bubbles.storage
import android.content.Context
import android.util.AtomicFile
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepository.kt
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepository.kt
index e0a7c78..7f0b165 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepository.kt
@@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
+package com.android.wm.shell.bubbles.storage
import android.content.pm.LauncherApps
import android.os.UserHandle
import com.android.internal.annotations.VisibleForTesting
-import com.android.systemui.bubbles.ShortcutKey
+import com.android.wm.shell.bubbles.ShortcutKey
private const val CAPACITY = 16
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt
rename to libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt
index bf163a2..fe72bd3 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt
@@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
+package com.android.wm.shell.bubbles.storage
-import com.android.internal.util.FastXmlSerializer
-import org.xmlpull.v1.XmlSerializer
-import java.io.IOException
import android.util.Xml
+import com.android.internal.util.FastXmlSerializer
import com.android.internal.util.XmlUtils
import org.xmlpull.v1.XmlPullParser
+import org.xmlpull.v1.XmlSerializer
+import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.nio.charset.StandardCharsets
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/AlphaOptimizedButton.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/AlphaOptimizedButton.java
new file mode 100644
index 0000000..6f0a61b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/AlphaOptimizedButton.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.common;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.Button;
+
+/**
+ * A Button which doesn't have overlapping drawing commands
+ *
+ * This is the copy from SystemUI/statusbar.
+ */
+public class AlphaOptimizedButton extends Button {
+ public AlphaOptimizedButton(Context context) {
+ super(context);
+ }
+
+ public AlphaOptimizedButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public AlphaOptimizedButton(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public AlphaOptimizedButton(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TriangleShape.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TriangleShape.java
new file mode 100644
index 0000000..7079190
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TriangleShape.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.common;
+
+import android.graphics.Outline;
+import android.graphics.Path;
+import android.graphics.drawable.shapes.PathShape;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Wrapper around {@link PathShape}
+ * that creates a shape with a triangular path (pointing up or down).
+ *
+ * This is the copy from SystemUI/recents.
+ */
+public class TriangleShape extends PathShape {
+ private Path mTriangularPath;
+
+ public TriangleShape(Path path, float stdWidth, float stdHeight) {
+ super(path, stdWidth, stdHeight);
+ mTriangularPath = path;
+ }
+
+ public static TriangleShape create(float width, float height, boolean isPointingUp) {
+ Path triangularPath = new Path();
+ if (isPointingUp) {
+ triangularPath.moveTo(0, height);
+ triangularPath.lineTo(width, height);
+ triangularPath.lineTo(width / 2, 0);
+ triangularPath.close();
+ } else {
+ triangularPath.moveTo(0, 0);
+ triangularPath.lineTo(width / 2, height);
+ triangularPath.lineTo(width, 0);
+ triangularPath.close();
+ }
+ return new TriangleShape(triangularPath, width, height);
+ }
+
+ /** Create an arrow TriangleShape that points to the left or the right */
+ public static TriangleShape createHorizontal(
+ float width, float height, boolean isPointingLeft) {
+ Path triangularPath = new Path();
+ if (isPointingLeft) {
+ triangularPath.moveTo(0, height / 2);
+ triangularPath.lineTo(width, height);
+ triangularPath.lineTo(width, 0);
+ triangularPath.close();
+ } else {
+ triangularPath.moveTo(0, height);
+ triangularPath.lineTo(width, height / 2);
+ triangularPath.lineTo(0, 0);
+ triangularPath.close();
+ }
+ return new TriangleShape(triangularPath, width, height);
+ }
+
+ @Override
+ public void getOutline(@NonNull Outline outline) {
+ outline.setPath(mTriangularPath);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index bf5b1d8..c77f594 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -16,17 +16,9 @@
package com.android.wm.shell.draganddrop;
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.content.ClipDescription.EXTRA_ACTIVITY_OPTIONS;
-import static android.content.ClipDescription.EXTRA_PENDING_INTENT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
-import static android.content.Intent.EXTRA_PACKAGE_NAME;
-import static android.content.Intent.EXTRA_SHORTCUT_ID;
-import static android.content.Intent.EXTRA_TASK_ID;
-import static android.content.Intent.EXTRA_USER;
import static android.view.DragEvent.ACTION_DRAG_ENDED;
import static android.view.DragEvent.ACTION_DRAG_ENTERED;
import static android.view.DragEvent.ACTION_DRAG_EXITED;
@@ -42,25 +34,10 @@
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.ActivityOptions;
-import android.app.ActivityTaskManager;
-import android.app.PendingIntent;
-import android.content.ActivityNotFoundException;
-import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Context;
-import android.content.Intent;
-import android.content.pm.LauncherApps;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.Slog;
import android.util.SparseArray;
import android.view.DragEvent;
import android.view.LayoutInflater;
@@ -76,6 +53,7 @@
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreen;
+import java.util.Objects;
import java.util.Optional;
/**
@@ -91,10 +69,12 @@
private SplitScreen mSplitScreen;
private final SparseArray<PerDisplay> mDisplayDropTargets = new SparseArray<>();
- private boolean mIsHandlingDrag;
- private DragLayout mDragLayout;
private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+ // A count of the number of active drags in progress to ensure that we only hide the window when
+ // all the drag animations have completed
+ private int mActiveDragCount;
+
public DragAndDropController(Context context, DisplayController displayController) {
mContext = context;
mDisplayController = displayController;
@@ -124,26 +104,31 @@
layoutParams.setFitInsetsTypes(0);
layoutParams.setTitle("ShellDropTarget");
- FrameLayout dropTarget = (FrameLayout) LayoutInflater.from(context).inflate(
+ FrameLayout rootView = (FrameLayout) LayoutInflater.from(context).inflate(
R.layout.global_drop_target, null);
- dropTarget.setOnDragListener(this);
- dropTarget.setVisibility(View.INVISIBLE);
- wm.addView(dropTarget, layoutParams);
- mDisplayDropTargets.put(displayId, new PerDisplay(displayId, context, wm, dropTarget));
+ rootView.setOnDragListener(this);
+ rootView.setVisibility(View.INVISIBLE);
+ DragLayout dragLayout = new DragLayout(context, mSplitScreen);
+ rootView.addView(dragLayout,
+ new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ wm.addView(rootView, layoutParams);
+
+ mDisplayDropTargets.put(displayId,
+ new PerDisplay(displayId, context, wm, rootView, dragLayout));
}
@Override
public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Display changed: %d", displayId);
final PerDisplay pd = mDisplayDropTargets.get(displayId);
- pd.dropTarget.requestApplyInsets();
+ pd.rootView.requestApplyInsets();
}
@Override
public void onDisplayRemoved(int displayId) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Display removed: %d", displayId);
final PerDisplay pd = mDisplayDropTargets.get(displayId);
- pd.wm.removeViewImmediate(pd.dropTarget);
+ pd.wm.removeViewImmediate(pd.rootView);
mDisplayDropTargets.remove(displayId);
}
@@ -158,32 +143,33 @@
final ClipDescription description = event.getClipDescription();
if (event.getAction() == ACTION_DRAG_STARTED) {
- final boolean hasValidClipData = description.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY)
- || description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT)
- || description.hasMimeType(MIMETYPE_APPLICATION_TASK);
- mIsHandlingDrag = hasValidClipData;
+ final boolean hasValidClipData = event.getClipData().getItemCount() > 0
+ && (description.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY)
+ || description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT)
+ || description.hasMimeType(MIMETYPE_APPLICATION_TASK));
+ pd.isHandlingDrag = hasValidClipData;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
- "Clip description: handlingDrag=%b mimeTypes=%s",
- mIsHandlingDrag, getMimeTypes(description));
+ "Clip description: handlingDrag=%b itemCount=%d mimeTypes=%s",
+ pd.isHandlingDrag, event.getClipData().getItemCount(),
+ getMimeTypes(description));
}
- if (!mIsHandlingDrag) {
+ if (!pd.isHandlingDrag) {
return false;
}
switch (event.getAction()) {
case ACTION_DRAG_STARTED:
- mDragLayout = new DragLayout(pd.context,
- mDisplayController.getDisplayLayout(displayId), mSplitScreen);
- pd.dropTarget.addView(mDragLayout,
- new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ mActiveDragCount++;
+ pd.dragLayout.prepare(mDisplayController.getDisplayLayout(displayId),
+ event.getClipData());
setDropTargetWindowVisibility(pd, View.VISIBLE);
break;
case ACTION_DRAG_ENTERED:
- mDragLayout.show(event);
+ pd.dragLayout.show();
break;
case ACTION_DRAG_LOCATION:
- mDragLayout.update(event);
+ pd.dragLayout.update(event);
break;
case ACTION_DROP: {
return handleDrop(event, pd);
@@ -191,20 +177,22 @@
case ACTION_DRAG_EXITED: {
// Either one of DROP or EXITED will happen, and when EXITED we won't consume
// the drag surface
- mDragLayout.hide(event, null);
+ pd.dragLayout.hide(event, null);
break;
}
case ACTION_DRAG_ENDED:
// TODO(b/169894807): Ensure sure it's not possible to get ENDED without DROP
// or EXITED
- if (!mDragLayout.hasDropped()) {
- final View dragLayout = mDragLayout;
- mDragLayout.hide(event, () -> {
- setDropTargetWindowVisibility(pd, View.INVISIBLE);
- pd.dropTarget.removeView(dragLayout);
+ if (!pd.dragLayout.hasDropped()) {
+ mActiveDragCount--;
+ pd.dragLayout.hide(event, () -> {
+ if (mActiveDragCount == 0) {
+ // Hide the window if another drag hasn't been started while animating
+ // the drag-end
+ setDropTargetWindowVisibility(pd, View.INVISIBLE);
+ }
});
}
- mDragLayout = null;
break;
}
return true;
@@ -214,52 +202,14 @@
* Handles dropping on the drop target.
*/
private boolean handleDrop(DragEvent event, PerDisplay pd) {
- final ClipData data = event.getClipData();
- final ClipDescription description = event.getClipDescription();
final SurfaceControl dragSurface = event.getDragSurface();
- final View dragLayout = mDragLayout;
- final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK);
- final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT);
- return mDragLayout.drop(event, dragSurface, (dropTargetBounds) -> {
- if (dropTargetBounds != null && data.getItemCount() > 0) {
- final Intent intent = data.getItemAt(0).getIntent();
- // TODO(b/169894807): Properly handle the drop, for now just launch it
- if (isTask) {
- int taskId = intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID);
- try {
- ActivityTaskManager.getService().startActivityFromRecents(
- taskId, null);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to launch task", e);
- }
- } else if (isShortcut) {
- try {
- Bundle opts = intent.hasExtra(EXTRA_ACTIVITY_OPTIONS)
- ? intent.getBundleExtra(EXTRA_ACTIVITY_OPTIONS)
- : null;
- LauncherApps launcherApps =
- mContext.getSystemService(LauncherApps.class);
- launcherApps.startShortcut(
- intent.getStringExtra(EXTRA_PACKAGE_NAME),
- intent.getStringExtra(EXTRA_SHORTCUT_ID),
- null /* sourceBounds */, opts,
- intent.getParcelableExtra(EXTRA_USER));
- } catch (ActivityNotFoundException e) {
- Slog.e(TAG, "Failed to launch shortcut", e);
- }
- } else {
- PendingIntent pi = intent.getParcelableExtra(EXTRA_PENDING_INTENT);
- try {
- pi.send();
- } catch (PendingIntent.CanceledException e) {
- Slog.e(TAG, "Failed to launch activity", e);
- }
- }
+ mActiveDragCount--;
+ return pd.dragLayout.drop(event, dragSurface, () -> {
+ if (mActiveDragCount == 0) {
+ // Hide the window if another drag hasn't been started while animating the drop
+ setDropTargetWindowVisibility(pd, View.INVISIBLE);
}
- setDropTargetWindowVisibility(pd, View.INVISIBLE);
- pd.dropTarget.removeView(dragLayout);
-
// Clean up the drag surface
mTransaction.reparent(dragSurface, null);
mTransaction.apply();
@@ -270,9 +220,9 @@
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
"Set drop target window visibility: displayId=%d visibility=%d",
pd.displayId, visibility);
- pd.dropTarget.setVisibility(visibility);
+ pd.rootView.setVisibility(visibility);
if (visibility == View.VISIBLE) {
- pd.dropTarget.requestApplyInsets();
+ pd.rootView.requestApplyInsets();
}
}
@@ -291,13 +241,17 @@
final int displayId;
final Context context;
final WindowManager wm;
- final FrameLayout dropTarget;
+ final FrameLayout rootView;
+ final DragLayout dragLayout;
- PerDisplay(int dispId, Context c, WindowManager w, FrameLayout l) {
+ boolean isHandlingDrag;
+
+ PerDisplay(int dispId, Context c, WindowManager w, FrameLayout rv, DragLayout dl) {
displayId = dispId;
context = c;
wm = w;
- dropTarget = l;
+ rootView = rv;
+ dragLayout = dl;
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
new file mode 100644
index 0000000..25890bc
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.draganddrop;
+
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.ClipDescription.EXTRA_ACTIVITY_OPTIONS;
+import static android.content.ClipDescription.EXTRA_PENDING_INTENT;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
+import static android.content.Intent.EXTRA_PACKAGE_NAME;
+import static android.content.Intent.EXTRA_SHORTCUT_ID;
+import static android.content.Intent.EXTRA_TASK_ID;
+import static android.content.Intent.EXTRA_USER;
+
+import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_FULLSCREEN;
+import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
+import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
+import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
+import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
+
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.IActivityTaskManager;
+import android.app.PendingIntent;
+import android.app.WindowConfiguration;
+import android.content.ActivityNotFoundException;
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.LauncherApps;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.splitscreen.SplitScreen;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The policy for handling drag and drop operations to shell.
+ */
+public class DragAndDropPolicy {
+
+ private static final String TAG = DragAndDropPolicy.class.getSimpleName();
+
+ private final Context mContext;
+ private final IActivityTaskManager mIActivityTaskManager;
+ private final Starter mStarter;
+ private final SplitScreen mSplitScreen;
+ private final ArrayList<DragAndDropPolicy.Target> mTargets = new ArrayList<>();
+
+ private DragSession mSession;
+
+ public DragAndDropPolicy(Context context, SplitScreen splitScreen) {
+ this(context, ActivityTaskManager.getService(), splitScreen,
+ new DefaultStarter(context, splitScreen));
+ }
+
+ @VisibleForTesting
+ DragAndDropPolicy(Context context, IActivityTaskManager activityTaskManager,
+ SplitScreen splitScreen, Starter starter) {
+ mContext = context;
+ mIActivityTaskManager = activityTaskManager;
+ mSplitScreen = splitScreen;
+ mStarter = starter;
+ }
+
+ /**
+ * Starts a new drag session with the given initial drag data.
+ */
+ void start(DisplayLayout displayLayout, ClipData data) {
+ mSession = new DragSession(mContext, mIActivityTaskManager, displayLayout, data);
+ // TODO(b/169894807): Also update the session data with task stack changes
+ mSession.update();
+ }
+
+ /**
+ * Returns the target's regions based on the current state of the device and display.
+ */
+ @NonNull
+ ArrayList<Target> getTargets(Insets insets) {
+ mTargets.clear();
+ if (mSession == null) {
+ // Return early if this isn't an app drag
+ return mTargets;
+ }
+
+ final int w = mSession.displayLayout.width();
+ final int h = mSession.displayLayout.height();
+ final int iw = w - insets.left - insets.right;
+ final int ih = h - insets.top - insets.bottom;
+ final int l = insets.left;
+ final int t = insets.top;
+ final boolean isVerticalSplit = mSession.isPhone && !mSession.displayLayout.isLandscape();
+ if (mSession.dragItemSupportsSplitscreen
+ && mSession.runningTaskActType == ACTIVITY_TYPE_STANDARD
+ && mSession.runningTaskWinMode == WINDOWING_MODE_FULLSCREEN
+ && mSession.runningTaskIsResizeable) {
+ // Allow splitting when there is a fullscreen standard activity running
+ if (isVerticalSplit) {
+ // TODO(b/169894807): For now, only allow splitting to the right/bottom until we
+ // have split pairs
+ mTargets.add(new Target(TYPE_FULLSCREEN,
+ new Rect(0, 0, w, h / 2),
+ new Rect(l, t, l + iw, t + ih),
+ new Rect(0, 0, w, h)));
+ mTargets.add(new Target(TYPE_SPLIT_BOTTOM,
+ new Rect(0, h / 2, w, h),
+ new Rect(l, t + ih / 2, l + iw, t + ih),
+ new Rect(0, h / 2, w, h)));
+ } else {
+ mTargets.add(new Target(TYPE_FULLSCREEN,
+ new Rect(0, 0, w / 2, h),
+ new Rect(l, t, l + iw, t + ih),
+ new Rect(0, 0, w, h)));
+ mTargets.add(new Target(TYPE_SPLIT_RIGHT,
+ new Rect(w / 2, 0, w, h),
+ new Rect(l + iw / 2, t, l + iw, t + ih),
+ new Rect(w / 2, 0, w, h)));
+ }
+ } else if (mSession.dragItemSupportsSplitscreen
+ && mSplitScreen != null
+ && mSplitScreen.isDividerVisible()) {
+ // Already split, allow replacing existing split task
+ // TODO(b/169894807): For now, only allow replacing the non-primary task until we have
+ // split pairs
+ final Rect secondarySplitRawBounds =
+ mSplitScreen.getDividerView().getNonMinimizedSplitScreenSecondaryBounds();
+ final Rect secondarySplitBounds = new Rect(secondarySplitRawBounds);
+ secondarySplitBounds.intersect(new Rect(l, t, l + iw, t + ih));
+ if (isVerticalSplit) {
+ mTargets.add(new Target(TYPE_FULLSCREEN,
+ new Rect(0, 0, w, secondarySplitRawBounds.top),
+ new Rect(l, t, l + iw, t + ih),
+ new Rect(0, 0, w, secondarySplitRawBounds.top)));
+ } else {
+ mTargets.add(new Target(TYPE_FULLSCREEN,
+ new Rect(0, 0, secondarySplitRawBounds.left, h),
+ new Rect(l, t, l + iw, t + ih),
+ new Rect(0, 0, w, h)));
+ }
+ mTargets.add(new Target(isVerticalSplit ? TYPE_SPLIT_BOTTOM : TYPE_SPLIT_RIGHT,
+ new Rect(secondarySplitBounds),
+ new Rect(secondarySplitBounds),
+ new Rect(secondarySplitBounds)));
+ } else {
+ // Otherwise only show the fullscreen target
+ mTargets.add(new Target(TYPE_FULLSCREEN,
+ new Rect(0, 0, w, h),
+ new Rect(l, t, l + iw, t + ih),
+ new Rect(0, 0, w, h)));
+ }
+ return mTargets;
+ }
+
+ /**
+ * Returns the target at the given position based on the targets previously calculated.
+ */
+ @Nullable
+ Target getTargetAtLocation(int x, int y) {
+ for (int i = mTargets.size() - 1; i >= 0; i--) {
+ DragAndDropPolicy.Target t = mTargets.get(i);
+ if (t.hitRegion.contains(x, y)) {
+ return t;
+ }
+ }
+ return null;
+ }
+
+ @VisibleForTesting
+ void handleDrop(Target target, ClipData data) {
+ if (target == null || !mTargets.contains(target)) {
+ return;
+ }
+
+ final ClipDescription description = data.getDescription();
+ final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK);
+ final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT);
+ final Intent dragData = mSession.dragData;
+
+ if (target.type == TYPE_FULLSCREEN) {
+ if (mSplitScreen != null && mSplitScreen.isDividerVisible()) {
+ // If in split, remove split and launch fullscreen
+ mStarter.exitSplitScreen(mSession.runningTaskId);
+ } else {
+ // Not in split, fall through to launch
+ }
+ } else {
+ if (mSplitScreen != null && mSplitScreen.isDividerVisible()) {
+ // Split is already visible, just replace the task
+ // TODO(b/169894807): Since we only allow replacing the non-primary target above
+ // just fall through and start the activity
+ } else {
+ // Not in split, enter split now
+ mStarter.enterSplitScreen(mSession.runningTaskId,
+ target.type == TYPE_SPLIT_LEFT || target.type == TYPE_SPLIT_TOP);
+ }
+ }
+
+ Bundle opts = dragData.hasExtra(EXTRA_ACTIVITY_OPTIONS)
+ ? dragData.getBundleExtra(EXTRA_ACTIVITY_OPTIONS)
+ : null;
+ if (isTask) {
+ mStarter.startTask(dragData.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID), opts);
+ } else if (isShortcut) {
+ mStarter.startShortcut(dragData.getStringExtra(EXTRA_PACKAGE_NAME),
+ dragData.getStringExtra(EXTRA_SHORTCUT_ID),
+ opts, dragData.getParcelableExtra(EXTRA_USER));
+ } else {
+ mStarter.startIntent(dragData.getParcelableExtra(EXTRA_PENDING_INTENT), opts);
+ }
+ }
+
+ /**
+ * Per-drag session data.
+ */
+ private static class DragSession {
+ private final Context mContext;
+ private final IActivityTaskManager mIActivityTaskManager;
+ private final ClipData mInitialDragData;
+
+ final DisplayLayout displayLayout;
+ Intent dragData;
+ int runningTaskId;
+ @WindowConfiguration.WindowingMode
+ int runningTaskWinMode = WINDOWING_MODE_UNDEFINED;
+ @WindowConfiguration.ActivityType
+ int runningTaskActType = ACTIVITY_TYPE_STANDARD;
+ boolean runningTaskIsResizeable;
+ boolean dragItemSupportsSplitscreen;
+ boolean isPhone;
+
+ DragSession(Context context, IActivityTaskManager activityTaskManager,
+ DisplayLayout dispLayout, ClipData data) {
+ mContext = context;
+ mIActivityTaskManager = activityTaskManager;
+ mInitialDragData = data;
+ displayLayout = dispLayout;
+ }
+
+ /**
+ * Updates the session data based on the current state of the system.
+ */
+ void update() {
+ final ClipDescription description = mInitialDragData.getDescription();
+ try {
+ List<ActivityManager.RunningTaskInfo> tasks =
+ mIActivityTaskManager.getFilteredTasks(1,
+ false /* filterOnlyVisibleRecents */);
+ if (!tasks.isEmpty()) {
+ final ActivityManager.RunningTaskInfo task = tasks.get(0);
+ runningTaskWinMode = task.getWindowingMode();
+ runningTaskActType = task.getActivityType();
+ runningTaskId = task.taskId;
+ runningTaskIsResizeable = task.isResizeable;
+ }
+ } catch (RemoteException e) {
+ // Fall through
+ }
+
+ final ActivityInfo info = mInitialDragData.getItemAt(0).getActivityInfo();
+ dragItemSupportsSplitscreen = info == null
+ || ActivityInfo.isResizeableMode(info.resizeMode);
+ isPhone = mContext.getResources().getConfiguration().smallestScreenWidthDp < 600;
+ dragData = mInitialDragData.getItemAt(0).getIntent();
+ }
+ }
+
+ /**
+ * Interface for actually committing the task launches.
+ */
+ @VisibleForTesting
+ interface Starter {
+ void startTask(int taskId, Bundle activityOptions);
+ void startShortcut(String packageName, String shortcutId, Bundle activityOptions,
+ UserHandle user);
+ void startIntent(PendingIntent intent, Bundle activityOptions);
+ void enterSplitScreen(int taskId, boolean leftOrTop);
+ void exitSplitScreen(int taskId);
+ }
+
+ /**
+ * Default implementation of the starter which calls through the system services to launch the
+ * tasks.
+ */
+ private static class DefaultStarter implements Starter {
+ private final Context mContext;
+ private final SplitScreen mSplitScreen;
+
+ public DefaultStarter(Context context, SplitScreen splitScreen) {
+ mContext = context;
+ mSplitScreen = splitScreen;
+ }
+
+ @Override
+ public void startTask(int taskId, Bundle activityOptions) {
+ try {
+ ActivityTaskManager.getService().startActivityFromRecents(taskId, null);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to launch task", e);
+ }
+ }
+
+ @Override
+ public void startShortcut(String packageName, String shortcutId, Bundle activityOptions,
+ UserHandle user) {
+ try {
+ LauncherApps launcherApps =
+ mContext.getSystemService(LauncherApps.class);
+ launcherApps.startShortcut(packageName, shortcutId, null /* sourceBounds */,
+ activityOptions, user);
+ } catch (ActivityNotFoundException e) {
+ Slog.e(TAG, "Failed to launch shortcut", e);
+ }
+ }
+
+ @Override
+ public void startIntent(PendingIntent intent, Bundle activityOptions) {
+ try {
+ intent.send(null, 0, null, null, null, null, activityOptions);
+ } catch (PendingIntent.CanceledException e) {
+ Slog.e(TAG, "Failed to launch activity", e);
+ }
+ }
+
+ @Override
+ public void enterSplitScreen(int taskId, boolean leftOrTop) {
+ mSplitScreen.splitPrimaryTask();
+ }
+
+ @Override
+ public void exitSplitScreen(int taskId) {
+ mSplitScreen.dismissSplitToPrimaryTask();
+ }
+ }
+
+ /**
+ * Represents a drop target.
+ */
+ static class Target {
+ static final int TYPE_FULLSCREEN = 0;
+ static final int TYPE_SPLIT_LEFT = 1;
+ static final int TYPE_SPLIT_TOP = 2;
+ static final int TYPE_SPLIT_RIGHT = 3;
+ static final int TYPE_SPLIT_BOTTOM = 4;
+ @IntDef(value = {
+ TYPE_FULLSCREEN,
+ TYPE_SPLIT_LEFT,
+ TYPE_SPLIT_TOP,
+ TYPE_SPLIT_RIGHT,
+ TYPE_SPLIT_BOTTOM
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface Type{}
+
+ final @Type int type;
+
+ // The actual hit region for this region
+ final Rect hitRegion;
+ // The approximate visual region for where the task will start
+ final Rect drawRegion;
+ // The
+ final Rect dropTargetBounds;
+
+ public Target(@Type int t, Rect hit, Rect draw, Rect drop) {
+ type = t;
+ hitRegion = hit;
+ drawRegion = draw;
+ dropTargetBounds = drop;
+ }
+
+ @Override
+ public String toString() {
+ return "Target {hit=" + hitRegion + " drop=" + dropTargetBounds + "}";
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index b70036b..fa857cdd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -24,6 +24,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
+import android.content.ClipData;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Insets;
@@ -52,20 +53,19 @@
*/
public class DragLayout extends View {
- private final DisplayLayout mDisplayLayout;
- private final SplitScreen mSplitScreen;
+ private final DragAndDropPolicy mPolicy;
- private final ArrayList<Target> mTargets = new ArrayList<>();
- private Target mCurrentTarget = null;
+ private DragAndDropPolicy.Target mCurrentTarget = null;
private DropOutlineDrawable mDropOutline;
private int mDisplayMargin;
private Insets mInsets = Insets.NONE;
+
+ private boolean mIsShowing;
private boolean mHasDropped;
- public DragLayout(Context context, DisplayLayout displayLayout, SplitScreen splitscreen) {
+ public DragLayout(Context context, SplitScreen splitscreen) {
super(context);
- mDisplayLayout = displayLayout;
- mSplitScreen = splitscreen;
+ mPolicy = new DragAndDropPolicy(context, splitscreen);
mDisplayMargin = context.getResources().getDimensionPixelSize(
R.dimen.drop_layout_display_margin);
mDropOutline = new DropOutlineDrawable(context);
@@ -76,7 +76,7 @@
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
mInsets = insets.getInsets(Type.systemBars() | Type.displayCutout());
- calculateDropTargets();
+ recomputeDropTargets();
return super.onApplyWindowInsets(insets);
}
@@ -100,66 +100,41 @@
return mHasDropped;
}
- public void show(DragEvent event) {
- calculateDropTargets();
+ public void prepare(DisplayLayout displayLayout, ClipData initialData) {
+ mPolicy.start(displayLayout, initialData);
mHasDropped = false;
+ mCurrentTarget = null;
}
- private void calculateDropTargets() {
- // Calculate all the regions based on split and landscape portrait
- // TODO: Filter based on clip data
- final float SIDE_MARGIN_PCT = 0.3f;
- final int w = mDisplayLayout.width();
- final int h = mDisplayLayout.height();
- final int iw = w - mInsets.left - mInsets.right;
- final int ih = h - mInsets.top - mInsets.bottom;
- final int l = mInsets.left;
- final int t = mInsets.top;
- final int r = mInsets.right;
- final int b = mInsets.bottom;
- mTargets.clear();
-
- // Left split
- addTarget(new Target(
- new Rect(0, 0,
- (int) (w * SIDE_MARGIN_PCT), h),
- new Rect(l + mDisplayMargin, t + mDisplayMargin,
- l + iw / 2 - mDisplayMargin, t + ih - mDisplayMargin),
- new Rect(0, 0, w / 2, h)));
-
- // Fullscreen
- addTarget(new Target(
- new Rect((int) (w * SIDE_MARGIN_PCT), 0,
- w - (int) (w * SIDE_MARGIN_PCT), h),
- new Rect(l + mDisplayMargin, t + mDisplayMargin,
- l + iw - mDisplayMargin, t + ih - mDisplayMargin),
- new Rect(0, 0, w, h)));
-
- // Right split
- addTarget(new Target(
- new Rect(w - (int) (w * SIDE_MARGIN_PCT), 0,
- w, h),
- new Rect(l + iw / 2 + mDisplayMargin, t + mDisplayMargin,
- l + iw - mDisplayMargin, t + ih - mDisplayMargin),
- new Rect(w / 2, 0, w, h)));
+ public void show() {
+ mIsShowing = true;
+ recomputeDropTargets();
}
- private void addTarget(Target t) {
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Add target: %s", t);
- mTargets.add(t);
+ /**
+ * Recalculates the drop targets based on the current policy.
+ */
+ private void recomputeDropTargets() {
+ if (!mIsShowing) {
+ return;
+ }
+ final ArrayList<DragAndDropPolicy.Target> targets = mPolicy.getTargets(mInsets);
+ for (int i = 0; i < targets.size(); i++) {
+ final DragAndDropPolicy.Target target = targets.get(i);
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Add target: %s", target);
+ // Inset the draw region by a little bit
+ target.drawRegion.inset(mDisplayMargin, mDisplayMargin);
+ }
}
+ /**
+ * Updates the visible drop target as the user drags.
+ */
public void update(DragEvent event) {
// Find containing region, if the same as mCurrentRegion, then skip, otherwise, animate the
// visibility of the current region
- Target target = null;
- for (int i = mTargets.size() - 1; i >= 0; i--) {
- Target t = mTargets.get(i);
- if (t.hitRegion.contains((int) event.getX(), (int) event.getY())) {
- target = t;
- break;
- }
- }
+ DragAndDropPolicy.Target target = mPolicy.getTargetAtLocation(
+ (int) event.getX(), (int) event.getY());
if (target != null && mCurrentTarget != target) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Current target: %s", target);
Interpolator boundsInterpolator = FAST_OUT_SLOW_IN;
@@ -175,7 +150,11 @@
}
}
+ /**
+ * Hides the drag layout and animates out the visible drop targets.
+ */
public void hide(DragEvent event, Runnable hideCompleteCallback) {
+ mIsShowing = false;
ObjectAnimator alphaAnimator = mDropOutline.startVisibilityAnimation(false, LINEAR);
ObjectAnimator boundsAnimator = null;
if (mCurrentTarget != null) {
@@ -199,50 +178,19 @@
mCurrentTarget = null;
}
+ /**
+ * Handles the drop onto a target and animates out the visible drop targets.
+ */
public boolean drop(DragEvent event, SurfaceControl dragSurface,
- Consumer<Rect> dropCompleteCallback) {
+ Runnable dropCompleteCallback) {
+ final boolean handledDrop = mCurrentTarget != null;
mHasDropped = true;
+
+ // Process the drop
+ mPolicy.handleDrop(mCurrentTarget, event.getClipData());
+
// TODO(b/169894807): Coordinate with dragSurface
- final Rect dropRegion = mCurrentTarget != null
- ? mCurrentTarget.dropTargetBounds
- : null;
-
- ObjectAnimator alphaAnimator = mDropOutline.startVisibilityAnimation(false, LINEAR);
- ObjectAnimator boundsAnimator = null;
- if (dropRegion != null) {
- Rect finalBounds = new Rect(mCurrentTarget.drawRegion);
- finalBounds.inset(mDisplayMargin, mDisplayMargin);
- mDropOutline.startBoundsAnimation(finalBounds, FAST_OUT_LINEAR_IN);
- }
-
- if (dropCompleteCallback != null) {
- ObjectAnimator lastAnim = boundsAnimator != null
- ? boundsAnimator
- : alphaAnimator;
- lastAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- dropCompleteCallback.accept(dropRegion);
- }
- });
- }
- return dropRegion != null;
- }
-
- private static class Target {
- final Rect hitRegion;
- final Rect drawRegion;
- final Rect dropTargetBounds;
-
- public Target(Rect hit, Rect draw, Rect drop) {
- hitRegion = hit;
- drawRegion = draw;
- dropTargetBounds = drop;
- }
-
- @Override
- public String toString() {
- return "Target {hit=" + hitRegion + " drop=" + dropTargetBounds + "}";
- }
+ hide(event, dropCompleteCallback);
+ return handledDrop;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java
index 08edc2f..64f7be5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java
@@ -40,7 +40,7 @@
import com.android.wm.shell.R;
/**
- * Drawable to draw the region of the
+ * Drawable to draw the region that the target will have once it is dropped.
*/
public class DropOutlineDrawable extends Drawable {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
index fc523ae..c4ce2cf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
@@ -42,6 +42,7 @@
private ComponentName mLastPipComponentName;
private final DisplayInfo mDisplayInfo = new DisplayInfo();
private final DisplayLayout mDisplayLayout = new DisplayLayout();
+ private final @NonNull AnimatingBoundsState mAnimatingBoundsState = new AnimatingBoundsState();
/**
* Set the current PIP bounds.
@@ -151,6 +152,60 @@
mPipReentryState = null;
}
+ public AnimatingBoundsState getAnimatingBoundsState() {
+ return mAnimatingBoundsState;
+ }
+
+ /** Source of truth for the current animation bounds of PIP. */
+ public static class AnimatingBoundsState {
+ /** The bounds used when PIP is being dragged or animated. */
+ private final Rect mTemporaryBounds = new Rect();
+ /** The destination bounds to which PIP is animating. */
+ private final Rect mAnimatingToBounds = new Rect();
+
+ /** Whether PIP is being dragged or animated (e.g. resizing, in fling, etc). */
+ public boolean isAnimating() {
+ return !mTemporaryBounds.isEmpty();
+ }
+
+ /** Set the temporary bounds used to represent the drag or animation bounds of PIP. */
+ public void setTemporaryBounds(Rect bounds) {
+ mTemporaryBounds.set(bounds);
+ }
+
+ /** Set the bounds to which PIP is animating. */
+ public void setAnimatingToBounds(Rect bounds) {
+ mAnimatingToBounds.set(bounds);
+ }
+
+ /** Called when all ongoing dragging and animation operations have ended. */
+ public void onAllAnimationsEnded() {
+ mTemporaryBounds.setEmpty();
+ }
+
+ /** Called when an ongoing physics animation has ended. */
+ public void onPhysicsAnimationEnded() {
+ mAnimatingToBounds.setEmpty();
+ }
+
+ /** Returns the temporary animation bounds. */
+ public Rect getTemporaryBounds() {
+ return mTemporaryBounds;
+ }
+
+ /** Returns the destination bounds to which PIP is currently animating. */
+ public Rect getAnimatingToBounds() {
+ return mAnimatingToBounds;
+ }
+
+ void dump(PrintWriter pw, String prefix) {
+ final String innerPrefix = prefix + " ";
+ pw.println(prefix + AnimatingBoundsState.class.getSimpleName());
+ pw.println(innerPrefix + "mTemporaryBounds=" + mTemporaryBounds);
+ pw.println(innerPrefix + "mAnimatingToBounds=" + mAnimatingToBounds);
+ }
+ }
+
static final class PipReentryState {
private static final String TAG = PipReentryState.class.getSimpleName();
@@ -190,10 +245,12 @@
pw.println(innerPrefix + "mAspectRatio=" + mAspectRatio);
pw.println(innerPrefix + "mDisplayInfo=" + mDisplayInfo);
pw.println(innerPrefix + "mDisplayLayout=" + mDisplayLayout);
+ pw.println(innerPrefix + "mIsStashed=" + mIsStashed);
if (mPipReentryState == null) {
pw.println(innerPrefix + "mPipReentryState=null");
} else {
mPipReentryState.dump(pw, innerPrefix);
}
+ mAnimatingBoundsState.dump(pw, innerPrefix);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 833924c..39772fb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -135,6 +135,7 @@
private final Handler mUpdateHandler;
private final PipBoundsState mPipBoundsState;
private final PipBoundsHandler mPipBoundsHandler;
+ // TODO(b/172286265): Remove dependency on .pip.PHONE.PipMenuActivityController
private final PipMenuActivityController mMenuActivityController;
private final PipAnimationController mPipAnimationController;
private final PipUiEventLogger mPipUiEventLoggerLogger;
@@ -946,10 +947,9 @@
mSurfaceTransactionHelper
.crop(tx, mLeash, destinationBounds)
.round(tx, mLeash, mState.isInPip());
- if (mMenuActivityController.isMenuVisible()) {
- runOnMainHandler(() -> {
- mMenuActivityController.resizePipMenu(mLeash, tx, destinationBounds);
- });
+ if (mMenuActivityController != null && mMenuActivityController.isMenuVisible()) {
+ runOnMainHandler(() ->
+ mMenuActivityController.resizePipMenu(mLeash, tx, destinationBounds));
} else {
tx.apply();
}
@@ -973,10 +973,9 @@
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
mSurfaceTransactionHelper.scale(tx, mLeash, startBounds, destinationBounds);
- if (mMenuActivityController.isMenuVisible()) {
- runOnMainHandler(() -> {
- mMenuActivityController.movePipMenu(mLeash, tx, destinationBounds);
- });
+ if (mMenuActivityController != null && mMenuActivityController.isMenuVisible()) {
+ runOnMainHandler(() ->
+ mMenuActivityController.movePipMenu(mLeash, tx, destinationBounds));
} else {
tx.apply();
}
@@ -993,7 +992,8 @@
if (direction == TRANSITION_DIRECTION_REMOVE_STACK) {
removePipImmediately();
return;
- } else if (isInPipDirection(direction) && type == ANIM_TYPE_ALPHA) {
+ } else if (isInPipDirection(direction) && type == ANIM_TYPE_ALPHA
+ && mMenuActivityController != null) {
// TODO: Synchronize this correctly in #applyEnterPipSyncTransaction
finishResizeForMenu(destinationBounds);
return;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index 9247c68..83cd63c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -42,7 +42,6 @@
import com.android.wm.shell.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip.PipTaskOrganizer;
-import java.io.PrintWriter;
import java.util.function.Consumer;
import kotlin.Unit;
@@ -80,20 +79,6 @@
/** The region that all of PIP must stay within. */
private final Rect mFloatingAllowedArea = new Rect();
- /**
- * Temporary bounds used when PIP is being dragged or animated. These bounds are applied to PIP
- * using {@link PipTaskOrganizer#scheduleUserResizePip}, so that we can animate shrinking into
- * and expanding out of the magnetic dismiss target.
- *
- * Once PIP is done being dragged or animated, we set {@link #mBounds} equal to these temporary
- * bounds, and call {@link PipTaskOrganizer#scheduleFinishResizePip} to 'officially' move PIP to
- * its new bounds.
- */
- private final Rect mTemporaryBounds = new Rect();
-
- /** The destination bounds to which PIP is animating. */
- private final Rect mAnimatingToBounds = new Rect();
-
private int mStashOffset = 0;
/** Coordinator instance for resolving conflicts with other floating content. */
@@ -108,15 +93,15 @@
});
/**
- * PhysicsAnimator instance for animating {@link #mTemporaryBounds} using physics animations.
+ * PhysicsAnimator instance for animating {@link PipBoundsState#getAnimatingBoundsState()}
+ * using physics animations.
*/
- private PhysicsAnimator<Rect> mTemporaryBoundsPhysicsAnimator = PhysicsAnimator.getInstance(
- mTemporaryBounds);
+ private final PhysicsAnimator<Rect> mTemporaryBoundsPhysicsAnimator;
private MagnetizedObject<Rect> mMagnetizedPip;
/**
- * Update listener that resizes the PIP to {@link #mTemporaryBounds}.
+ * Update listener that resizes the PIP to {@link PipBoundsState#getAnimatingBoundsState()}.
*/
private final PhysicsAnimator.UpdateListener<Rect> mResizePipUpdateListener;
@@ -189,14 +174,17 @@
mSnapAlgorithm = snapAlgorithm;
mFloatingContentCoordinator = floatingContentCoordinator;
mPipTaskOrganizer.registerPipTransitionCallback(mPipTransitionCallback);
+ mTemporaryBoundsPhysicsAnimator = PhysicsAnimator.getInstance(
+ mPipBoundsState.getAnimatingBoundsState().getTemporaryBounds());
mTemporaryBoundsPhysicsAnimator.setCustomAnimationHandler(
mSfAnimationHandlerThreadLocal.get());
+
reloadResources();
mResizePipUpdateListener = (target, values) -> {
- if (!mTemporaryBounds.isEmpty()) {
- mPipTaskOrganizer.scheduleUserResizePip(
- getBounds(), mTemporaryBounds, null);
+ if (mPipBoundsState.getAnimatingBoundsState().isAnimating()) {
+ mPipTaskOrganizer.scheduleUserResizePip(getBounds(),
+ mPipBoundsState.getAnimatingBoundsState().getTemporaryBounds(), null);
}
};
}
@@ -209,7 +197,8 @@
@NonNull
@Override
public Rect getFloatingBoundsOnScreen() {
- return !mAnimatingToBounds.isEmpty() ? mAnimatingToBounds : getBounds();
+ return !mPipBoundsState.getAnimatingBoundsState().getAnimatingToBounds().isEmpty()
+ ? mPipBoundsState.getAnimatingBoundsState().getAnimatingToBounds() : getBounds();
}
@NonNull
@@ -227,18 +216,14 @@
* Synchronizes the current bounds with the pinned stack, cancelling any ongoing animations.
*/
void synchronizePinnedStackBounds() {
- cancelAnimations();
- mTemporaryBounds.setEmpty();
+ cancelPhysicsAnimation();
+ mPipBoundsState.getAnimatingBoundsState().onAllAnimationsEnded();
if (mPipTaskOrganizer.isInPip()) {
mFloatingContentCoordinator.onContentMoved(this);
}
}
- boolean isAnimating() {
- return mTemporaryBoundsPhysicsAnimator.isRunning();
- }
-
/**
* Tries to move the pinned stack to the given {@param bounds}.
*/
@@ -261,14 +246,14 @@
if (!mSpringingToTouch) {
// If we are moving PIP directly to the touch event locations, cancel any animations and
// move PIP to the given bounds.
- cancelAnimations();
+ cancelPhysicsAnimation();
if (!isDragging) {
resizePipUnchecked(toBounds);
mPipBoundsState.setBounds(toBounds);
} else {
- mTemporaryBounds.set(toBounds);
- mPipTaskOrganizer.scheduleUserResizePip(getBounds(), mTemporaryBounds,
+ mPipBoundsState.getAnimatingBoundsState().setTemporaryBounds(toBounds);
+ mPipTaskOrganizer.scheduleUserResizePip(getBounds(), toBounds,
(Rect newBounds) -> {
mMainHandler.post(() -> {
mMenuController.updateMenuLayout(newBounds);
@@ -303,9 +288,9 @@
final float destinationY = targetCenter.y - (desiredHeight / 2f);
// If we're already in the dismiss target area, then there won't be a move to set the
- // temporary bounds, so just initialize it to the current bounds
- if (mTemporaryBounds.isEmpty()) {
- mTemporaryBounds.set(getBounds());
+ // temporary bounds, so just initialize it to the current bounds.
+ if (!mPipBoundsState.getAnimatingBoundsState().isAnimating()) {
+ mPipBoundsState.getAnimatingBoundsState().setTemporaryBounds(getBounds());
}
mTemporaryBoundsPhysicsAnimator
.spring(FloatProperties.RECT_X, destinationX, velX, mSpringConfig)
@@ -339,7 +324,7 @@
Log.d(TAG, "exitPip: skipAnimation=" + skipAnimation
+ " callers=\n" + Debug.getCallers(5, " "));
}
- cancelAnimations();
+ cancelPhysicsAnimation();
mMenuController.hideMenuWithoutResize();
mPipTaskOrganizer.getUpdateHandler().post(() -> {
mPipTaskOrganizer.exitPip(skipAnimation
@@ -356,7 +341,7 @@
if (DEBUG) {
Log.d(TAG, "removePip: callers=\n" + Debug.getCallers(5, " "));
}
- cancelAnimations();
+ cancelPhysicsAnimation();
mMenuController.hideMenuWithoutResize();
mPipTaskOrganizer.removePip();
}
@@ -383,14 +368,6 @@
}
/**
- * Returns the PIP bounds if we're not animating, or the current, temporary animating bounds
- * otherwise.
- */
- Rect getPossiblyAnimatingBounds() {
- return mTemporaryBounds.isEmpty() ? getBounds() : mTemporaryBounds;
- }
-
- /**
* Flings the PiP to the closest snap target.
*/
void flingToSnapTarget(
@@ -428,9 +405,10 @@
: mMovementBounds.right;
final float xEndValue = velocityX < 0 ? leftEdge : rightEdge;
+
+ final int startValueY = mPipBoundsState.getAnimatingBoundsState().getTemporaryBounds().top;
final float estimatedFlingYEndValue =
- PhysicsAnimator.estimateFlingEndValue(
- mTemporaryBounds.top, velocityY, mFlingConfigY);
+ PhysicsAnimator.estimateFlingEndValue(startValueY, velocityY, mFlingConfigY);
startBoundsAnimator(xEndValue /* toX */, estimatedFlingYEndValue /* toY */,
false /* dismiss */);
@@ -443,7 +421,7 @@
void animateToBounds(Rect bounds, PhysicsAnimator.SpringConfig springConfig) {
if (!mTemporaryBoundsPhysicsAnimator.isRunning()) {
// Animate from the current bounds if we're not already animating.
- mTemporaryBounds.set(getBounds());
+ mPipBoundsState.getAnimatingBoundsState().setTemporaryBounds(getBounds());
}
mTemporaryBoundsPhysicsAnimator
@@ -513,7 +491,7 @@
Log.d(TAG, "animateToOffset: originalBounds=" + originalBounds + " offset=" + offset
+ " callers=\n" + Debug.getCallers(5, " "));
}
- cancelAnimations();
+ cancelPhysicsAnimation();
mPipTaskOrganizer.scheduleOffsetPip(originalBounds, offset, SHIFT_DURATION,
mUpdateBoundsCallback);
}
@@ -521,9 +499,9 @@
/**
* Cancels all existing animations.
*/
- private void cancelAnimations() {
+ private void cancelPhysicsAnimation() {
mTemporaryBoundsPhysicsAnimator.cancel();
- mAnimatingToBounds.setEmpty();
+ mPipBoundsState.getAnimatingBoundsState().onPhysicsAnimationEnded();
mSpringingToTouch = false;
}
@@ -547,22 +525,19 @@
*/
private void startBoundsAnimator(float toX, float toY, boolean dismiss) {
if (!mSpringingToTouch) {
- cancelAnimations();
+ cancelPhysicsAnimation();
}
- // Set animatingToBounds directly to avoid allocating a new Rect, but then call
- // setAnimatingToBounds to run the normal logic for changing animatingToBounds.
- mAnimatingToBounds.set(
+ setAnimatingToBounds(new Rect(
(int) toX,
(int) toY,
(int) toX + getBounds().width(),
- (int) toY + getBounds().height());
- setAnimatingToBounds(mAnimatingToBounds);
+ (int) toY + getBounds().height()));
if (!mTemporaryBoundsPhysicsAnimator.isRunning()) {
mTemporaryBoundsPhysicsAnimator
.addUpdateListener(mResizePipUpdateListener)
- .withEndActions(this::onBoundsAnimationEnd);
+ .withEndActions(this::onBoundsPhysicsAnimationEnd);
}
mTemporaryBoundsPhysicsAnimator.start();
@@ -576,31 +551,34 @@
mDismissalPending = true;
}
- private void onBoundsAnimationEnd() {
+ private void onBoundsPhysicsAnimationEnd() {
+ // The physics animation ended, though we may not necessarily be done animating, such as
+ // when we're still dragging after moving out of the magnetic target.
if (!mDismissalPending
&& !mSpringingToTouch
&& !mMagnetizedPip.getObjectStuckToTarget()) {
- mPipBoundsState.setBounds(mTemporaryBounds);
+ // All animations (including dragging) have actually finished.
+ mPipBoundsState.setBounds(
+ mPipBoundsState.getAnimatingBoundsState().getTemporaryBounds());
+ mPipBoundsState.getAnimatingBoundsState().onAllAnimationsEnded();
if (!mDismissalPending) {
// do not schedule resize if PiP is dismissing, which may cause app re-open to
// mBounds instead of it's normal bounds.
mPipTaskOrganizer.scheduleFinishResizePip(getBounds());
}
- mTemporaryBounds.setEmpty();
}
-
- mAnimatingToBounds.setEmpty();
+ mPipBoundsState.getAnimatingBoundsState().onPhysicsAnimationEnded();
mSpringingToTouch = false;
mDismissalPending = false;
}
/**
- * Notifies the floating coordinator that we're moving, and sets {@link #mAnimatingToBounds} so
+ * Notifies the floating coordinator that we're moving, and sets the animating to bounds so
* we return these bounds from
* {@link FloatingContentCoordinator.FloatingContent#getFloatingBoundsOnScreen()}.
*/
private void setAnimatingToBounds(Rect bounds) {
- mAnimatingToBounds.set(bounds);
+ mPipBoundsState.getAnimatingBoundsState().setAnimatingToBounds(bounds);
mFloatingContentCoordinator.onContentMoved(this);
}
@@ -639,7 +617,8 @@
MagnetizedObject<Rect> getMagnetizedPip() {
if (mMagnetizedPip == null) {
mMagnetizedPip = new MagnetizedObject<Rect>(
- mContext, mTemporaryBounds, FloatProperties.RECT_X, FloatProperties.RECT_Y) {
+ mContext, mPipBoundsState.getAnimatingBoundsState().getTemporaryBounds(),
+ FloatProperties.RECT_X, FloatProperties.RECT_Y) {
@Override
public float getWidth(@NonNull Rect animatedPipBounds) {
return animatedPipBounds.width();
@@ -661,10 +640,4 @@
return mMagnetizedPip;
}
-
- public void dump(PrintWriter pw, String prefix) {
- final String innerPrefix = prefix + " ";
- pw.println(prefix + TAG);
- pw.println(innerPrefix + "mBounds=" + getBounds());
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index d820e77..c04e7e8a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -710,7 +710,7 @@
return;
}
- Rect bounds = mMotionHelper.getPossiblyAnimatingBounds();
+ Rect bounds = getPossiblyAnimatingBounds();
mDelta.set(0f, 0f);
mStartPosition.set(bounds.left, bounds.top);
mMovementWithinDismiss = touchState.getDownTouchPosition().y >= mMovementBounds.bottom;
@@ -747,7 +747,7 @@
mDelta.x += left - lastX;
mDelta.y += top - lastY;
- mTmpBounds.set(mMotionHelper.getPossiblyAnimatingBounds());
+ mTmpBounds.set(getPossiblyAnimatingBounds());
mTmpBounds.offsetTo((int) left, (int) top);
mMotionHelper.movePip(mTmpBounds, true /* isDragging */);
@@ -783,7 +783,7 @@
// Reset the touch state on up before the fling settles
mTouchState.reset();
- final Rect animatingBounds = mMotionHelper.getPossiblyAnimatingBounds();
+ final Rect animatingBounds = getPossiblyAnimatingBounds();
// If User releases the PIP window while it's out of the display bounds, put
// PIP into stashed mode.
if (mEnableStash
@@ -872,6 +872,16 @@
|| mExpandedBounds.height() != mNormalBounds.height();
}
+ /**
+ * Returns the PIP bounds if we're not animating, or the current, temporary animating bounds
+ * otherwise.
+ */
+ Rect getPossiblyAnimatingBounds() {
+ return mPipBoundsState.getAnimatingBoundsState().isAnimating()
+ ? mPipBoundsState.getAnimatingBoundsState().getTemporaryBounds()
+ : mPipBoundsState.getBounds();
+ }
+
public void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
@@ -889,7 +899,6 @@
pw.println(innerPrefix + "mMovementBoundsExtraOffsets=" + mMovementBoundsExtraOffsets);
mPipBoundsHandler.dump(pw, innerPrefix);
mTouchState.dump(pw, innerPrefix);
- mMotionHelper.dump(pw, innerPrefix);
if (mPipResizeGestureHandler != null) {
mPipResizeGestureHandler.dump(pw, innerPrefix);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index 985dff2..d117673 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -83,4 +83,9 @@
* @return {@code true} if it successes to split the primary task.
*/
boolean splitPrimaryTask();
+
+ /**
+ * Exits the split to make the primary task fullscreen.
+ */
+ void dismissSplitToPrimaryTask();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 8b616e8..341a459 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -501,6 +501,11 @@
}
}
+ @Override
+ public void dismissSplitToPrimaryTask() {
+ startDismissSplit(true /* toPrimaryTask */);
+ }
+
/** Notifies the bounds of split screen changed. */
void notifyBoundsChanged(Rect secondaryWindowBounds, Rect secondaryWindowInsets) {
synchronized (mBoundsChangedListeners) {
@@ -519,8 +524,8 @@
mHomeStackResizable = mWindowManagerProxy.applyEnterSplit(mSplits, mSplitLayout);
}
- void startDismissSplit() {
- mWindowManagerProxy.applyDismissSplit(mSplits, mSplitLayout, true /* dismissOrMaximize */);
+ void startDismissSplit(boolean toPrimaryTask) {
+ mWindowManagerProxy.applyDismissSplit(mSplits, mSplitLayout, !toPrimaryTask);
updateVisibility(false /* visible */);
mMinimized = false;
// Resets divider bar position to undefined, so new divider bar will apply default position
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java
index f709fed..64e9d66 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java
@@ -271,7 +271,7 @@
Log.d(TAG, " was in split, so this means leave it "
+ mPrimary.topActivityType + " " + mSecondary.topActivityType);
}
- mSplitScreenController.startDismissSplit();
+ mSplitScreenController.startDismissSplit(false /* toPrimaryTask */);
} else if (!primaryIsEmpty && primaryWasEmpty && secondaryWasEmpty) {
// Wasn't in split-mode (both were empty), but now that the primary split is
// populated, we should fully enter split by moving everything else into secondary.
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
index 8b2f668..58fc90e 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
@@ -32,8 +32,19 @@
<!-- Workaround grant runtime permission exception from b/152733071 -->
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
<uses-permission android:name="android.permission.READ_LOGS"/>
+ <!-- Force-stop test apps -->
+ <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/>
<application>
<uses-library android:name="android.test.runner"/>
+
+ <service android:name=".NotificationListener"
+ android:exported="true"
+ android:label="WMShellTestsNotificationListenerService"
+ android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
+ <intent-filter>
+ <action android:name="android.service.notification.NotificationListenerService" />
+ </intent-filter>
+ </service>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
new file mode 100644
index 0000000..ef0390f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.flicker
+
+import android.content.ComponentName
+
+const val IME_WINDOW_NAME = "InputMethod"
+const val PIP_WINDOW_NAME = "PipMenuActivity"
+
+// Test App
+const val TEST_APP_PACKAGE_NAME = "com.android.wm.shell.flicker.testapp"
+// Test App > Pip Activity
+val TEST_APP_PIP_ACTIVITY_COMPONENT_NAME: ComponentName = ComponentName.createRelative(
+ TEST_APP_PACKAGE_NAME, ".PipActivity")
+const val TEST_APP_PIP_ACTIVITY_LABEL = "PipApp"
+const val TEST_APP_PIP_ACTIVITY_WINDOW_NAME = "PipActivity"
+// Test App > Ime Activity
+val TEST_APP_IME_ACTIVITY_COMPONENT_NAME: ComponentName = ComponentName.createRelative(
+ TEST_APP_PACKAGE_NAME, ".ImeActivity")
+const val TEST_APP_IME_ACTIVITY_LABEL = "ImeApp"
+
+const val SYSTEM_UI_PACKAGE_NAME = "com.android.systemui"
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt
index 99f824b..75b55c1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker
+import android.content.pm.PackageManager
import android.os.RemoteException
import android.os.SystemClock
import android.platform.helpers.IAppHelper
@@ -41,6 +42,9 @@
val uiDevice by lazy {
UiDevice.getInstance(instrumentation)
}
+ val packageManager: PackageManager by lazy {
+ instrumentation.context.getPackageManager()
+ }
/**
* Build a test tag for the test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NotificationListener.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NotificationListener.kt
new file mode 100644
index 0000000..5c7ec30
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NotificationListener.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.flicker
+
+import android.service.notification.NotificationListenerService
+import android.service.notification.StatusBarNotification
+import android.util.Log
+import com.android.compatibility.common.util.SystemUtil.runShellCommand
+
+class NotificationListener : NotificationListenerService() {
+ private val notifications: MutableMap<Any, StatusBarNotification> = mutableMapOf()
+
+ override fun onNotificationPosted(sbn: StatusBarNotification) {
+ if (DEBUG) Log.d(TAG, "onNotificationPosted: $sbn")
+ notifications[sbn.key] = sbn
+ }
+
+ override fun onNotificationRemoved(sbn: StatusBarNotification) {
+ if (DEBUG) Log.d(TAG, "onNotificationRemoved: $sbn")
+ notifications.remove(sbn.key)
+ }
+
+ override fun onListenerConnected() {
+ if (DEBUG) Log.d(TAG, "onListenerConnected")
+ instance = this
+ }
+
+ override fun onListenerDisconnected() {
+ if (DEBUG) Log.d(TAG, "onListenerDisconnected")
+ instance = null
+ notifications.clear()
+ }
+
+ companion object {
+ private const val DEBUG = false
+ private const val TAG = "WMShellFlickerTests_NotificationListener"
+
+ private const val CMD_NOTIFICATION_ALLOW_LISTENER = "cmd notification allow_listener %s"
+ private const val CMD_NOTIFICATION_DISALLOW_LISTENER =
+ "cmd notification disallow_listener %s"
+ private const val COMPONENT_NAME = "com.android.wm.shell.flicker/.NotificationListener"
+
+ private var instance: NotificationListener? = null
+
+ fun startNotificationListener(): Boolean {
+ if (instance != null) {
+ return true
+ }
+
+ runShellCommand(CMD_NOTIFICATION_ALLOW_LISTENER.format(COMPONENT_NAME))
+ return wait { instance != null }
+ }
+
+ fun stopNotificationListener(): Boolean {
+ if (instance == null) {
+ return true
+ }
+
+ runShellCommand(CMD_NOTIFICATION_DISALLOW_LISTENER.format(COMPONENT_NAME))
+ return wait { instance == null }
+ }
+
+ fun waitForNotificationToAppear(predicate: (StatusBarNotification) -> Boolean): Boolean {
+ return instance?.let {
+ wait { it.notifications.values.any(predicate) }
+ } ?: throw IllegalStateException("NotificationListenerService is not connected")
+ }
+
+ fun waitForNotificationToDisappear(predicate: (StatusBarNotification) -> Boolean): Boolean {
+ return instance?.let {
+ wait { it.notifications.values.none(predicate) }
+ } ?: throw IllegalStateException("NotificationListenerService is not connected")
+ }
+ }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt
new file mode 100644
index 0000000..a6d6735
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.flicker
+
+import android.os.SystemClock
+
+private const val DEFAULT_TIMEOUT = 10000L
+private const val DEFAULT_POLL_INTERVAL = 1000L
+
+fun wait(condition: () -> Boolean): Boolean {
+ val (success, _) = waitForResult(extractor = condition, validator = { it })
+ return success
+}
+
+fun <R> waitForResult(
+ timeout: Long = DEFAULT_TIMEOUT,
+ interval: Long = DEFAULT_POLL_INTERVAL,
+ extractor: () -> R,
+ validator: (R) -> Boolean = { it != null }
+): Pair<Boolean, R?> {
+ val startTime = SystemClock.uptimeMillis()
+ do {
+ val result = extractor()
+ if (validator(result)) {
+ return (true to result)
+ }
+ SystemClock.sleep(interval)
+ } while (SystemClock.uptimeMillis() - startTime < timeout)
+
+ return (false to null)
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
new file mode 100644
index 0000000..e8cf7d9
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.flicker.helpers
+
+import android.app.ActivityManager
+import android.app.Instrumentation
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager.FEATURE_LEANBACK
+import android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.wm.shell.flicker.TEST_APP_PACKAGE_NAME
+
+abstract class BaseAppHelper(
+ instrumentation: Instrumentation,
+ launcherName: String,
+ private val launcherActivityComponent: ComponentName
+) : StandardAppHelper(
+ instrumentation,
+ TEST_APP_PACKAGE_NAME,
+ launcherName,
+ LauncherStrategyFactory.getInstance(instrumentation).launcherStrategy
+) {
+ protected val uiDevice: UiDevice = UiDevice.getInstance(instrumentation)
+
+ private val context: Context
+ get() = mInstrumentation.context
+
+ private val activityManager: ActivityManager?
+ get() = context.getSystemService(ActivityManager::class.java)
+
+ private val appSelector = By.pkg(packageName).depth(0)
+
+ protected val isTelevision: Boolean
+ get() = context.packageManager.run {
+ hasSystemFeature(FEATURE_LEANBACK) || hasSystemFeature(FEATURE_LEANBACK_ONLY)
+ }
+
+ val label: String
+ get() = context.packageManager.run {
+ getApplicationLabel(getApplicationInfo(packageName, 0)).toString()
+ }
+
+ fun launchViaIntent() {
+ context.startActivity(openAppIntent)
+
+ uiDevice.wait(Until.hasObject(appSelector), APP_LAUNCH_WAIT_TIME_MS)
+ }
+
+ fun forceStop() = activityManager?.forceStopPackage(packageName)
+
+ override fun getOpenAppIntent(): Intent {
+ val intent = Intent()
+ intent.component = launcherActivityComponent
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ return intent
+ }
+
+ companion object {
+ private const val APP_LAUNCH_WAIT_TIME_MS = 10_000L
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt
deleted file mode 100644
index 47a62ce..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.wm.shell.flicker.helpers
-
-import android.app.Instrumentation
-import android.support.test.launcherhelper.ILauncherStrategy
-import com.android.server.wm.flicker.helpers.StandardAppHelper
-
-abstract class FlickerAppHelper(
- instr: Instrumentation,
- launcherName: String,
- launcherStrategy: ILauncherStrategy
-) : StandardAppHelper(instr, sFlickerPackage, launcherName, launcherStrategy) {
- companion object {
- var sFlickerPackage = "com.android.wm.shell.flicker.testapp"
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
index 0cedc0a..a6650d7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
@@ -17,37 +17,36 @@
package com.android.wm.shell.flicker.helpers
import android.app.Instrumentation
-import android.support.test.launcherhelper.ILauncherStrategy
-import android.support.test.launcherhelper.LauncherStrategyFactory
import androidx.test.uiautomator.By
-import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.helpers.FIND_TIMEOUT
import com.android.server.wm.flicker.helpers.waitForIME
+import com.android.wm.shell.flicker.TEST_APP_IME_ACTIVITY_COMPONENT_NAME
+import com.android.wm.shell.flicker.TEST_APP_IME_ACTIVITY_LABEL
import org.junit.Assert
open class ImeAppHelper(
- instr: Instrumentation,
- launcherName: String = "ImeApp",
- launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
- .getInstance(instr)
- .launcherStrategy
-) : FlickerAppHelper(instr, launcherName, launcherStrategy) {
- open fun openIME(device: UiDevice) {
- val editText = device.wait(
+ instrumentation: Instrumentation
+) : BaseAppHelper(
+ instrumentation,
+ TEST_APP_IME_ACTIVITY_LABEL,
+ TEST_APP_IME_ACTIVITY_COMPONENT_NAME
+) {
+ fun openIME() {
+ val editText = uiDevice.wait(
Until.findObject(By.res(getPackage(), "plain_text_input")),
FIND_TIMEOUT)
Assert.assertNotNull("Text field not found, this usually happens when the device " +
"was left in an unknown state (e.g. in split screen)", editText)
editText.click()
- if (!device.waitForIME()) {
+ if (!uiDevice.waitForIME()) {
Assert.fail("IME did not appear")
}
}
- open fun closeIME(device: UiDevice) {
- device.pressBack()
+ fun closeIME() {
+ uiDevice.pressBack()
// Using only the AccessibilityInfo it is not possible to identify if the IME is active
- device.waitForIdle(1000)
+ uiDevice.waitForIdle(1000)
}
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
index 5391702..d5efa40 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
@@ -17,29 +17,56 @@
package com.android.wm.shell.flicker.helpers
import android.app.Instrumentation
-import android.support.test.launcherhelper.ILauncherStrategy
-import android.support.test.launcherhelper.LauncherStrategyFactory
+import android.os.SystemClock
+import android.view.KeyEvent.KEYCODE_WINDOW
import androidx.test.uiautomator.By
-import androidx.test.uiautomator.UiDevice
-import com.android.server.wm.flicker.helpers.hasPipWindow
+import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.helpers.closePipWindow
-import org.junit.Assert
+import com.android.server.wm.flicker.helpers.hasPipWindow
+import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
+import com.android.wm.shell.flicker.TEST_APP_PIP_ACTIVITY_COMPONENT_NAME
+import com.android.wm.shell.flicker.TEST_APP_PIP_ACTIVITY_LABEL
+import org.junit.Assert.assertNotNull
class PipAppHelper(
- instr: Instrumentation,
- launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
- .getInstance(instr)
- .launcherStrategy
-) : FlickerAppHelper(instr, "PipApp", launcherStrategy) {
- fun clickEnterPipButton(device: UiDevice) {
- val enterPipButton = device.findObject(By.res(getPackage(), "enter_pip"))
- Assert.assertNotNull("Pip button not found, this usually happens when the device " +
+ instrumentation: Instrumentation
+) : BaseAppHelper(
+ instrumentation,
+ TEST_APP_PIP_ACTIVITY_LABEL,
+ TEST_APP_PIP_ACTIVITY_COMPONENT_NAME
+) {
+ fun clickEnterPipButton() {
+ val enterPipButton = uiDevice.findObject(By.res(packageName, "enter_pip"))
+ assertNotNull("Pip button not found, this usually happens when the device " +
"was left in an unknown state (e.g. in split screen)", enterPipButton)
enterPipButton.click()
- device.hasPipWindow()
+
+ // TODO(b/172321238): remove this check once hasPipWindow is fixed on TVs
+ if (!isTelevision) {
+ uiDevice.hasPipWindow()
+ } else {
+ // Simply wait for 3 seconds
+ SystemClock.sleep(3_000)
+ }
}
- fun closePipWindow(device: UiDevice) {
- device.closePipWindow()
+ fun closePipWindow() {
+ // TODO(b/172321238): remove this check once and simply call closePipWindow once the TV
+ // logic is integrated there.
+ if (!isTelevision) {
+ uiDevice.closePipWindow()
+ } else {
+ // Bring up Pip menu
+ uiDevice.pressKeyCode(KEYCODE_WINDOW)
+
+ // Wait for the menu to come up and render the close button
+ val closeButton = uiDevice.wait(
+ Until.findObject(By.res(SYSTEM_UI_PACKAGE_NAME, "close_button")), 3_000)
+ assertNotNull("Pip menu close button is not found", closeButton)
+ closeButton.click()
+
+ // Give it 1 second, just in case
+ SystemClock.sleep(1_000)
+ }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index 010aa0d..a1da7c9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -31,6 +31,7 @@
import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
import com.android.wm.shell.flicker.statusBarLayerRotatesScales
import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
+import com.android.wm.shell.flicker.PIP_WINDOW_NAME
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -79,7 +80,7 @@
}
}
transitions {
- testApp.clickEnterPipButton(device)
+ testApp.clickEnterPipButton()
device.expandPipWindow()
}
assertions {
@@ -89,7 +90,7 @@
all("pipWindowBecomesVisible") {
this.showsAppWindow(testApp.`package`)
.then()
- .showsAppWindow(sPipWindowTitle)
+ .showsAppWindow(PIP_WINDOW_NAME)
}
}
@@ -103,7 +104,7 @@
all("pipLayerBecomesVisible") {
this.showsLayer(testApp.launcherName)
.then()
- .showsLayer(sPipWindowTitle)
+ .showsLayer(PIP_WINDOW_NAME)
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
index 43e0225..d343f2a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
@@ -18,7 +18,6 @@
import android.content.ComponentName
import android.graphics.Region
-import android.support.test.launcherhelper.LauncherStrategyFactory
import android.util.Log
import android.view.Surface
import android.view.WindowManager
@@ -29,6 +28,9 @@
import com.android.server.wm.flicker.helpers.closePipWindow
import com.android.server.wm.flicker.helpers.hasPipWindow
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.wm.shell.flicker.TEST_APP_IME_ACTIVITY_COMPONENT_NAME
+import com.android.wm.shell.flicker.IME_WINDOW_NAME
+import com.android.wm.shell.flicker.TEST_APP_PIP_ACTIVITY_WINDOW_NAME
import com.android.wm.shell.flicker.helpers.ImeAppHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -51,19 +53,11 @@
private val windowManager: WindowManager =
instrumentation.context.getSystemService(WindowManager::class.java)
- private val keyboardApp = ImeAppHelper(instrumentation, "ImeApp",
- LauncherStrategyFactory.getInstance(instrumentation).launcherStrategy)
-
- private val KEYBOARD_ACTIVITY: ComponentName = ComponentName.createRelative(
- "com.android.wm.shell.flicker.testapp", ".ImeActivity")
- private val PIP_ACTIVITY_WINDOW_NAME = "PipActivity"
- private val INPUT_METHOD_WINDOW_NAME = "InputMethod"
-
- private val testRepetitions = 10
+ private val keyboardApp = ImeAppHelper(instrumentation)
private val keyboardScenario: FlickerBuilder
get() = FlickerBuilder(instrumentation).apply {
- repeat { testRepetitions }
+ repeat { TEST_REPETITIONS }
// disable layer tracing
withLayerTracing { null }
setup {
@@ -73,11 +67,11 @@
// launch our target pip app
testApp.open()
this.setRotation(rotation)
- testApp.clickEnterPipButton(device)
+ testApp.clickEnterPipButton()
// open an app with an input field and a keyboard
// UiAutomator doesn't support to launch the multiple Activities in a task.
// So use launchActivity() for the Keyboard Activity.
- launchActivity(KEYBOARD_ACTIVITY)
+ launchActivity(TEST_APP_IME_ACTIVITY_COMPONENT_NAME)
}
}
teardown {
@@ -101,10 +95,10 @@
withTestName { testTag }
transitions {
// open the soft keyboard
- keyboardApp.openIME(device)
+ keyboardApp.openIME()
// then close it again
- keyboardApp.closeIME(device)
+ keyboardApp.closeIME()
}
assertions {
windowManagerTrace {
@@ -127,18 +121,18 @@
withTestName { testTag }
transitions {
// open the soft keyboard
- keyboardApp.openIME(device)
+ keyboardApp.openIME()
}
teardown {
eachRun {
// close the keyboard
- keyboardApp.closeIME(device)
+ keyboardApp.closeIME()
}
}
assertions {
windowManagerTrace {
end {
- isAboveWindow(INPUT_METHOD_WINDOW_NAME, PIP_ACTIVITY_WINDOW_NAME)
+ isAboveWindow(IME_WINDOW_NAME, TEST_APP_PIP_ACTIVITY_WINDOW_NAME)
}
}
}
@@ -207,6 +201,8 @@
}
companion object {
+ private const val TEST_REPETITIONS = 10
+
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<Array<Any>> {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt
index 3822d69..c1c34ec 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt
@@ -24,8 +24,4 @@
rotation: Int
) : NonRotationTestBase(rotationName, rotation) {
protected val testApp = PipAppHelper(instrumentation)
-
- companion object {
- const val sPipWindowTitle = "PipMenuActivity"
- }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt
new file mode 100644
index 0000000..569da1d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.flicker.pip.tv
+
+import android.app.Notification
+import android.service.notification.StatusBarNotification
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.NotificationListener.Companion.startNotificationListener
+import com.android.wm.shell.flicker.NotificationListener.Companion.stopNotificationListener
+import com.android.wm.shell.flicker.NotificationListener.Companion.waitForNotificationToAppear
+import com.android.wm.shell.flicker.NotificationListener.Companion.waitForNotificationToDisappear
+import org.junit.After
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip Notifications on TV.
+ * To run this test: `atest WMShellFlickerTests:TvPipNotificationTests`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class TvPipNotificationTests(rotationName: String, rotation: Int)
+ : TvPipTestBase(rotationName, rotation) {
+
+ @Before
+ override fun setUp() {
+ super.setUp()
+ val started = startNotificationListener()
+ if (!started) {
+ error("NotificationListener hasn't started")
+ }
+ }
+
+ @After
+ override fun tearDown() {
+ stopNotificationListener()
+ testApp.forceStop()
+ super.tearDown()
+ }
+
+ @Test
+ fun pipNotification_postedAndDismissed() {
+ testApp.launchViaIntent()
+ testApp.clickEnterPipButton()
+
+ assertTrue("Pip notification should have been posted",
+ waitForNotificationToAppear { it.isPipNotificationWithTitle(testApp.label) })
+
+ testApp.closePipWindow()
+
+ assertTrue("Pip notification should have been dismissed",
+ waitForNotificationToDisappear { it.isPipNotificationWithTitle(testApp.label) })
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> {
+ val supportedRotations = intArrayOf(Surface.ROTATION_0)
+ return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
+ }
+ }
+}
+
+private const val PIP_NOTIFICATION_TAG = "PipNotification"
+
+private val StatusBarNotification.title: String
+ get() = notification?.extras?.getString(Notification.EXTRA_TITLE) ?: ""
+
+private fun StatusBarNotification.isPipNotificationWithTitle(expectedTitle: String): Boolean =
+ tag == PIP_NOTIFICATION_TAG && title == expectedTitle
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
new file mode 100644
index 0000000..104248c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.flicker.pip.tv
+
+import android.content.pm.PackageManager.FEATURE_LEANBACK
+import android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.wm.shell.flicker.pip.PipTestBase
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+
+abstract class TvPipTestBase(rotationName: String, rotation: Int)
+ : PipTestBase(rotationName, rotation) {
+
+ private val isTelevision: Boolean
+ get() = packageManager.run {
+ hasSystemFeature(FEATURE_LEANBACK) || hasSystemFeature(FEATURE_LEANBACK_ONLY)
+ }
+
+ @Before
+ open fun setUp() {
+ Assume.assumeTrue(isTelevision)
+ uiDevice.wakeUpAndGoToHomeScreen()
+ }
+
+ @After
+ open fun tearDown() {
+ }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml b/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml
index a8f795e..59d9104 100644
--- a/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml
@@ -22,6 +22,13 @@
<application android:debuggable="true" android:largeHeap="true">
<uses-library android:name="android.test.mock" />
<uses-library android:name="android.test.runner" />
+
+ <activity android:name=".bubbles.BubblesTestActivity"
+ android:allowEmbedded="true"
+ android:documentLaunchMode="always"
+ android:excludeFromRecents="true"
+ android:exported="false"
+ android:resizeableActivity="true" />
</application>
<instrumentation
diff --git a/libs/WindowManager/Shell/tests/unittest/res/layout/main.xml b/libs/WindowManager/Shell/tests/unittest/res/layout/main.xml
new file mode 100644
index 0000000..0d09f86
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/res/layout/main.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ >
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="this is a test activity"
+ />
+ <EditText
+ android:layout_height="wrap_content"
+ android:id="@+id/editText1"
+ android:layout_width="match_parent">
+ <requestFocus></requestFocus>
+ </EditText>
+</LinearLayout>
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTestCase.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java
similarity index 79%
rename from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTestCase.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java
index fdebe4e..5bdf831 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTestCase.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.pip;
+package com.android.wm.shell;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -24,17 +24,18 @@
import androidx.test.InstrumentationRegistry;
+import org.junit.After;
import org.junit.Before;
/**
- * Base class that does One Handed specific setup.
+ * Base class that does shell test case setup.
*/
-public abstract class PipTestCase {
+public abstract class ShellTestCase {
protected TestableContext mContext;
@Before
- public void setup() {
+ public void shellSetup() {
final Context context =
InstrumentationRegistry.getInstrumentation().getTargetContext();
final DisplayManager dm = context.getSystemService(DisplayManager.class);
@@ -47,6 +48,14 @@
.adoptShellPermissionIdentity();
}
+ @After
+ public void shellTearDown() {
+ InstrumentationRegistry
+ .getInstrumentation()
+ .getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+
protected Context getContext() {
return mContext;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TaskViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java
similarity index 95%
rename from packages/SystemUI/tests/src/com/android/systemui/bubbles/TaskViewTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java
index 5c14859..34f772f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TaskViewTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
@@ -30,7 +30,6 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.app.ActivityOptions;
@@ -45,8 +44,6 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.SysuiTestCase;
-import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.HandlerExecutor;
import org.junit.After;
@@ -60,8 +57,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-// TODO: Place in com.android.wm.shell vs. com.android.wm.shell.bubbles on shell migration.
-public class TaskViewTest extends SysuiTestCase {
+public class TaskViewTest extends ShellTestCase {
@Mock
TaskView.Listener mViewListener;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
index 31c08ae..7adc411 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -38,8 +38,8 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.BubbleData.TimeSource;
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.bubbles.BubbleData.TimeSource;
import com.google.common.collect.ImmutableList;
@@ -63,7 +63,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class BubbleDataTest extends SysuiTestCase {
+public class BubbleDataTest extends ShellTestCase {
private BubbleEntry mEntryA1;
private BubbleEntry mEntryA2;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleFlyoutViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java
similarity index 93%
rename from packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleFlyoutViewTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java
index fd6e2ee..5b77e4a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleFlyoutViewTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotSame;
@@ -30,8 +30,8 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
+import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTestCase;
import org.junit.Before;
import org.junit.Test;
@@ -42,7 +42,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class BubbleFlyoutViewTest extends SysuiTestCase {
+public class BubbleFlyoutViewTest extends ShellTestCase {
private BubbleFlyoutView mFlyout;
private TextView mFlyoutText;
private TextView mSenderName;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java
similarity index 95%
rename from packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java
index 690a1ad..0693052 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import static com.google.common.truth.Truth.assertThat;
@@ -37,8 +37,8 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
+import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTestCase;
import org.junit.Before;
import org.junit.Test;
@@ -49,7 +49,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
-public class BubbleTest extends SysuiTestCase {
+public class BubbleTest extends ShellTestCase {
@Mock
private Notification mNotif;
@Mock
@@ -72,7 +72,7 @@
Intent target = new Intent(mContext, BubblesTestActivity.class);
Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder(
PendingIntent.getActivity(mContext, 0, target, 0),
- Icon.createWithResource(mContext, R.drawable.android))
+ Icon.createWithResource(mContext, R.drawable.bubble_ic_create_bubble))
.build();
when(mSbn.getNotification()).thenReturn(mNotif);
when(mNotif.getBubbleMetadata()).thenReturn(metadata);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubblesTestActivity.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesTestActivity.java
similarity index 80%
copy from packages/SystemUI/tests/src/com/android/systemui/bubbles/BubblesTestActivity.java
copy to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesTestActivity.java
index 43d2ad1..d5fbe55 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubblesTestActivity.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesTestActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,21 +14,20 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
-import com.android.systemui.R;
+import com.android.wm.shell.R;
/**
* Referenced by NotificationTestHelper#makeBubbleMetadata
*/
public class BubblesTestActivity extends Activity {
- public static final String BUBBLE_ACTIVITY_OPENED =
- "com.android.systemui.bubbles.BUBBLE_ACTIVITY_OPENED";
+ public static final String BUBBLE_ACTIVITY_OPENED = "BUBBLE_ACTIVITY_OPENED";
@Override
public void onCreate(Bundle savedInstanceState) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java
similarity index 96%
rename from packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java
index a5bb8ea..9c4f341 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles.animation;
+package com.android.wm.shell.bubbles.animation;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
@@ -34,8 +34,8 @@
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.test.filters.SmallTest;
-import com.android.systemui.R;
-import com.android.systemui.bubbles.BubblePositioner;
+import com.android.wm.shell.R;
+import com.android.wm.shell.bubbles.BubblePositioner;
import org.junit.Before;
import org.junit.Ignore;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayoutTest.java
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayoutTest.java
index 498330c..c4edbb2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayoutTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles.animation;
+package com.android.wm.shell.bubbles.animation;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTestCase.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayoutTestCase.java
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTestCase.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayoutTestCase.java
index a5f2e8b..a7a7db8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTestCase.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayoutTestCase.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles.animation;
+package com.android.wm.shell.bubbles.animation;
import static org.mockito.Mockito.when;
@@ -30,8 +30,8 @@
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringForce;
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
+import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTestCase;
import org.junit.Before;
import org.mockito.Mock;
@@ -50,7 +50,7 @@
*
* See physics-animation-testing.md.
*/
-public class PhysicsAnimationLayoutTestCase extends SysuiTestCase {
+public class PhysicsAnimationLayoutTestCase extends ShellTestCase {
TestablePhysicsAnimationLayout mLayout;
List<View> mViews = new ArrayList<>();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/StackAnimationControllerTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/StackAnimationControllerTest.java
index 7d0abec..6b01462 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/StackAnimationControllerTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles.animation;
+package com.android.wm.shell.bubbles.animation;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
@@ -33,8 +33,8 @@
import androidx.dynamicanimation.animation.SpringForce;
import androidx.test.filters.SmallTest;
-import com.android.systemui.R;
-import com.android.systemui.bubbles.BubblePositioner;
+import com.android.wm.shell.R;
+import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.common.FloatingContentCoordinator;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt
similarity index 92%
rename from packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt
index 9b8fd11..4160280 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
+package com.android.wm.shell.bubbles.storage
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
+import com.android.wm.shell.ShellTestCase
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertNotNull
import junit.framework.Assert.assertTrue
@@ -28,7 +28,7 @@
@SmallTest
@RunWith(AndroidTestingRunner::class)
-class BubblePersistentRepositoryTest : SysuiTestCase() {
+class BubblePersistentRepositoryTest : ShellTestCase() {
private val bubbles = listOf(
BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1", 120, 0),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt
similarity index 96%
rename from packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt
index 7ea611c..4fab9a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
+package com.android.wm.shell.bubbles.storage
import android.content.pm.LauncherApps
import android.os.UserHandle
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.eq
+import com.android.wm.shell.ShellTestCase
import junit.framework.Assert.assertEquals
import org.junit.Before
import org.junit.Test
@@ -32,7 +32,7 @@
@SmallTest
@RunWith(AndroidTestingRunner::class)
-class BubbleVolatileRepositoryTest : SysuiTestCase() {
+class BubbleVolatileRepositoryTest : ShellTestCase() {
private val user0 = UserHandle.of(0)
private val user10 = UserHandle.of(10)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt
similarity index 95%
rename from packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt
index 8cf4534..e0891a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
+package com.android.wm.shell.bubbles.storage
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
+import com.android.wm.shell.ShellTestCase
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertTrue
import org.junit.Test
@@ -28,7 +28,7 @@
@SmallTest
@RunWith(AndroidTestingRunner::class)
-class BubbleXmlHelperTest : SysuiTestCase() {
+class BubbleXmlHelperTest : ShellTestCase() {
private val bubbles = listOf(
BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1", 120, 0),
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
new file mode 100644
index 0000000..affd736
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.draganddrop;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
+
+import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_FULLSCREEN;
+import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
+import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
+
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManager;
+import android.app.IActivityTaskManager;
+import android.app.PendingIntent;
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.os.RemoteException;
+import android.view.DisplayInfo;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.draganddrop.DragAndDropPolicy.Target;
+import com.android.wm.shell.splitscreen.DividerView;
+import com.android.wm.shell.splitscreen.SplitScreen;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+
+/**
+ * Tests for the drag and drop policy.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DragAndDropPolicyTest {
+
+ @Mock
+ private Context mContext;
+
+ @Mock
+ private IActivityTaskManager mIActivityTaskManager;
+
+ @Mock
+ private SplitScreen mSplitScreen;
+
+ @Mock
+ private DragAndDropPolicy.Starter mStarter;
+
+ private DisplayLayout mDisplayLayout;
+ private Insets mInsets;
+ private DragAndDropPolicy mPolicy;
+
+ private ClipData mActivityClipData;
+ private ClipData mNonResizeableActivityClipData;
+ private ClipData mTaskClipData;
+ private ClipData mShortcutClipData;
+
+ private ActivityManager.RunningTaskInfo mHomeTask;
+ private ActivityManager.RunningTaskInfo mFullscreenAppTask;
+ private ActivityManager.RunningTaskInfo mNonResizeableFullscreenAppTask;
+ private ActivityManager.RunningTaskInfo mSplitPrimaryAppTask;
+
+ @Before
+ public void setUp() throws RemoteException {
+ MockitoAnnotations.initMocks(this);
+
+ Resources res = mock(Resources.class);
+ Configuration config = new Configuration();
+ doReturn(config).when(res).getConfiguration();
+ DisplayInfo info = new DisplayInfo();
+ info.logicalWidth = 100;
+ info.logicalHeight = 100;
+ mDisplayLayout = new DisplayLayout(info, res, false, false);
+ mInsets = Insets.of(0, 0, 0, 0);
+
+ DividerView divider = mock(DividerView.class);
+ doReturn(divider).when(mSplitScreen).getDividerView();
+ doReturn(new Rect(50, 0, 100, 100)).when(divider)
+ .getNonMinimizedSplitScreenSecondaryBounds();
+
+ mPolicy = new DragAndDropPolicy(mContext, mIActivityTaskManager, mSplitScreen, mStarter);
+ mActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
+ mNonResizeableActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
+ setClipDataResizeable(mNonResizeableActivityClipData, false);
+ mTaskClipData = createClipData(MIMETYPE_APPLICATION_TASK);
+ mShortcutClipData = createClipData(MIMETYPE_APPLICATION_SHORTCUT);
+
+ mHomeTask = createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
+ mFullscreenAppTask = createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ mNonResizeableFullscreenAppTask =
+ createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ mNonResizeableFullscreenAppTask.isResizeable = false;
+ mSplitPrimaryAppTask = createTaskInfo(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
+ ACTIVITY_TYPE_STANDARD);
+
+ setIsPhone(false);
+ setInSplitScreen(false);
+ setRunningTask(mFullscreenAppTask);
+ }
+
+ /**
+ * Creates a clip data that is by default resizeable.
+ */
+ private ClipData createClipData(String mimeType) {
+ ClipDescription clipDescription = new ClipDescription(mimeType, new String[] { mimeType });
+ Intent i = new Intent();
+ switch (mimeType) {
+ case MIMETYPE_APPLICATION_SHORTCUT:
+ i.putExtra(Intent.EXTRA_PACKAGE_NAME, "package");
+ i.putExtra(Intent.EXTRA_SHORTCUT_ID, "shortcut_id");
+ break;
+ case MIMETYPE_APPLICATION_TASK:
+ i.putExtra(Intent.EXTRA_TASK_ID, 12345);
+ break;
+ case MIMETYPE_APPLICATION_ACTIVITY:
+ i.putExtra(ClipDescription.EXTRA_PENDING_INTENT, mock(PendingIntent.class));
+ break;
+ }
+ i.putExtra(Intent.EXTRA_USER, android.os.Process.myUserHandle());
+ ClipData.Item item = new ClipData.Item(i);
+ item.setActivityInfo(new ActivityInfo());
+ ClipData data = new ClipData(clipDescription, item);
+ setClipDataResizeable(data, true);
+ return data;
+ }
+
+ private ActivityManager.RunningTaskInfo createTaskInfo(int winMode, int actType) {
+ ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
+ info.configuration.windowConfiguration.setActivityType(actType);
+ info.configuration.windowConfiguration.setWindowingMode(winMode);
+ info.isResizeable = true;
+ return info;
+ }
+
+ private void setRunningTask(ActivityManager.RunningTaskInfo task) throws RemoteException {
+ doReturn(Collections.singletonList(task)).when(mIActivityTaskManager)
+ .getFilteredTasks(anyInt(), anyBoolean());
+ }
+
+ private void setClipDataResizeable(ClipData data, boolean resizeable) {
+ data.getItemAt(0).getActivityInfo().resizeMode = resizeable
+ ? ActivityInfo.RESIZE_MODE_RESIZEABLE
+ : ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+ }
+
+ private void setIsPhone(boolean isPhone) {
+ Resources res = mock(Resources.class);
+ Configuration config = mock(Configuration.class);
+ config.smallestScreenWidthDp = isPhone ? 400 : 800;
+ doReturn(config).when(res).getConfiguration();
+ doReturn(res).when(mContext).getResources();
+ }
+
+ private void setInSplitScreen(boolean inSplitscreen) {
+ doReturn(inSplitscreen).when(mSplitScreen).isDividerVisible();
+ }
+
+ @Test
+ public void testDragAppOverFullscreenHome_expectOnlyFullscreenTarget() throws RemoteException {
+ setRunningTask(mHomeTask);
+ mPolicy.start(mDisplayLayout, mActivityClipData);
+ ArrayList<Target> targets = assertExactTargetTypes(
+ mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
+
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ verify(mStarter).startIntent(any(), any());
+ }
+
+ @Test
+ public void testDragAppOverFullscreenApp_expectSplitScreenAndFullscreenTargets()
+ throws RemoteException {
+ setRunningTask(mFullscreenAppTask);
+ mPolicy.start(mDisplayLayout, mActivityClipData);
+ // TODO(b/169894807): For now, only allow splitting to the right/bottom until we have split
+ // pairs
+ ArrayList<Target> targets = assertExactTargetTypes(
+ mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_RIGHT);
+
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ verify(mStarter).startIntent(any(), any());
+ reset(mStarter);
+
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
+ verify(mStarter).enterSplitScreen(anyInt(), eq(false));
+ verify(mStarter).startIntent(any(), any());
+ }
+
+ @Test
+ public void testDragAppOverFullscreenAppPhone_expectVerticalSplitScreenAndFullscreenTargets()
+ throws RemoteException {
+ setIsPhone(true);
+ setRunningTask(mFullscreenAppTask);
+ mPolicy.start(mDisplayLayout, mActivityClipData);
+ // TODO(b/169894807): For now, only allow splitting to the right/bottom until we have split
+ // pairs
+ ArrayList<Target> targets = assertExactTargetTypes(
+ mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_BOTTOM);
+
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ verify(mStarter).startIntent(any(), any());
+ reset(mStarter);
+
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
+ verify(mStarter).enterSplitScreen(anyInt(), eq(false));
+ verify(mStarter).startIntent(any(), any());
+ }
+
+ @Test
+ public void testDragAppOverFullscreenNonResizeableApp_expectOnlyFullscreenTargets()
+ throws RemoteException {
+ setRunningTask(mNonResizeableFullscreenAppTask);
+ mPolicy.start(mDisplayLayout, mActivityClipData);
+ ArrayList<Target> targets = assertExactTargetTypes(
+ mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
+
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ verify(mStarter).startIntent(any(), any());
+ }
+
+ @Test
+ public void testDragNonResizeableAppOverFullscreenApp_expectOnlyFullscreenTargets()
+ throws RemoteException {
+ setRunningTask(mFullscreenAppTask);
+ mPolicy.start(mDisplayLayout, mNonResizeableActivityClipData);
+ ArrayList<Target> targets = assertExactTargetTypes(
+ mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
+
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ verify(mStarter).startIntent(any(), any());
+ }
+
+ @Test
+ public void testDragAppOverSplitApp_expectFullscreenAndSplitTargets() throws RemoteException {
+ setInSplitScreen(true);
+ setRunningTask(mSplitPrimaryAppTask);
+ mPolicy.start(mDisplayLayout, mActivityClipData);
+ // TODO(b/169894807): For now, only allow splitting to the right/bottom until we have split
+ // pairs
+ ArrayList<Target> targets = assertExactTargetTypes(
+ mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_RIGHT);
+
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ verify(mStarter).startIntent(any(), any());
+ reset(mStarter);
+
+ // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
+ verify(mStarter).startIntent(any(), any());
+ }
+
+ @Test
+ public void testDragAppOverSplitAppPhone_expectFullscreenAndVerticalSplitTargets()
+ throws RemoteException {
+ setIsPhone(true);
+ setInSplitScreen(true);
+ setRunningTask(mSplitPrimaryAppTask);
+ mPolicy.start(mDisplayLayout, mActivityClipData);
+ // TODO(b/169894807): For now, only allow splitting to the right/bottom until we have split
+ // pairs
+ ArrayList<Target> targets = assertExactTargetTypes(
+ mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_BOTTOM);
+
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ verify(mStarter).startIntent(any(), any());
+ reset(mStarter);
+
+ // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
+ verify(mStarter).startIntent(any(), any());
+ }
+
+ @Test
+ public void testTargetHitRects() throws RemoteException {
+ setRunningTask(mFullscreenAppTask);
+ mPolicy.start(mDisplayLayout, mActivityClipData);
+ ArrayList<Target> targets = mPolicy.getTargets(mInsets);
+ for (Target t : targets) {
+ assertTrue(mPolicy.getTargetAtLocation(t.hitRegion.left, t.hitRegion.top) == t);
+ assertTrue(mPolicy.getTargetAtLocation(t.hitRegion.right - 1, t.hitRegion.top) == t);
+ assertTrue(mPolicy.getTargetAtLocation(t.hitRegion.right - 1, t.hitRegion.bottom - 1)
+ == t);
+ assertTrue(mPolicy.getTargetAtLocation(t.hitRegion.left, t.hitRegion.bottom - 1)
+ == t);
+ }
+ }
+
+ private Target filterTargetByType(ArrayList<Target> targets, int type) {
+ for (Target t : targets) {
+ if (type == t.type) {
+ return t;
+ }
+ }
+ fail("Target with type: " + type + " not found");
+ return null;
+ }
+
+ private ArrayList<Target> assertExactTargetTypes(ArrayList<Target> targets,
+ int... expectedTargetTypes) {
+ HashSet<Integer> expected = new HashSet<>();
+ for (int t : expectedTargetTypes) {
+ expected.add(t);
+ }
+ for (Target t : targets) {
+ if (!expected.contains(t.type)) {
+ fail("Found unexpected target type: " + t.type);
+ }
+ expected.remove(t.type);
+ }
+ assertTrue(expected.isEmpty());
+ return targets;
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
index 255e749..55e7a35 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
@@ -32,9 +32,7 @@
import androidx.test.filters.SmallTest;
-import com.android.wm.shell.pip.PipAnimationController;
-import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
-import com.android.wm.shell.pip.PipTestCase;
+import com.android.wm.shell.ShellTestCase;
import org.junit.Before;
import org.junit.Test;
@@ -49,7 +47,7 @@
@RunWith(AndroidTestingRunner.class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class PipAnimationControllerTest extends PipTestCase {
+public class PipAnimationControllerTest extends ShellTestCase {
private PipAnimationController mPipAnimationController;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java
index 37421d9..5169243 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java
@@ -30,8 +30,7 @@
import androidx.test.filters.SmallTest;
-import com.android.wm.shell.pip.PipBoundsHandler;
-import com.android.wm.shell.pip.PipTestCase;
+import com.android.wm.shell.ShellTestCase;
import org.junit.Before;
import org.junit.Test;
@@ -46,7 +45,7 @@
@RunWith(AndroidTestingRunner.class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class PipBoundsHandlerTest extends PipTestCase {
+public class PipBoundsHandlerTest extends ShellTestCase {
private static final int ROUNDING_ERROR_MARGIN = 16;
private static final float ASPECT_RATIO_ERROR_MARGIN = 0.01f;
private static final float DEFAULT_ASPECT_RATIO = 1f;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
index dc9399e..844f82d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
@@ -28,6 +28,8 @@
import androidx.test.filters.SmallTest;
+import com.android.wm.shell.ShellTestCase;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -38,7 +40,7 @@
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
-public class PipBoundsStateTest extends PipTestCase {
+public class PipBoundsStateTest extends ShellTestCase {
private static final Rect DEFAULT_BOUNDS = new Rect(0, 0, 10, 10);
private static final float DEFAULT_SNAP_FRACTION = 1.0f;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 39381c6..efe553a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -40,6 +40,7 @@
import android.window.WindowContainerToken;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.pip.phone.PipMenuActivityController;
import com.android.wm.shell.splitscreen.SplitScreen;
@@ -58,7 +59,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
-public class PipTaskOrganizerTest extends PipTestCase {
+public class PipTaskOrganizerTest extends ShellTestCase {
private PipTaskOrganizer mSpiedPipTaskOrganizer;
@Mock private DisplayController mMockdDisplayController;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 5f0f196..a00a3b6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -35,6 +35,7 @@
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ShellExecutor;
@@ -42,7 +43,6 @@
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipTaskOrganizer;
-import com.android.wm.shell.pip.PipTestCase;
import org.junit.Before;
import org.junit.Test;
@@ -56,7 +56,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
-public class PipControllerTest extends PipTestCase {
+public class PipControllerTest extends ShellTestCase {
private PipController mPipController;
@Mock private DisplayController mMockDisplayController;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
index 3f60cc0..f6dcec2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
@@ -31,17 +31,13 @@
import androidx.test.filters.SmallTest;
import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.pip.PipBoundsHandler;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip.PipTaskOrganizer;
-import com.android.wm.shell.pip.PipTestCase;
import com.android.wm.shell.pip.PipUiEventLogger;
-import com.android.wm.shell.pip.phone.PipMenuActivityController;
-import com.android.wm.shell.pip.phone.PipMotionHelper;
-import com.android.wm.shell.pip.phone.PipResizeGestureHandler;
-import com.android.wm.shell.pip.phone.PipTouchHandler;
import org.junit.Before;
import org.junit.Test;
@@ -59,7 +55,7 @@
@RunWith(AndroidTestingRunner.class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class PipTouchHandlerTest extends PipTestCase {
+public class PipTouchHandlerTest extends ShellTestCase {
private PipTouchHandler mPipTouchHandler;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchStateTest.java
index 40667f7..000f7e8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchStateTest.java
@@ -35,8 +35,7 @@
import androidx.test.filters.SmallTest;
-import com.android.wm.shell.pip.PipTestCase;
-import com.android.wm.shell.pip.phone.PipTouchState;
+import com.android.wm.shell.ShellTestCase;
import org.junit.Before;
import org.junit.Test;
@@ -47,7 +46,7 @@
@RunWith(AndroidTestingRunner.class)
@SmallTest
@RunWithLooper
-public class PipTouchStateTest extends PipTestCase {
+public class PipTouchStateTest extends ShellTestCase {
private PipTouchState mTouchState;
private CountDownLatch mDoubleTapCallbackTriggeredLatch;
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 903ca2a..a3fcf90 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -160,10 +160,17 @@
"tests/ObbFile_test.cpp",
"tests/PosixUtils_test.cpp",
],
- shared_libs: common_test_libs + ["libbinder", "liblog", "libui"],
+ shared_libs: common_test_libs + [
+ "libbinder",
+ "liblog",
+ "libui",
+ ],
},
host: {
- static_libs: common_test_libs + ["liblog", "libz"],
+ static_libs: common_test_libs + [
+ "liblog",
+ "libz",
+ ],
},
},
data: [
@@ -204,10 +211,20 @@
export_include_dirs: ["include"],
target: {
android: {
- shared_libs: common_test_libs + ["libbinder", "liblog"],
+ shared_libs: common_test_libs + [
+ "libbinder",
+ "liblog",
+ ],
},
host: {
- static_libs: common_test_libs + ["libbinder", "liblog"],
+ static_libs: common_test_libs + [
+ "libbinder",
+ "liblog",
+ ],
+ },
+ darwin: {
+ // libbinder is not supported on mac
+ enabled: false,
},
},
}
diff --git a/libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp b/libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp
index 2dac47b..b36ff09 100644
--- a/libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp
+++ b/libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp
@@ -27,5 +27,9 @@
"libutils",
],
},
+ darwin: {
+ // libbinder is not supported on mac
+ enabled: false,
+ },
},
}
diff --git a/location/java/android/location/Geocoder.java b/location/java/android/location/Geocoder.java
index 704cdbf..307fb87 100644
--- a/location/java/android/location/Geocoder.java
+++ b/location/java/android/location/Geocoder.java
@@ -21,6 +21,8 @@
import android.os.RemoteException;
import android.os.ServiceManager;
+import com.android.internal.util.Preconditions;
+
import java.io.IOException;
import java.util.Collections;
import java.util.List;
@@ -77,12 +79,9 @@
* @throws NullPointerException if Locale is null
*/
public Geocoder(Context context, Locale locale) {
- if (locale == null) {
- throw new NullPointerException("locale == null");
- }
mParams = new GeocoderParams(context, locale);
- IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE);
- mService = ILocationManager.Stub.asInterface(b);
+ mService = ILocationManager.Stub.asInterface(
+ ServiceManager.getService(Context.LOCATION_SERVICE));
}
/**
@@ -121,13 +120,10 @@
* I/O problem occurs
*/
public List<Address> getFromLocation(double latitude, double longitude, int maxResults)
- throws IOException {
- if (latitude < -90.0 || latitude > 90.0) {
- throw new IllegalArgumentException("latitude == " + latitude);
- }
- if (longitude < -180.0 || longitude > 180.0) {
- throw new IllegalArgumentException("longitude == " + longitude);
- }
+ throws IOException {
+ Preconditions.checkArgumentInRange(latitude, -90.0, 90.0, "latitude");
+ Preconditions.checkArgumentInRange(longitude, -180.0, 180.0, "longitude");
+
try {
GeocodeListener listener = new GeocodeListener();
mService.getFromLocation(latitude, longitude, maxResults, mParams, listener);
@@ -161,17 +157,7 @@
* I/O problem occurs
*/
public List<Address> getFromLocationName(String locationName, int maxResults) throws IOException {
- if (locationName == null) {
- throw new IllegalArgumentException("locationName == null");
- }
-
- try {
- GeocodeListener listener = new GeocodeListener();
- mService.getFromLocationName(locationName, 0, 0, 0, 0, maxResults, mParams, listener);
- return listener.getResults();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getFromLocationName(locationName, maxResults, 0, 0, 0, 0);
}
/**
@@ -210,27 +196,14 @@
* I/O problem occurs
*/
public List<Address> getFromLocationName(String locationName, int maxResults,
- double lowerLeftLatitude, double lowerLeftLongitude,
- double upperRightLatitude, double upperRightLongitude) throws IOException {
- if (locationName == null) {
- throw new IllegalArgumentException("locationName == null");
- }
- if (lowerLeftLatitude < -90.0 || lowerLeftLatitude > 90.0) {
- throw new IllegalArgumentException("lowerLeftLatitude == "
- + lowerLeftLatitude);
- }
- if (lowerLeftLongitude < -180.0 || lowerLeftLongitude > 180.0) {
- throw new IllegalArgumentException("lowerLeftLongitude == "
- + lowerLeftLongitude);
- }
- if (upperRightLatitude < -90.0 || upperRightLatitude > 90.0) {
- throw new IllegalArgumentException("upperRightLatitude == "
- + upperRightLatitude);
- }
- if (upperRightLongitude < -180.0 || upperRightLongitude > 180.0) {
- throw new IllegalArgumentException("upperRightLongitude == "
- + upperRightLongitude);
- }
+ double lowerLeftLatitude, double lowerLeftLongitude, double upperRightLatitude,
+ double upperRightLongitude) throws IOException {
+ Preconditions.checkArgument(locationName != null);
+ Preconditions.checkArgumentInRange(lowerLeftLatitude, -90.0, 90.0, "lowerLeftLatitude");
+ Preconditions.checkArgumentInRange(lowerLeftLongitude, -180.0, 180.0, "lowerLeftLongitude");
+ Preconditions.checkArgumentInRange(upperRightLatitude, -90.0, 90.0, "upperRightLatitude");
+ Preconditions.checkArgumentInRange(upperRightLongitude, -180.0, 180.0,
+ "upperRightLongitude");
try {
GeocodeListener listener = new GeocodeListener();
diff --git a/location/java/android/location/GeocoderParams.java b/location/java/android/location/GeocoderParams.java
index 1c6e9b6..b00a9a9 100644
--- a/location/java/android/location/GeocoderParams.java
+++ b/location/java/android/location/GeocoderParams.java
@@ -16,12 +16,16 @@
package android.location;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.Process;
import java.util.Locale;
+import java.util.Objects;
/**
* This class contains extra parameters to pass to an IGeocodeProvider
@@ -34,64 +38,88 @@
* @hide
*/
public class GeocoderParams implements Parcelable {
- private Locale mLocale;
- private String mPackageName;
- // used only for parcelling
- private GeocoderParams() {
+ private final int mUid;
+ private final String mPackageName;
+ private final @Nullable String mAttributionTag;
+ private final Locale mLocale;
+
+ public GeocoderParams(Context context) {
+ this(context, Locale.getDefault());
}
- /**
- * This object is only constructed by the Geocoder class
- *
- * @hide
- */
public GeocoderParams(Context context, Locale locale) {
- mLocale = locale;
- mPackageName = context.getPackageName();
+ this(Process.myUid(), context.getPackageName(), context.getAttributionTag(), locale);
+ }
+
+ private GeocoderParams(int uid, String packageName, String attributionTag, Locale locale) {
+ mUid = uid;
+ mPackageName = Objects.requireNonNull(packageName);
+ mAttributionTag = attributionTag;
+ mLocale = Objects.requireNonNull(locale);
}
/**
- * returns the Geocoder's locale
+ * Returns the client UID.
*/
@UnsupportedAppUsage
- public Locale getLocale() {
- return mLocale;
+ public int getClientUid() {
+ return mUid;
}
/**
- * returns the package name of the Geocoder's client
+ * Returns the client package name.
*/
@UnsupportedAppUsage
- public String getClientPackage() {
+ public @NonNull String getClientPackage() {
return mPackageName;
}
- public static final @android.annotation.NonNull Parcelable.Creator<GeocoderParams> CREATOR =
- new Parcelable.Creator<GeocoderParams>() {
- public GeocoderParams createFromParcel(Parcel in) {
- GeocoderParams gp = new GeocoderParams();
- String language = in.readString();
- String country = in.readString();
- String variant = in.readString();
- gp.mLocale = new Locale(language, country, variant);
- gp.mPackageName = in.readString();
- return gp;
- }
+ /**
+ * Returns the client attribution tag.
+ */
+ @UnsupportedAppUsage
+ public @Nullable String getClientAttributionTag() {
+ return mAttributionTag;
+ }
- public GeocoderParams[] newArray(int size) {
- return new GeocoderParams[size];
- }
- };
+ /**
+ * Returns the locale.
+ */
+ @UnsupportedAppUsage
+ public @NonNull Locale getLocale() {
+ return mLocale;
+ }
+
+ public static final @NonNull Parcelable.Creator<GeocoderParams> CREATOR =
+ new Parcelable.Creator<GeocoderParams>() {
+ public GeocoderParams createFromParcel(Parcel in) {
+ int uid = in.readInt();
+ String packageName = in.readString();
+ String attributionTag = in.readString();
+ String language = in.readString();
+ String country = in.readString();
+ String variant = in.readString();
+
+ return new GeocoderParams(uid, packageName, attributionTag,
+ new Locale(language, country, variant));
+ }
+
+ public GeocoderParams[] newArray(int size) {
+ return new GeocoderParams[size];
+ }
+ };
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeInt(mUid);
+ parcel.writeString(mPackageName);
+ parcel.writeString(mAttributionTag);
parcel.writeString(mLocale.getLanguage());
parcel.writeString(mLocale.getCountry());
parcel.writeString(mLocale.getVariant());
- parcel.writeString(mPackageName);
}
}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 3493693..b61b79e 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -76,12 +76,11 @@
* obtain periodic updates of the device's geographical location, or to be notified when the device
* enters the proximity of a given geographical location.
*
- * <p class="note">Unless noted, all Location API methods require the {@link
- * android.Manifest.permission#ACCESS_COARSE_LOCATION} or {@link
- * android.Manifest.permission#ACCESS_FINE_LOCATION} permissions. If your application only has the
- * coarse permission then it will not have access to fine location providers. Other providers will
- * still return location results, but the exact location will be obfuscated to a coarse level of
- * accuracy.
+ * <p class="note">Unless otherwise noted, all Location API methods require the
+ * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} or
+ * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permissions. If your application only
+ * has the coarse permission then providers will still return location results, but the exact
+ * location will be obfuscated to a coarse level of accuracy.
*/
@SuppressWarnings({"deprecation"})
@SystemService(Context.LOCATION_SERVICE)
@@ -89,6 +88,16 @@
public class LocationManager {
/**
+ * For apps targeting Android S and above, immutable PendingIntents passed into location APIs
+ * will generate an IllegalArgumentException.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
+ public static final long BLOCK_IMMUTABLE_PENDING_INTENTS = 171317480L;
+
+ /**
* For apps targeting Android S and above, LocationRequest system APIs may not be used with
* PendingIntent location requests.
*
@@ -96,7 +105,7 @@
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
- public static final long PREVENT_PENDING_INTENT_SYSTEM_API_USAGE = 169887240L;
+ public static final long BLOCK_PENDING_INTENT_SYSTEM_API_USAGE = 169887240L;
/**
* For apps targeting Android S and above, location clients may receive historical locations
@@ -116,7 +125,7 @@
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
- private static final long GET_PROVIDER_SECURITY_EXCEPTIONS = 150935354L;
+ public static final long GET_PROVIDER_SECURITY_EXCEPTIONS = 150935354L;
/**
* For apps targeting Android K and above, supplied {@link PendingIntent}s must be targeted to a
@@ -126,7 +135,7 @@
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
- private static final long TARGETED_PENDING_INTENT = 148963590L;
+ public static final long BLOCK_UNTARGETED_PENDING_INTENTS = 148963590L;
/**
* For apps targeting Android K and above, incomplete locations may not be passed to
@@ -136,7 +145,7 @@
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
- private static final long INCOMPLETE_LOCATION = 148964793L;
+ public static final long BLOCK_INCOMPLETE_LOCATIONS = 148964793L;
/**
* For apps targeting Android S and above, all {@link GpsStatus} API usage must be replaced with
@@ -146,7 +155,7 @@
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
- private static final long GPS_STATUS_USAGE = 144027538L;
+ public static final long BLOCK_GPS_STATUS_USAGE = 144027538L;
/**
* Name of the network location provider.
@@ -1372,11 +1381,16 @@
Preconditions.checkArgument(locationRequest != null, "invalid null location request");
Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent");
- if (Compatibility.isChangeEnabled(TARGETED_PENDING_INTENT)) {
+ if (Compatibility.isChangeEnabled(BLOCK_UNTARGETED_PENDING_INTENTS)) {
Preconditions.checkArgument(pendingIntent.isTargetedToPackage(),
"pending intent must be targeted to a package");
}
+ if (Compatibility.isChangeEnabled(BLOCK_IMMUTABLE_PENDING_INTENTS)) {
+ Preconditions.checkArgument(!pendingIntent.isImmutable(),
+ "pending intent must be mutable");
+ }
+
try {
mService.registerLocationPendingIntent(provider, locationRequest, pendingIntent,
mContext.getPackageName(), mContext.getAttributionTag());
@@ -1729,7 +1743,7 @@
Preconditions.checkArgument(provider != null, "invalid null provider");
Preconditions.checkArgument(location != null, "invalid null location");
- if (Compatibility.isChangeEnabled(INCOMPLETE_LOCATION)) {
+ if (Compatibility.isChangeEnabled(BLOCK_INCOMPLETE_LOCATIONS)) {
Preconditions.checkArgument(location.isComplete(),
"incomplete location object, missing timestamp or accuracy?");
} else {
@@ -1821,29 +1835,38 @@
* {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}. From API version 17 and onwards,
* this method requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission.
*
- * @param latitude the latitude of the central point of the alert region
- * @param longitude the longitude of the central point of the alert region
- * @param radius the radius of the central point of the alert region in meters
- * @param expiration expiration realtime for this proximity alert in milliseconds, or -1 to
- * indicate no expiration
- * @param intent a {@link PendingIntent} that will sent when entry to or exit from the alert
- * region is detected
+ * @param latitude the latitude of the central point of the alert region
+ * @param longitude the longitude of the central point of the alert region
+ * @param radius the radius of the central point of the alert region in meters
+ * @param expiration expiration realtime for this proximity alert in milliseconds, or -1 to
+ * indicate no expiration
+ * @param pendingIntent a {@link PendingIntent} that will sent when entry to or exit from the
+ * alert region is detected
* @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
* permission is not present
*/
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void addProximityAlert(double latitude, double longitude, float radius, long expiration,
- @NonNull PendingIntent intent) {
- Preconditions.checkArgument(intent != null, "invalid null pending intent");
- if (Compatibility.isChangeEnabled(TARGETED_PENDING_INTENT)) {
- Preconditions.checkArgument(intent.isTargetedToPackage(),
+ @NonNull PendingIntent pendingIntent) {
+ Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent");
+
+ if (Compatibility.isChangeEnabled(BLOCK_UNTARGETED_PENDING_INTENTS)) {
+ Preconditions.checkArgument(pendingIntent.isTargetedToPackage(),
"pending intent must be targeted to a package");
}
- if (expiration < 0) expiration = Long.MAX_VALUE;
+
+ if (Compatibility.isChangeEnabled(BLOCK_IMMUTABLE_PENDING_INTENTS)) {
+ Preconditions.checkArgument(!pendingIntent.isImmutable(),
+ "pending intent must be mutable");
+ }
+
+ if (expiration < 0) {
+ expiration = Long.MAX_VALUE;
+ }
try {
Geofence fence = Geofence.createCircle(latitude, longitude, radius, expiration);
- mService.requestGeofence(fence, intent, mContext.getPackageName(),
+ mService.requestGeofence(fence, pendingIntent, mContext.getPackageName(),
mContext.getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1941,7 +1964,7 @@
@Deprecated
@RequiresPermission(ACCESS_FINE_LOCATION)
public @Nullable GpsStatus getGpsStatus(@Nullable GpsStatus status) {
- if (Compatibility.isChangeEnabled(GPS_STATUS_USAGE)) {
+ if (Compatibility.isChangeEnabled(BLOCK_GPS_STATUS_USAGE)) {
throw new UnsupportedOperationException(
"GpsStatus APIs not supported, please use GnssStatus APIs instead");
}
@@ -1976,7 +1999,7 @@
@Deprecated
@RequiresPermission(ACCESS_FINE_LOCATION)
public boolean addGpsStatusListener(GpsStatus.Listener listener) {
- if (Compatibility.isChangeEnabled(GPS_STATUS_USAGE)) {
+ if (Compatibility.isChangeEnabled(BLOCK_GPS_STATUS_USAGE)) {
throw new UnsupportedOperationException(
"GpsStatus APIs not supported, please use GnssStatus APIs instead");
}
@@ -1996,7 +2019,7 @@
*/
@Deprecated
public void removeGpsStatusListener(GpsStatus.Listener listener) {
- if (Compatibility.isChangeEnabled(GPS_STATUS_USAGE)) {
+ if (Compatibility.isChangeEnabled(BLOCK_GPS_STATUS_USAGE)) {
throw new UnsupportedOperationException(
"GpsStatus APIs not supported, please use GnssStatus APIs instead");
}
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 1d06e28..a2861c2 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -943,7 +943,7 @@
* with named endpoint channels. The samples in the frame correspond to the
* named set bits in the channel position mask, in ascending bit order.
* See {@link #setChannelIndexMask(int)} to specify channels
- * based on endpoint numbered channels. This <a href="#channelPositionMask>description of
+ * based on endpoint numbered channels. This <a href="#channelPositionMask">description of
* channel position masks</a> covers the concept in more details.
* @param channelMask describes the configuration of the audio channels.
* <p> For output, the channelMask can be an OR-ed combination of
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index 4b208ce..5c1f893 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -676,17 +676,9 @@
return null;
}
- /**
- * Instantiate a CA system of the specified system id.
- *
- * @param CA_system_id The system id of the CA system.
- *
- * @throws UnsupportedCasException if the device does not support the
- * specified CA system.
- */
- public MediaCas(int CA_system_id) throws UnsupportedCasException {
+ private void createPlugin(int casSystemId) throws UnsupportedCasException {
try {
- mCasSystemId = CA_system_id;
+ mCasSystemId = casSystemId;
mUserId = ActivityManager.getCurrentUser();
IMediaCasService service = getService();
android.hardware.cas.V1_2.IMediaCasService serviceV12 =
@@ -696,16 +688,16 @@
android.hardware.cas.V1_1.IMediaCasService.castFrom(service);
if (serviceV11 == null) {
Log.d(TAG, "Used cas@1_0 interface to create plugin");
- mICas = service.createPlugin(CA_system_id, mBinder);
+ mICas = service.createPlugin(casSystemId, mBinder);
} else {
Log.d(TAG, "Used cas@1.1 interface to create plugin");
- mICas = mICasV11 = serviceV11.createPluginExt(CA_system_id, mBinder);
+ mICas = mICasV11 = serviceV11.createPluginExt(casSystemId, mBinder);
}
} else {
Log.d(TAG, "Used cas@1.2 interface to create plugin");
mICas = mICasV11 = mICasV12 =
android.hardware.cas.V1_2.ICas
- .castFrom(serviceV12.createPluginExt(CA_system_id, mBinder));
+ .castFrom(serviceV12.createPluginExt(casSystemId, mBinder));
}
} catch(Exception e) {
Log.e(TAG, "Failed to create plugin: " + e);
@@ -713,11 +705,37 @@
} finally {
if (mICas == null) {
throw new UnsupportedCasException(
- "Unsupported CA_system_id " + CA_system_id);
+ "Unsupported casSystemId " + casSystemId);
}
}
}
+ private void registerClient(@NonNull Context context,
+ @Nullable String tvInputServiceSessionId, @PriorityHintUseCaseType int priorityHint) {
+
+ mTunerResourceManager = (TunerResourceManager)
+ context.getSystemService(Context.TV_TUNER_RESOURCE_MGR_SERVICE);
+ if (mTunerResourceManager != null) {
+ int[] clientId = new int[1];
+ ResourceClientProfile profile =
+ new ResourceClientProfile(tvInputServiceSessionId, priorityHint);
+ mTunerResourceManager.registerClientProfile(
+ profile, context.getMainExecutor(), mResourceListener, clientId);
+ mClientId = clientId[0];
+ }
+ }
+ /**
+ * Instantiate a CA system of the specified system id.
+ *
+ * @param casSystemId The system id of the CA system.
+ *
+ * @throws UnsupportedCasException if the device does not support the
+ * specified CA system.
+ */
+ public MediaCas(int casSystemId) throws UnsupportedCasException {
+ createPlugin(casSystemId);
+ }
+
/**
* Instantiate a CA system of the specified system id.
*
@@ -733,19 +751,35 @@
public MediaCas(@NonNull Context context, int casSystemId,
@Nullable String tvInputServiceSessionId,
@PriorityHintUseCaseType int priorityHint) throws UnsupportedCasException {
- this(casSystemId);
-
Objects.requireNonNull(context, "context must not be null");
- mTunerResourceManager = (TunerResourceManager)
- context.getSystemService(Context.TV_TUNER_RESOURCE_MGR_SERVICE);
- if (mTunerResourceManager != null) {
- int[] clientId = new int[1];
- ResourceClientProfile profile =
- new ResourceClientProfile(tvInputServiceSessionId, priorityHint);
- mTunerResourceManager.registerClientProfile(
- profile, context.getMainExecutor(), mResourceListener, clientId);
- mClientId = clientId[0];
- }
+ createPlugin(casSystemId);
+ registerClient(context, tvInputServiceSessionId, priorityHint);
+ }
+ /**
+ * Instantiate a CA system of the specified system id with EvenListener.
+ *
+ * @param context the context of the caller.
+ * @param casSystemId The system id of the CA system.
+ * @param tvInputServiceSessionId The Id of the session opened in TV Input Service (TIS)
+ * {@link android.media.tv.TvInputService#onCreateSession(String, String)}
+ * @param priorityHint priority hint from the use case type for new created CAS system.
+ * @param listener the event listener to be set.
+ * @param handler the handler whose looper the event listener will be called on.
+ * If handler is null, we'll try to use current thread's looper, or the main
+ * looper. If neither are available, an internal thread will be created instead.
+ *
+ * @throws UnsupportedCasException if the device does not support the
+ * specified CA system.
+ */
+ public MediaCas(@NonNull Context context, int casSystemId,
+ @Nullable String tvInputServiceSessionId,
+ @PriorityHintUseCaseType int priorityHint,
+ @Nullable Handler handler, @Nullable EventListener listener)
+ throws UnsupportedCasException {
+ Objects.requireNonNull(context, "context must not be null");
+ setEventListener(listener, handler);
+ createPlugin(casSystemId);
+ registerClient(context, tvInputServiceSessionId, priorityHint);
}
IHwBinder getBinder() {
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index df5e85e..da69c6c 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -520,11 +520,12 @@
@Override
public void applyVolumeShaper(
- @NonNull VolumeShaper.Configuration configuration,
- @NonNull VolumeShaper.Operation operation) {
+ @NonNull VolumeShaperConfiguration configuration,
+ @NonNull VolumeShaperOperation operation) {
final PlayerBase pb = mWeakPB.get();
if (pb != null) {
- pb.playerApplyVolumeShaper(configuration, operation);
+ pb.playerApplyVolumeShaper(VolumeShaper.Configuration.fromParcelable(configuration),
+ VolumeShaper.Operation.fromParcelable(operation));
}
}
}
diff --git a/media/java/android/media/PlayerProxy.java b/media/java/android/media/PlayerProxy.java
index 5f3997a..ec39128 100644
--- a/media/java/android/media/PlayerProxy.java
+++ b/media/java/android/media/PlayerProxy.java
@@ -143,7 +143,8 @@
@NonNull VolumeShaper.Configuration configuration,
@NonNull VolumeShaper.Operation operation) {
try {
- mConf.getIPlayer().applyVolumeShaper(configuration, operation);
+ mConf.getIPlayer().applyVolumeShaper(configuration.toParcelable(),
+ operation.toParcelable());
} catch (NullPointerException|RemoteException e) {
throw new IllegalStateException(
"No player to proxy for applyVolumeShaper operation,"
diff --git a/media/java/android/media/VolumeShaper.java b/media/java/android/media/VolumeShaper.java
index df8d08e..5bad693 100644
--- a/media/java/android/media/VolumeShaper.java
+++ b/media/java/android/media/VolumeShaper.java
@@ -21,6 +21,7 @@
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
+import android.os.BadParcelableException;
import android.os.Parcel;
import android.os.Parcelable;
@@ -482,50 +483,62 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- // this needs to match the native VolumeShaper.Configuration parceling
- dest.writeInt(mType);
- dest.writeInt(mId);
- if (mType != TYPE_ID) {
- dest.writeInt(mOptionFlags);
- dest.writeDouble(mDurationMs);
- // this needs to match the native Interpolator parceling
- dest.writeInt(mInterpolatorType);
- dest.writeFloat(0.f); // first slope (specifying for native side)
- dest.writeFloat(0.f); // last slope (specifying for native side)
- // mTimes and mVolumes should have the same length.
- dest.writeInt(mTimes.length);
- for (int i = 0; i < mTimes.length; ++i) {
- dest.writeFloat(mTimes[i]);
- dest.writeFloat(mVolumes[i]);
- }
- }
+ VolumeShaperConfiguration parcelable = toParcelable();
+ parcelable.writeToParcel(dest, flags);
}
- public static final @android.annotation.NonNull Parcelable.Creator<VolumeShaper.Configuration> CREATOR
- = new Parcelable.Creator<VolumeShaper.Configuration>() {
- @Override
- public VolumeShaper.Configuration createFromParcel(Parcel p) {
- // this needs to match the native VolumeShaper.Configuration parceling
- final int type = p.readInt();
- final int id = p.readInt();
- if (type == TYPE_ID) {
- return new VolumeShaper.Configuration(id);
- } else {
- final int optionFlags = p.readInt();
- final double durationMs = p.readDouble();
- // this needs to match the native Interpolator parceling
- final int interpolatorType = p.readInt();
- final float firstSlope = p.readFloat(); // ignored on the Java side
- final float lastSlope = p.readFloat(); // ignored on the Java side
- final int length = p.readInt();
- final float[] times = new float[length];
- final float[] volumes = new float[length];
- for (int i = 0; i < length; ++i) {
- times[i] = p.readFloat();
- volumes[i] = p.readFloat();
- }
+ /** @hide */
+ public VolumeShaperConfiguration toParcelable() {
+ VolumeShaperConfiguration parcelable = new VolumeShaperConfiguration();
+ parcelable.type = typeToAidl(mType);
+ parcelable.id = mId;
+ if (mType != TYPE_ID) {
+ parcelable.optionFlags = optionFlagsToAidl(mOptionFlags);
+ parcelable.durationMs = mDurationMs;
+ parcelable.interpolatorConfig = toInterpolatorParcelable();
+ }
+ return parcelable;
+ }
- return new VolumeShaper.Configuration(
+ private InterpolatorConfig toInterpolatorParcelable() {
+ InterpolatorConfig parcelable = new InterpolatorConfig();
+ parcelable.type = interpolatorTypeToAidl(mInterpolatorType);
+ parcelable.firstSlope = 0.f; // first slope (specifying for native side)
+ parcelable.lastSlope = 0.f; // last slope (specifying for native side)
+ parcelable.xy = new float[mTimes.length * 2];
+ for (int i = 0; i < mTimes.length; ++i) {
+ parcelable.xy[i * 2] = mTimes[i];
+ parcelable.xy[i * 2 + 1] = mVolumes[i];
+ }
+ return parcelable;
+ }
+
+ /** @hide */
+ public static Configuration fromParcelable(VolumeShaperConfiguration parcelable) {
+ // this needs to match the native VolumeShaper.Configuration parceling
+ final int type = typeFromAidl(parcelable.type);
+ final int id = parcelable.id;
+ if (type == TYPE_ID) {
+ return new VolumeShaper.Configuration(id);
+ } else {
+ final int optionFlags = optionFlagsFromAidl(parcelable.optionFlags);
+ final double durationMs = parcelable.durationMs;
+ final int interpolatorType = interpolatorTypeFromAidl(
+ parcelable.interpolatorConfig.type);
+ // parcelable.interpolatorConfig.firstSlope is ignored on the Java side
+ // parcelable.interpolatorConfig.lastSlope is ignored on the Java side
+ final int length = parcelable.interpolatorConfig.xy.length;
+ if (length % 2 != 0) {
+ throw new android.os.BadParcelableException("xy length must be even");
+ }
+ final float[] times = new float[length / 2];
+ final float[] volumes = new float[length / 2];
+ for (int i = 0; i < length / 2; ++i) {
+ times[i] = parcelable.interpolatorConfig.xy[i * 2];
+ volumes[i] = parcelable.interpolatorConfig.xy[i * 2 + 1];
+ }
+
+ return new VolumeShaper.Configuration(
type,
id,
optionFlags,
@@ -533,7 +546,14 @@
interpolatorType,
times,
volumes);
- }
+ }
+ }
+
+ public static final @android.annotation.NonNull Parcelable.Creator<VolumeShaper.Configuration> CREATOR
+ = new Parcelable.Creator<VolumeShaper.Configuration>() {
+ @Override
+ public VolumeShaper.Configuration createFromParcel(Parcel p) {
+ return fromParcelable(VolumeShaperConfiguration.CREATOR.createFromParcel(p));
}
@Override
@@ -542,6 +562,84 @@
}
};
+ private static @InterpolatorType
+ int interpolatorTypeFromAidl(@android.media.InterpolatorType int aidl) {
+ switch (aidl) {
+ case android.media.InterpolatorType.STEP:
+ return INTERPOLATOR_TYPE_STEP;
+ case android.media.InterpolatorType.LINEAR:
+ return INTERPOLATOR_TYPE_LINEAR;
+ case android.media.InterpolatorType.CUBIC:
+ return INTERPOLATOR_TYPE_CUBIC;
+ case android.media.InterpolatorType.CUBIC_MONOTONIC:
+ return INTERPOLATOR_TYPE_CUBIC_MONOTONIC;
+ default:
+ throw new BadParcelableException("Unknown interpolator type");
+ }
+ }
+
+ private static @android.media.InterpolatorType
+ int interpolatorTypeToAidl(@InterpolatorType int type) {
+ switch (type) {
+ case INTERPOLATOR_TYPE_STEP:
+ return android.media.InterpolatorType.STEP;
+ case INTERPOLATOR_TYPE_LINEAR:
+ return android.media.InterpolatorType.LINEAR;
+ case INTERPOLATOR_TYPE_CUBIC:
+ return android.media.InterpolatorType.CUBIC;
+ case INTERPOLATOR_TYPE_CUBIC_MONOTONIC:
+ return android.media.InterpolatorType.CUBIC_MONOTONIC;
+ default:
+ throw new RuntimeException("Unknown interpolator type");
+ }
+ }
+
+ private static @Type
+ int typeFromAidl(@android.media.VolumeShaperConfigurationType int aidl) {
+ switch (aidl) {
+ case VolumeShaperConfigurationType.ID:
+ return TYPE_ID;
+ case VolumeShaperConfigurationType.SCALE:
+ return TYPE_SCALE;
+ default:
+ throw new BadParcelableException("Unknown type");
+ }
+ }
+
+ private static @android.media.VolumeShaperConfigurationType
+ int typeToAidl(@Type int type) {
+ switch (type) {
+ case TYPE_ID:
+ return VolumeShaperConfigurationType.ID;
+ case TYPE_SCALE:
+ return VolumeShaperConfigurationType.SCALE;
+ default:
+ throw new RuntimeException("Unknown type");
+ }
+ }
+
+ private static int optionFlagsFromAidl(int aidl) {
+ int result = 0;
+ if ((aidl & (1 << VolumeShaperConfigurationOptionFlag.VOLUME_IN_DBFS)) != 0) {
+ result |= OPTION_FLAG_VOLUME_IN_DBFS;
+ }
+ if ((aidl & (1 << VolumeShaperConfigurationOptionFlag.CLOCK_TIME)) != 0) {
+ result |= OPTION_FLAG_CLOCK_TIME;
+ }
+ return result;
+ }
+
+ private static int optionFlagsToAidl(int flags) {
+ int result = 0;
+ if ((flags & OPTION_FLAG_VOLUME_IN_DBFS) != 0) {
+ result |= (1 << VolumeShaperConfigurationOptionFlag.VOLUME_IN_DBFS);
+ }
+ if ((flags & OPTION_FLAG_CLOCK_TIME) != 0) {
+ result |= (1 << VolumeShaperConfigurationOptionFlag.CLOCK_TIME);
+ }
+ return result;
+ }
+
/**
* @hide
* Constructs a {@code VolumeShaper} from an id.
@@ -1172,25 +1270,31 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- // this needs to match the native VolumeShaper.Operation parceling
- dest.writeInt(mFlags);
- dest.writeInt(mReplaceId);
- dest.writeFloat(mXOffset);
+ toParcelable().writeToParcel(dest, flags);
+ }
+
+ /** @hide */
+ public VolumeShaperOperation toParcelable() {
+ VolumeShaperOperation result = new VolumeShaperOperation();
+ result.flags = flagsToAidl(mFlags);
+ result.replaceId = mReplaceId;
+ result.xOffset = mXOffset;
+ return result;
+ }
+
+ /** @hide */
+ public static Operation fromParcelable(VolumeShaperOperation parcelable) {
+ return new VolumeShaper.Operation(
+ flagsFromAidl(parcelable.flags),
+ parcelable.replaceId,
+ parcelable.xOffset);
}
public static final @android.annotation.NonNull Parcelable.Creator<VolumeShaper.Operation> CREATOR
= new Parcelable.Creator<VolumeShaper.Operation>() {
@Override
public VolumeShaper.Operation createFromParcel(Parcel p) {
- // this needs to match the native VolumeShaper.Operation parceling
- final int flags = p.readInt();
- final int replaceId = p.readInt();
- final float xOffset = p.readFloat();
-
- return new VolumeShaper.Operation(
- flags
- , replaceId
- , xOffset);
+ return fromParcelable(VolumeShaperOperation.CREATOR.createFromParcel(p));
}
@Override
@@ -1199,6 +1303,46 @@
}
};
+ private static int flagsFromAidl(int aidl) {
+ int result = 0;
+ if ((aidl & (1 << VolumeShaperOperationFlag.REVERSE)) != 0) {
+ result |= FLAG_REVERSE;
+ }
+ if ((aidl & (1 << VolumeShaperOperationFlag.TERMINATE)) != 0) {
+ result |= FLAG_TERMINATE;
+ }
+ if ((aidl & (1 << VolumeShaperOperationFlag.JOIN)) != 0) {
+ result |= FLAG_JOIN;
+ }
+ if ((aidl & (1 << VolumeShaperOperationFlag.DELAY)) != 0) {
+ result |= FLAG_DEFER;
+ }
+ if ((aidl & (1 << VolumeShaperOperationFlag.CREATE_IF_NECESSARY)) != 0) {
+ result |= FLAG_CREATE_IF_NEEDED;
+ }
+ return result;
+ }
+
+ private static int flagsToAidl(int flags) {
+ int result = 0;
+ if ((flags & FLAG_REVERSE) != 0) {
+ result |= (1 << VolumeShaperOperationFlag.REVERSE);
+ }
+ if ((flags & FLAG_TERMINATE) != 0) {
+ result |= (1 << VolumeShaperOperationFlag.TERMINATE);
+ }
+ if ((flags & FLAG_JOIN) != 0) {
+ result |= (1 << VolumeShaperOperationFlag.JOIN);
+ }
+ if ((flags & FLAG_DEFER) != 0) {
+ result |= (1 << VolumeShaperOperationFlag.DELAY);
+ }
+ if ((flags & FLAG_CREATE_IF_NEEDED) != 0) {
+ result |= (1 << VolumeShaperOperationFlag.CREATE_IF_NECESSARY);
+ }
+ return result;
+ }
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private Operation(@Flag int flags, int replaceId, float xOffset) {
mFlags = flags;
@@ -1393,17 +1537,27 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeFloat(mVolume);
- dest.writeFloat(mXOffset);
+ toParcelable().writeToParcel(dest, flags);
+ }
+
+ /** @hide */
+ public VolumeShaperState toParcelable() {
+ VolumeShaperState result = new VolumeShaperState();
+ result.volume = mVolume;
+ result.xOffset = mXOffset;
+ return result;
+ }
+
+ /** @hide */
+ public static State fromParcelable(VolumeShaperState p) {
+ return new VolumeShaper.State(p.volume, p.xOffset);
}
public static final @android.annotation.NonNull Parcelable.Creator<VolumeShaper.State> CREATOR
= new Parcelable.Creator<VolumeShaper.State>() {
@Override
public VolumeShaper.State createFromParcel(Parcel p) {
- return new VolumeShaper.State(
- p.readFloat() // volume
- , p.readFloat()); // xOffset
+ return fromParcelable(VolumeShaperState.CREATOR.createFromParcel(p));
}
@Override
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 1881e38..5a578dd 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -122,6 +122,17 @@
android.hardware.tv.tuner.V1_1.Constants.Constant
.INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM;
/**
+ * Invalid first macroblock address in MmtpRecordEvent and TsRecordEvent.
+ *
+ * <p>Returned by {@link MmtpRecordEvent#getMbInSlice()} and
+ * {@link TsRecordEvent#getMbInSlice()} when the requested sequence number is not available.
+ *
+ * @see android.media.tv.tuner.filter.MmtpRecordEvent#getMbInSlice()
+ * @see android.media.tv.tuner.filter.TsRecordEvent#getMbInSlice()
+ */
+ public static final int INVALID_FIRST_MACROBLOCK_IN_SLICE =
+ android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_FIRST_MACROBLOCK_IN_SLICE;
+ /**
* Invalid local transport stream id.
*
* <p>Returned by {@link #linkFrontendToCiCam(int)} when the requested failed
@@ -1062,6 +1073,13 @@
}
}
+ private void onDvbcAnnexReported(int dvbcAnnex) {
+ if (mScanCallbackExecutor != null && mScanCallback != null) {
+ mScanCallbackExecutor.execute(
+ () -> mScanCallback.onDvbcAnnexReported(dvbcAnnex));
+ }
+ }
+
/**
* Opens a filter object based on the given types and buffer size.
*
diff --git a/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java b/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java
index 7060bd72..f0abce9 100644
--- a/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java
+++ b/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java
@@ -31,13 +31,16 @@
private final long mDataLength;
private final int mMpuSequenceNumber;
private final long mPts;
+ private final int mFirstMbInSlice;
// This constructor is used by JNI code only
- private MmtpRecordEvent(int scHevcIndexMask, long dataLength, int mpuSequenceNumber, long pts) {
+ private MmtpRecordEvent(int scHevcIndexMask, long dataLength, int mpuSequenceNumber, long pts,
+ int firstMbInSlice) {
mScHevcIndexMask = scHevcIndexMask;
mDataLength = dataLength;
mMpuSequenceNumber = mpuSequenceNumber;
mPts = pts;
+ mFirstMbInSlice = firstMbInSlice;
}
/**
@@ -58,6 +61,11 @@
/**
* Get the MPU sequence number of the filtered data.
+ *
+ * <p>This field is only supported in Tuner 1.1 or higher version. Unsupported version will
+ * return {@link android.media.tv.tuner.Tuner.INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM}. Use
+ * {@link android.media.tv.tuner.TunerVersionChecker.getTunerVersion()} to get the version
+ * information.
*/
public int getMpuSequenceNumber() {
return mMpuSequenceNumber;
@@ -65,10 +73,26 @@
/**
* Get the Presentation Time Stamp(PTS) for the audio or video frame. It is based on 90KHz
- * and has the same format as the PTS in ISO/IEC 13818-1. It is used only for the SC and
- * the SC_HEVC.
+ * and has the same format as the PTS in ISO/IEC 13818-1.
+ *
+ * <p>This field is only supported in Tuner 1.1 or higher version. Unsupported version will
+ * return {@link android.media.tv.tuner.Tuner.INVALID_TIMESTAMP}. Use
+ * {@link android.media.tv.tuner.TunerVersionChecker.getTunerVersion()} to get the version
+ * information.
*/
public long getPts() {
return mPts;
}
+
+ /**
+ * Get the address of the first macroblock in the slice defined in ITU-T Rec. H.264.
+ *
+ * <p>This field is only supported in Tuner 1.1 or higher version. Unsupported version will
+ * return {@link android.media.tv.tuner.Tuner.INVALID_FIRST_MACROBLOCK_IN_SLICE}. Use
+ * {@link android.media.tv.tuner.TunerVersionChecker.getTunerVersion()} to get the version
+ * information.
+ */
+ public int getFirstMbInSlice() {
+ return mFirstMbInSlice;
+ }
}
diff --git a/media/java/android/media/tv/tuner/filter/RecordSettings.java b/media/java/android/media/tv/tuner/filter/RecordSettings.java
index ec01e44..a6fd20e 100644
--- a/media/java/android/media/tv/tuner/filter/RecordSettings.java
+++ b/media/java/android/media/tv/tuner/filter/RecordSettings.java
@@ -133,8 +133,11 @@
* according to ISO/IEC 13818-1.
* @hide
*/
- @IntDef(flag = true, value = {SC_INDEX_I_FRAME, SC_INDEX_P_FRAME, SC_INDEX_B_FRAME,
- SC_INDEX_SEQUENCE})
+ @IntDef(prefix = "SC_INDEX_",
+ flag = true,
+ value = {SC_INDEX_I_FRAME, SC_INDEX_P_FRAME, SC_INDEX_B_FRAME,
+ SC_INDEX_SEQUENCE, SC_INDEX_I_SLICE, SC_INDEX_P_SLICE,
+ SC_INDEX_B_SLICE, SC_INDEX_SI_SLICE, SC_INDEX_SP_SLICE})
@Retention(RetentionPolicy.SOURCE)
public @interface ScIndex {}
@@ -154,7 +157,31 @@
* SC index for a new sequence.
*/
public static final int SC_INDEX_SEQUENCE = Constants.DemuxScIndex.SEQUENCE;
-
+ /**
+ * All blocks are coded as I blocks.
+ */
+ public static final int SC_INDEX_I_SLICE =
+ android.hardware.tv.tuner.V1_1.Constants.DemuxScIndex.I_SLICE;
+ /**
+ * Blocks are coded as I or P blocks.
+ */
+ public static final int SC_INDEX_P_SLICE =
+ android.hardware.tv.tuner.V1_1.Constants.DemuxScIndex.P_SLICE;
+ /**
+ * Blocks are coded as I, P or B blocks.
+ */
+ public static final int SC_INDEX_B_SLICE =
+ android.hardware.tv.tuner.V1_1.Constants.DemuxScIndex.B_SLICE;
+ /**
+ * A so-called switching I slice that is coded.
+ */
+ public static final int SC_INDEX_SI_SLICE =
+ android.hardware.tv.tuner.V1_1.Constants.DemuxScIndex.SI_SLICE;
+ /**
+ * A so-called switching P slice that is coded.
+ */
+ public static final int SC_INDEX_SP_SLICE =
+ android.hardware.tv.tuner.V1_1.Constants.DemuxScIndex.SP_SLICE;
/**
* Indexes can be tagged by NAL unit group in HEVC according to ISO/IEC 23008-2.
diff --git a/media/java/android/media/tv/tuner/filter/TsRecordEvent.java b/media/java/android/media/tv/tuner/filter/TsRecordEvent.java
index 258e2f2..6ea3bf8 100644
--- a/media/java/android/media/tv/tuner/filter/TsRecordEvent.java
+++ b/media/java/android/media/tv/tuner/filter/TsRecordEvent.java
@@ -33,14 +33,17 @@
private final int mScIndexMask;
private final long mDataLength;
private final long mPts;
+ private final int mFirstMbInSlice;
// This constructor is used by JNI code only
- private TsRecordEvent(int pid, int tsIndexMask, int scIndexMask, long dataLength, long pts) {
+ private TsRecordEvent(int pid, int tsIndexMask, int scIndexMask, long dataLength, long pts,
+ int firstMbInSlice) {
mPid = pid;
mTsIndexMask = tsIndexMask;
mScIndexMask = scIndexMask;
mDataLength = dataLength;
mPts = pts;
+ mFirstMbInSlice = firstMbInSlice;
}
/**
@@ -77,10 +80,26 @@
/**
* Gets the Presentation Time Stamp(PTS) for the audio or video frame. It is based on 90KHz
- * and has the same format as the PTS in ISO/IEC 13818-1. It is used only for the SC and
- * the SC_HEVC.
+ * and has the same format as the PTS in ISO/IEC 13818-1.
+ *
+ * <p>This field is only supported in Tuner 1.1 or higher version. Unsupported version will
+ * return {@link android.media.tv.tuner.Tuner.INVALID_TIMESTAMP}. Use
+ * {@link android.media.tv.tuner.TunerVersionChecker.getTunerVersion()} to get the version
+ * information.
*/
public long getPts() {
return mPts;
}
+
+ /**
+ * Get the address of the first macroblock in the slice defined in ITU-T Rec. H.264.
+ *
+ * <p>This field is only supported in Tuner 1.1 or higher version. Unsupported version will
+ * return {@link android.media.tv.tuner.Tuner.INVALID_FIRST_MACROBLOCK_IN_SLICE}. Use
+ * {@link android.media.tv.tuner.TunerVersionChecker.getTunerVersion()} to get the version
+ * information.
+ */
+ public int getFirstMbInSlice() {
+ return mFirstMbInSlice;
+ }
}
diff --git a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
index fadc004..98f8096 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
@@ -341,12 +341,13 @@
return mScanType;
}
/**
- * To receive Diseqc Message or not. Default value is false.
+ * Get if the client could handle the Diseqc Rx Message or not. Default value is false.
*
- * The setter {@link Builder#setDiseqcRxMessage(boolean)} is only supported with Tuner HAL 1.1
- * or higher.
+ * The setter {@link Builder#setCouldHandleDiseqcRxMessage(boolean)} is only supported with
+ * Tuner HAL 1.1 or higher. Use {@link TunerVersionChecker.getTunerVersion()} to check the
+ * version.
*/
- public boolean isDiseqcRxMessage() {
+ public boolean getCouldHandleDiseqcRxMessage() {
return mIsDiseqcRxMessage;
}
@@ -408,16 +409,18 @@
}
/**
- * Set true to receive Diseqc Message.
+ * Set true to indicate the client could handle the Diseqc Messages. Note that it's still
+ * possible that the client won't receive the messages when HAL is not able to setup Rx
+ * channel in the hardware layer.
*
* <p>This API is only supported by Tuner HAL 1.1 or higher. Unsupported version would cause
* no-op. Use {@link TunerVersionChecker.getTunerVersion()} to check the version.
*/
@NonNull
- public Builder setDiseqcRxMessage(boolean isDiseqcRxMessage) {
+ public Builder setCouldHandleDiseqcRxMessage(boolean couldReceiveDiseqcMessage) {
if (TunerVersionChecker.checkHigherOrEqualVersionTo(
- TunerVersionChecker.TUNER_VERSION_1_1, "setDiseqcRxMessage")) {
- mIsDiseqcRxMessage = isDiseqcRxMessage;
+ TunerVersionChecker.TUNER_VERSION_1_1, "setCouldHandleDiseqcRxMessage")) {
+ mIsDiseqcRxMessage = couldReceiveDiseqcMessage;
}
return this;
}
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
index 2147622..f8470b11 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
@@ -302,6 +302,7 @@
*
* @return the end frequency in Hz.
*/
+ @IntRange(from = 1)
public int getEndFrequency() {
return mEndFrequency;
}
@@ -341,11 +342,15 @@
*
* @param endFrequency the end frequency used during blind scan. The default value is
* {@link android.media.tv.tuner.Tuner#INVALID_FRONTEND_SETTING_FREQUENCY}.
+ * @throws IllegalArgumentException if the {@code endFrequency} is not greater than 0.
*/
@IntRange(from = 1)
public void setEndFrequency(int endFrequency) {
if (TunerVersionChecker.checkHigherOrEqualVersionTo(
TunerVersionChecker.TUNER_VERSION_1_1, "setEndFrequency")) {
+ if (endFrequency < 1) {
+ throw new IllegalArgumentException("endFrequency must be greater than 0");
+ }
mEndFrequency = endFrequency;
}
}
diff --git a/media/java/android/media/tv/tuner/frontend/ScanCallback.java b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
index 9bf7a5d..27627d7 100644
--- a/media/java/android/media/tv/tuner/frontend/ScanCallback.java
+++ b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
@@ -75,4 +75,7 @@
/** Frontend scan message priority reported. */
default void onPriorityReported(boolean isHighPriority) {}
+
+ /** DVBC Frontend Annex reported. */
+ default void onDvbcAnnexReported(@DvbcFrontendSettings.Annex int dvbcAnnex) {}
}
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 724965d..c7fb50f 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -31,6 +31,8 @@
],
shared_libs: [
+ "audioclient-types-aidl-unstable-cpp",
+ "av-types-aidl-unstable-cpp",
"libandroid_runtime",
"libaudioclient",
"libnativehelper",
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 27e1992..758f015 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -605,9 +605,13 @@
jlong pts = (eventsExt.size() > i) ? static_cast<jlong>(eventsExt[i].tsRecord().pts)
: static_cast<jlong>(Constant64Bit::INVALID_PRESENTATION_TIME_STAMP);
+ jlong firstMbInSlice = (eventsExt.size() > i)
+ ? static_cast<jint>(eventsExt[i].tsRecord().firstMbInSlice)
+ : static_cast<jint>(Constant::INVALID_FIRST_MACROBLOCK_IN_SLICE);
jobject obj =
- env->NewObject(eventClazz, eventInit, jpid, ts, sc, byteNumber, pts);
+ env->NewObject(eventClazz, eventInit, jpid, ts, sc, byteNumber,
+ pts, firstMbInSlice);
env->SetObjectArrayElement(arr, i, obj);
}
return arr;
@@ -632,10 +636,13 @@
: static_cast<jint>(Constant::INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM);
jlong pts = (eventsExt.size() > i) ? static_cast<jlong>(eventsExt[i].mmtpRecord().pts)
: static_cast<jlong>(Constant64Bit::INVALID_PRESENTATION_TIME_STAMP);
+ jlong firstMbInSlice = (eventsExt.size() > i)
+ ? static_cast<jint>(eventsExt[i].mmtpRecord().firstMbInSlice)
+ : static_cast<jint>(Constant::INVALID_FIRST_MACROBLOCK_IN_SLICE);
jobject obj =
env->NewObject(eventClazz, eventInit, scHevcIndexMask, byteNumber,
- mpuSequenceNumber, pts);
+ mpuSequenceNumber, pts, firstMbInSlice);
env->SetObjectArrayElement(arr, i, obj);
}
return arr;
@@ -1058,10 +1065,18 @@
bool isHighPriority = message.isHighPriority();
env->CallVoidMethod(
mObject,
- env->GetMethodID(clazz, "onPriorityReported", "([B)V"),
+ env->GetMethodID(clazz, "onPriorityReported", "(B)V"),
isHighPriority);
break;
}
+ case FrontendScanMessageTypeExt1_1::DVBC_ANNEX: {
+ jint dvbcAnnex = (jint) message.annex();
+ env->CallVoidMethod(
+ mObject,
+ env->GetMethodID(clazz, "onDvbcAnnexReported", "(I)V"),
+ dvbcAnnex);
+ break;
+ }
default:
break;
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
index 3def945..ec1240f 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
@@ -17,7 +17,6 @@
package com.android.systemui;
import com.android.systemui.biometrics.AuthController;
-import com.android.systemui.bubbles.dagger.BubbleModule;
import com.android.systemui.car.navigationbar.CarNavigationBar;
import com.android.systemui.car.notification.CarNotificationModule;
import com.android.systemui.car.sideloaded.SideLoadedAppController;
@@ -48,8 +47,7 @@
/** Binder for car specific {@link SystemUI} modules. */
@Module(includes = {RecentsModule.class, StatusBarModule.class, NotificationsModule.class,
- BubbleModule.class, KeyguardModule.class, OverlayWindowModule.class,
- CarNotificationModule.class})
+ KeyguardModule.class, OverlayWindowModule.class, CarNotificationModule.class})
public abstract class CarSystemUIBinder {
/** Inject into AuthController. */
@Binds
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
index 271b70d..bbcc6a2 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
@@ -108,7 +108,8 @@
}
Intent nextActivity = new Intent(intent);
- nextActivity.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ nextActivity.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
+ | Intent.FLAG_GRANT_READ_URI_PERMISSION);
// The the installation source as the nextActivity thinks this activity is the source, hence
// set the originating UID and sourceInfo explicitly
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index dd1c12a..6a563f3 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -550,9 +550,9 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Lisää vieras"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Poista vieras"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Vieras"</string>
- <string name="user_image_take_photo" msgid="467512954561638530">"Ota valokuva"</string>
+ <string name="user_image_take_photo" msgid="467512954561638530">"Ota kuva"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Valitse kuva"</string>
- <string name="user_image_photo_selector" msgid="433658323306627093">"Valitse valokuva"</string>
+ <string name="user_image_photo_selector" msgid="433658323306627093">"Valitse kuva"</string>
<string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Laitteen oletusasetus"</string>
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Ei käytössä"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Käytössä"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 08a2b99..90d49e2 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -33,11 +33,11 @@
<string name="wifi_cant_connect_to_ap" msgid="3099667989279700135">"\'<xliff:g id="AP_NAME">%1$s</xliff:g>\' સાથે કનેક્ટ કરી શકાતું નથી"</string>
<string name="wifi_check_password_try_again" msgid="8817789642851605628">"પાસવર્ડ તપાસો અને ફરી પ્રયાસ કરો"</string>
<string name="wifi_not_in_range" msgid="1541760821805777772">"રેન્જમાં નથી"</string>
- <string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"આપમેળે કનેક્ટ કરશે નહીં"</string>
+ <string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"ઑટોમૅટિક રીતે કનેક્ટ કરશે નહીં"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"કોઈ ઇન્ટરનેટ ઍક્સેસ નથી"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા સચવાયું"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s દ્વારા સ્વત: કનેક્ટ થયેલ"</string>
- <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"નેટવર્ક રેટિંગ પ્રદાતા દ્વારા આપમેળે કનેક્ટ થયું"</string>
+ <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"નેટવર્ક રેટિંગ પ્રદાતા દ્વારા ઑટોમૅટિક રીતે કનેક્ટ થયું"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s દ્વારા કનેક્ટ થયેલ"</string>
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા કનેક્ટ થયેલ"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s દ્વારા ઉપલબ્ધ"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 6a4c8c3..48421ce 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1385,4 +1385,9 @@
<!-- Name of the 3.5mm and usb audio device. [CHAR LIMIT=50] -->
<string name="media_transfer_wired_usb_device_name">Wired headphone</string>
+
+ <!-- Label for Wifi hotspot switch on. Toggles hotspot on [CHAR LIMIT=30] -->
+ <string name="wifi_hotspot_switch_on_text">On</string>
+ <!-- Label for Wifi hotspot switch off. Toggles hotspot off [CHAR LIMIT=30] -->
+ <string name="wifi_hotspot_switch_off_text">Off</string>
</resources>
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 2412a32..48eb600 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -230,6 +230,7 @@
Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR,
Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_SV,
Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_VR,
+ Settings.Global.DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS,
Settings.Global.DEVICE_DEMO_MODE,
Settings.Global.BATTERY_SAVER_ADAPTIVE_CONSTANTS,
Settings.Global.BATTERY_SAVER_CONSTANTS,
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index f9268eec..39a6ed1 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -352,7 +352,7 @@
android:exported="true" />
<activity
- android:name=".bubbles.BubbleOverflowActivity"
+ android:name="com.android.wm.shell.bubbles.BubbleOverflowActivity"
android:theme="@style/BubbleOverflow"
android:excludeFromRecents="true"
android:documentLaunchMode="always"
diff --git a/packages/SystemUI/res/drawable/bubble_dismiss_circle.xml b/packages/SystemUI/res/drawable/bubble_dismiss_circle.xml
deleted file mode 100644
index 8c7e82f..0000000
--- a/packages/SystemUI/res/drawable/bubble_dismiss_circle.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<!--
- The transparent circle outline that encircles the bubbles when they're in the dismiss target.
--->
-<shape
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="oval">
-
- <stroke
- android:width="1dp"
- android:color="#66FFFFFF" />
-
- <solid android:color="#B3000000" />
-</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/bubble_dismiss_icon.xml b/packages/SystemUI/res/drawable/bubble_dismiss_icon.xml
deleted file mode 100644
index 5c8de58..0000000
--- a/packages/SystemUI/res/drawable/bubble_dismiss_icon.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<!-- The 'X' bubble dismiss icon. This is just ic_close with a stroke. -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M19.000000,6.400000l-1.400000,-1.400000 -5.600000,5.600000 -5.600000,-5.600000 -1.400000,1.400000 5.600000,5.600000 -5.600000,5.600000 1.400000,1.400000 5.600000,-5.600000 5.600000,5.600000 1.400000,-1.400000 -5.600000,-5.600000z"
- android:fillColor="#FFFFFFFF"
- android:strokeColor="#FF000000"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_create_bubble.xml b/packages/SystemUI/res/drawable/ic_create_bubble.xml
deleted file mode 100644
index 4abbc81..0000000
--- a/packages/SystemUI/res/drawable/ic_create_bubble.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="20dp"
- android:height="20dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:fillColor="#FF000000"
- android:pathData="M23,5v8h-2V5H3v14h10v2v0H3c-1.1,0 -2,-0.9 -2,-2V5c0,-1.1 0.9,-2 2,-2h18C22.1,3 23,3.9 23,5zM10,8v2.59L5.71,6.29L4.29,7.71L8.59,12H6v2h6V8H10zM19,15c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,15 19,15z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_screenshot_scroll.xml b/packages/SystemUI/res/drawable/ic_screenshot_scroll.xml
new file mode 100644
index 0000000..c260ba9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_screenshot_scroll.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<!-- ic_unfold_more_24px.xml -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12,5.83L15.17,9l1.41,-1.41L12,3 7.41,7.59 8.83,9 12,5.83zM12,18.17L8.83,15l-1.41,1.41L12,21l4.59,-4.59L15.17,15 12,18.17z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_stop_bubble.xml b/packages/SystemUI/res/drawable/ic_stop_bubble.xml
deleted file mode 100644
index 6cf67a7..0000000
--- a/packages/SystemUI/res/drawable/ic_stop_bubble.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2020 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT 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:width="20dp"
- android:height="20dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:fillColor="#FF000000"
- android:pathData="M11.29,14.71L7,10.41V13H5V7h6v2H8.41l4.29,4.29L11.29,14.71zM21,3H3C1.9,3 1,3.9 1,5v14c0,1.1 0.9,2 2,2h10v0v-2H3V5h18v8h2V5C23,3.9 22.1,3 21,3zM19,15c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,15 19,15z"/>
-</vector>
diff --git a/packages/SystemUI/res/layout-land/global_screenshot_preview.xml b/packages/SystemUI/res/layout-land/global_screenshot_preview.xml
index 040303a..71b414f 100644
--- a/packages/SystemUI/res/layout-land/global_screenshot_preview.xml
+++ b/packages/SystemUI/res/layout-land/global_screenshot_preview.xml
@@ -28,6 +28,6 @@
android:visibility="gone"
android:background="@drawable/screenshot_rounded_corners"
android:adjustViewBounds="true"
- android:contentDescription="@string/screenshot_edit"
+ android:contentDescription="@string/screenshot_edit_label"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml
index 1b5f9c1..6c20c1e 100644
--- a/packages/SystemUI/res/layout/global_screenshot.xml
+++ b/packages/SystemUI/res/layout/global_screenshot.xml
@@ -46,7 +46,7 @@
android:layout_height="@dimen/screenshot_dismiss_button_tappable_size"
android:elevation="7dp"
android:visibility="gone"
- android:contentDescription="@string/screenshot_dismiss_ui_description">
+ android:contentDescription="@string/screenshot_dismiss_description">
<ImageView
android:id="@+id/global_screenshot_dismiss_image"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/global_screenshot_preview.xml b/packages/SystemUI/res/layout/global_screenshot_preview.xml
index c745854..5262407 100644
--- a/packages/SystemUI/res/layout/global_screenshot_preview.xml
+++ b/packages/SystemUI/res/layout/global_screenshot_preview.xml
@@ -28,6 +28,6 @@
android:visibility="gone"
android:background="@drawable/screenshot_rounded_corners"
android:adjustViewBounds="true"
- android:contentDescription="@string/screenshot_edit"
+ android:contentDescription="@string/screenshot_edit_label"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_screenshot_static.xml b/packages/SystemUI/res/layout/global_screenshot_static.xml
index 26edf3a..096ec7d 100644
--- a/packages/SystemUI/res/layout/global_screenshot_static.xml
+++ b/packages/SystemUI/res/layout/global_screenshot_static.xml
@@ -56,6 +56,9 @@
android:id="@+id/screenshot_share_chip"/>
<include layout="@layout/global_screenshot_action_chip"
android:id="@+id/screenshot_edit_chip"/>
+ <include layout="@layout/global_screenshot_action_chip"
+ android:id="@+id/screenshot_scroll_chip"
+ android:visibility="gone" />
</LinearLayout>
</HorizontalScrollView>
<include layout="@layout/global_screenshot_preview"/>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 220a773..4042ef9 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Battery, twee stawe."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Battery, drie stawe."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Battery vol."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Geen foon nie."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Foon, een staaf."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Foon, twee stawe."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profiel kan gemonitor word"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Netwerk kan dalk gemonitor word"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Netwerk kan dalk gemonitor word"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Hierdie toestel word deur jou ouer bestuur"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Jou organisasie besit hierdie toestel en kan netwerkverkeer monitor"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> besit hierdie toestel en kan netwerkverkeer monitor"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Hierdie toestel behoort aan jou organisasie en is gekoppel aan <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Deaktiveer VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Ontkoppel VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Bekyk beleide"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Bekyk kontroles"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Hierdie toestel behoort aan <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nJou IT-admin kan instellings, korporatiewe toegang, programme, data wat met jou toestel geassosieer word, en jou toestel se ligginginligting monitor en bestuur.\n\nKontak jou IT-admin vir meer inligting."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Hierdie toestel behoort aan jou organisasie.\n\nJou IT-admin kan instellings, korporatiewe toegang, programme, data wat met jou toestel geassosieer word, en jou toestel se ligginginligting monitor en bestuur.\n\nKontak jou IT-admin vir meer inligting."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Jou organisasie het \'n sertifikaatoutoriteit op hierdie toestel geïnstalleer. Jou veilige netwerkverkeer kan gemonitor of gewysig word."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Jou administrateur het netwerkloglêers aangeskakel wat verkeer op jou toestel monitor.\n\nKontak jou administrateur vir meer inligting."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Jy het \'n program toestemming gegee om \'n VPN-verbinding op te stel.\n\nHierdie program kan jou toestel- en netwerkaktiwiteit monitor, insluitend e-posse, programme en webwerwe."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Jou werkprofiel word deur <xliff:g id="ORGANIZATION">%1$s</xliff:g> bestuur.\n\nJou administrateur kan jou netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, bestuur.\n\nKontak jou administrateur vir meer inligting.\n\nJy is ook aan \'n VPN gekoppel, wat jou netwerkaktiwiteit kan monitor."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Hierdie toestel word deur jou ouer bestuur. Jou ouer kan inligting sien en bestuur soos die programme wat jy gebruik, jou ligging en jou skermtyd."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Jy is gekoppel aan <xliff:g id="APPLICATION">%1$s</xliff:g>, wat jou netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Jy is gekoppel aan <xliff:g id="APPLICATION">%1$s</xliff:g>, wat jou persoonlike netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Bind nuwe toestel saam"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Bounommer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Bounommer is na knipbord gekopieer."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index b2a7c16..e8a8a0d 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"ባትሪ ሁለት አሞሌዎች።"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"ባትሪ ሦስት አሞሌዎች።"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"ባትሪ ሙሉ ነው።"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"ምንም ስልክ የለም።"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"የስልክ አንድ አሞሌ"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"የስልክ ሁለት አሞሌ"</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"መገለጫ ክትትል ሊደረግበት ይችላል"</string>
<string name="vpn_footer" msgid="3457155078010607471">"አውታረ መረብ በክትትል እየተደረገበት ሊሆን ይችላል"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"አውታረ መረብ ክትትል የሚደረግበት ሊሆን ይችላል"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ይህ መሣሪያ በእርስዎ ወላጅ የሚተዳደር ነው።"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"የእርስዎ ድርጅት የዚህ መሣሪያ ባለቤት ነው፣ እና የአውታረ መረብ ትራፊክን ሊከታተል ይችላል"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> የዚህ መሣሪያ ባለቤት ነው፣ እና የአውታረ መረብ ትራፊክን ሊከታተል ይችላል"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"ይህ መሣሪያ የድርጅትዎ ሲሆን ከ<xliff:g id="VPN_APP">%1$s</xliff:g> ጋር ተገናኝቷል"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN አሰናክል"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"የVPN ግንኙነት አቋርጥ"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"መመሪያዎችን ይመልከቱ"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"መቆጣጠሪያዎችን አሳይ"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"ይህ መሣሪያ የ<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ነው።\n\nየእርስዎ የአይቲ አስተዳዳሪ ቅንብሮችን፣ የኮርፖሬት መዳረሻን፣ መተግበሪያዎችን፣ ከመሣሪያዎ ጋር የተጎዳኘ ውሂብን እና የመሣሪያዎ አካባቢ መረጃን መከታተል እና ማቀናበር ይችላል።\n\nተጨማሪ መረጃ የአይቲ አስተዳዳሪዎን ያነጋግሩ።"</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"ይህ መሣሪያ የድርጅትዎ ነው።\n\nየእርስዎ የአይቲ አስተዳዳሪ ቅንብሮችን፣ የኮርፖሬት መዳረሻን፣ መተግበሪያዎችን፣ ከመሣሪያዎ ጋር የተጎዳኘ ውሂብን እና የመሣሪያዎ አካባቢ መረጃን መከታተል እና ማቀናበር ይችላል።\n\nለተጨማሪ መረጃ የአይቲ አስተዳዳሪዎን ያነጋግሩ።"</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"የእርስዎ ድርጅት የእውቅና ማረጋገጫ ሰጪ ባለሥልጣን በዚህ መሣሪያ ላይ ጭኗል። የእርስዎ ደኅንነቱ የተጠበቀ አውታረ መረብ ትራፊክ ክትትል ሊደረግበት እና ሊሻሻል ይችላል።"</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"የእርስዎ አስተዳዳሪ የአውታረ መረብ ምዝግብ ማስታወሻ መያዝን አብርተዋል፣ ይህም በመሣሪያዎ ላይ ያለውን ትራፊክ ይከታተላል።\n\nተጨማሪ መረጃ ለማግኘት አስተዳዳሪዎን ያነጋግሩ።"</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"አንድ መተግበሪያ የVPN ግንኙነት እንዲያዋቅር ፍቃድ ሰጥተውታል።\n\nይህ መተግበሪያ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የመሣሪያዎን እና የአውታረ መረብ እንቅስቃሴዎን መከታተል ይችላል።"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"የእርስዎ የስራ መገለጫ በ<xliff:g id="ORGANIZATION">%1$s</xliff:g> ነው የሚቀናበረው።\n\nየእርስዎ አስተዳዳሪ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችን ጨምሮ የአውታረ መረብ እንቅስቃሴዎን መከታተል ይችላል።\n\nተጨማሪ መረጃ ለማግኘት አስተዳዳሪዎን ያነጋግሩ።\n\nእርስዎ እንዲሁም የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችል ቪፒኤን ጋር ተገናኝተዋል።"</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ይህ መሣሪያ በእርስዎ ወላጅ የሚተዳደር ነው። ወላጅዎ የሚጠቀሙባቸውን መተግበሪያዎች፣ አካባቢዎን እና የማያ ገጽ ጊዜዎን የመሳሰሉ መረጃዎችን ማየት እና ማስተዳደር ይችላል።"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"እርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የአውታረ መረብ እንቅስቃሴዎን ከሚከታተለው <xliff:g id="APPLICATION">%1$s</xliff:g> ጋር ተገናኝተዋል።"</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"እርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የግል የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION">%1$s</xliff:g> ጋር ተገናኝተዋል።"</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"አዲስ መሣሪያ ያጣምሩ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"የግንብ ቁጥር"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"የገንባ ቁጥር ወደ ቅንጥብ ሰሌዳ ተቀድቷል።"</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 2cced23..83940bf 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"إشارة البطارية تتكون من شريطين."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"إشارة البطارية تتكون من ثلاثة أشرطة."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"إشارة البطارية كاملة."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"ليست هناك إشارة بالهاتف."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"إشارة الهاتف تتكون من شريط واحد."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"إشارة الهاتف تتكون من شريطين."</string>
@@ -532,6 +534,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"ربما تتم مراقبة الملف الشخصي"</string>
<string name="vpn_footer" msgid="3457155078010607471">"قد تكون الشبكة خاضعة للمراقبة"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"قد تكون الشبكة خاضعة للمراقبة"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"يتولّى أحد الوالدين إدارة هذا الجهاز."</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"تملك مؤسستك هذا الجهاز ويمكنها تتبّع حركة بيانات الشبكة."</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"تملك مؤسسة <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> هذا الجهاز ويمكنها تتبّع حركة بيانات الشبكة"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"هذا الجهاز يخص مؤسستك وتم ربطه بشبكة <xliff:g id="VPN_APP">%1$s</xliff:g>."</string>
@@ -556,6 +559,7 @@
<string name="disable_vpn" msgid="482685974985502922">"إيقاف الشبكة الافتراضية الخاصة"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"قطع الاتصال بشبكة VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"عرض السياسات"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"عرض عناصر التحكم"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"هذا الجهاز يخص <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nيمكن لمشرف تكنولوجيا المعلومات تتبّع وإدارة الإعدادات والتطبيقات والبيانات المرتبطة بجهازك ومعلومات الموقع الجغرافي للجهاز وعمليات الدخول إلى نظام المؤسسة.\n\nللحصول على المزيد من المعلومات، يمكنك التواصل مع مشرف تكنولوجيا المعلومات."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"هذا الجهاز يخص مؤسستك.\n\nيمكن لمشرف تكنولوجيا المعلومات في مؤسستك تتبّع وإدارة الإعدادات والتطبيقات والبيانات المرتبطة بجهازك ومعلومات الموقع الجغرافي للجهاز وعمليات الدخول إلى نظام المؤسسة.\n\nللحصول على المزيد من المعلومات، يمكنك التواصل مع مشرف تكنولوجيا المعلومات."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"ثبّتت مؤسستك مرجعًا مصدّقًا على هذا الجهاز. قد تتم مراقبة حركة بيانات شبكتك الآمنة أو تعديلها."</string>
@@ -579,6 +583,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"شغَّل المشرف ميزة تسجيل بيانات الشبكة، والتي يتم من خلالها مراقبة حركة البيانات على جهازك.\n\nللحصول على المزيد من المعلومات، اتصل بالمشرف."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"لقد منحت تطبيقًا الإذن لإعداد اتصال شبكة افتراضية خاصة (VPN).\n\nيمكن لهذا التطبيق مراقبة أنشطتك على الجهاز والشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"تتم إدارة ملفك الشخصي للعمل بواسطة <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nويمكن للمشرف مراقبة نشاط الشبكة، بما في ذلك رسائل البريد الإلكتروني والتطبيقات والمواقع الإلكترونية.\n\nللحصول على المزيد من المعلومات، اتصل بالمشرف.\n\nوتجدر الإشارة إلى أنك متصل أيضًا بشبكة افتراضية خاصة يمكن أن تراقب نشاط الشبكة."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"يتولّى أحد الوالدين إدارة هذا الجهاز. يمكن للوالدين عرض وإدارة معلوماتك، مثلاً التطبيقات التي تستخدمها وموقعك الجغرافي ووقت النظر إلى الشاشة."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"شبكة افتراضية خاصة"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"تم ربطك بـ <xliff:g id="APPLICATION">%1$s</xliff:g>، الذي يمكنه مراقبة أنشطتك على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"أنت متصل بـ <xliff:g id="APPLICATION">%1$s</xliff:g>، الذي يمكنه مراقبة أنشطتك الشخصية على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
@@ -1113,4 +1118,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"إقران جهاز جديد"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"رقم الإصدار"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"تم نسخ رقم الإصدار إلى الحافظة."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 4c43e4e..5444b53 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"বেটাৰিৰ দুডাল দণ্ড।"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"বেটাৰিৰ তিনিডাল দণ্ড।"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"বেটাৰি পূৰাকৈ চ্চাৰ্জ হৈছে।"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"ফ\'নত ছিগনেল নাই৷"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"ফ\'ন ছিগনেলৰ এডাল দণ্ড।"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"ফ\'ন ছিগনেলৰ দুডাল দণ্ড।"</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"প্ৰ\'ফাইল নিৰীক্ষণ কৰা হ\'ব পাৰে"</string>
<string name="vpn_footer" msgid="3457155078010607471">"নেটৱৰ্ক নিৰীক্ষণ কৰা হ\'ব পাৰে"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"নেটৱৰ্ক নিৰীক্ষণ কৰা হ\'ব পাৰে"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"এই ডিভাইচটো আপোনাৰ অভিভাৱকে পৰিচালনা কৰে"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"এই ডিভাইচটোৰ গৰাকী আপোনাৰ প্ৰতিষ্ঠান আৰু ই নেটৱৰ্কৰ ট্ৰেফিক নিৰীক্ষণ কৰিব পাৰে"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"এই ডিভাইচটোৰ গৰাকী <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> আৰু এইটোৱে নেটৱৰ্কৰ ট্ৰেফিক নিৰীক্ষণ কৰিব পাৰে"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"এই ডিভাইচটো আপোনাৰ প্ৰতিষ্ঠানৰ আৰু এইটো <xliff:g id="VPN_APP">%1$s</xliff:g>ৰ সৈতে সংযুক্ত হৈ আছে"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"ভিপিএন অক্ষম কৰক"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"ভিপিএন সংযোগ বিচ্ছিন্ন কৰক"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"নীতিসমূহ চাওক"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"নিয়ন্ত্ৰণসমূহ চাওক"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"এই ডিভাইচটো <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>ৰ।\n\nআপোনাৰ আইটি প্ৰশাসকে আপোনাৰ ডিভাইচটোৰ লগত জড়িত ছেটিংসমূহ, কৰ্পৰে’টৰ এক্সেছ, এপ্সমূহ, ডেটা আৰু আপোনাৰ ডিভাইচটোৰ অৱস্থান সম্পৰ্কীয় তথ্য নিৰীক্ষণ কৰাৰ লগতে সেয়া পৰিচালনা কৰিব পাৰে।\n\nঅধিক তথ্যৰ বাবে আপোনাৰ আইটি প্ৰশাসকৰ সৈতে যোগাযোগ কৰক।"</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"এই ডিভাইচটো আপোনাৰ প্ৰতিষ্ঠানৰ।\n\nআপোনাৰ আইটি প্ৰশাসকে আপোনাৰ ডিভাইচটোৰ লগত জড়িত ছেটিংসমূহ, কৰ্পৰে’টৰ এক্সেছ, এপ্সমূহ, ডেটা আৰু আপোনাৰ ডিভাইচটোৰ অৱস্থান সম্পৰ্কীয় তথ্য নিৰীক্ষণ কৰাৰ লগতে সেয়া পৰিচালনা কৰিব পাৰে।\n\nঅধিক তথ্যৰ বাবে আপোনাৰ আইটি প্ৰশাসকৰ সৈতে যোগাযোগ কৰক।"</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"আপোনাৰ প্ৰতিষ্ঠানে এই ডিভাইচটোত এটা প্ৰমাণপত্ৰ সম্পৰ্কীয় কৰ্তৃপক্ষ ইনষ্টল কৰিছে। আপোনাৰ সুৰক্ষিত নেটৱৰ্ক ট্ৰেফিক পৰ্যবেক্ষণ বা সংশোধন কৰা হ\'ব পাৰে।"</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"আপোনাৰ প্ৰশাসকে নেটৱৰ্ক লগিং অন কৰিছে, যিয়ে আপোনাৰ ডিভাইচটোত নেটৱৰ্ক ট্ৰেফিক পৰ্যবেক্ষণ কৰে।\n\nএই সম্পৰ্কে অধিক জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক।"</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"আপুনি এটা এপক ভিপিএন সংযোগ ছেট আপ কৰিবলৈ অনুমতি দিছে। \n\n এই এপটোৱে ইমেইল, এপ্ আৰু ৱেবছাইটকে ধৰি আপোনাৰ নেটৱর্কৰ কাৰ্যকলাপ পৰ্যবেক্ষণ কৰিব পাৰে।"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g>য়ে আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইল পৰিচালনা কৰে।\n\nআপোনাৰ প্ৰশাসকে ইমেইল, এপসমূহ আৰু আপুনি চোৱা ৱেবছাইটকে ধৰি আপোনাৰ নেটৱৰ্কৰ সকলো কাৰ্যকলাপ পৰ্যবেক্ষণ কৰিব পাৰে। \n\nঅধিক তথ্যৰ বাবে আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক।\n\nইয়াৰ উপৰি, আপুনি এটা ভিপিএনৰ সৈতে সংযুক্ত হৈ আছে, যিয়ে আপোনাৰ নেটৱৰ্কৰ কাৰ্যকলাপ পৰ্যবেক্ষণ কৰিব পাৰে।"</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"এই ডিভাইচটো আপোনাৰ অভিভাৱকে পৰিচালনা কৰে। আপোনাৰ অভিভাৱকে আপুনি ব্যৱহাৰ কৰা এপ্, আপোনাৰ অৱস্থান আৰু আপুনি ডিভাইচত অতিবাহিত কৰা সময়ৰ দৰে তথ্য চাব আৰু পৰিচালনা কৰিব পাৰে।"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"ভিপিএন"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"আপুনি <xliff:g id="APPLICATION">%1$s</xliff:g>ৰে সংযুক্ত হৈ আছে যিয়ে আপোনাৰ ইমেইল, এপ্ আৰু ৱেবছাইটকে ধৰি নেটৱর্কৰ কাৰ্যকলাপ পৰ্যবেক্ষণ কৰিব পাৰে।"</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"আপুনি <xliff:g id="APPLICATION">%1$s</xliff:g>ৰে সংযুক্ত হৈ আছে, যি ইমেইল, এপ্ আৰু ৱেবছাইটসমূহকে ধৰি আপোনাৰ ব্যক্তিগত নেটৱর্কৰ কাৰ্যকলাপ নিৰীক্ষণ কৰিব পাৰে।"</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"নতুন ডিভাইচ পেয়াৰ কৰক"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"বিল্ডৰ নম্বৰ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ক্লিপব’ৰ্ডলৈ বিল্ডৰ নম্বৰ প্ৰতিলিপি কৰা হ’ল।"</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 4cefd84..f97b334 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Batareya iki xətdir."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Batareya üç xətdir."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batareya doludur"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Telefon yoxdur."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Şəbəkə bir xətdir."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Şəbəkə iki xətdir."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profil izlənə bilər"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Şəbəkə nəzərdən keçirilə bilər"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Şəbəkə nəzərdən keçirilə bilər"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Bu cihaz valideyniniz tərəfindən idarə olunur"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Təşkilatınız bu cihazın sahibidir və şəbəkə trafikinə nəzarət edə bilər"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> bu cihazın sahibidir və şəbəkə trafikinə nəzarət edə bilər"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Bu cihaz təşkilatınıza məxsusdur və <xliff:g id="VPN_APP">%1$s</xliff:g> şəbəkəsinə qoşulub"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN-i deaktiv edin"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN-i bağlantıdan ayırın"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Siyasətlərə Baxın"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Nizamlayıcılara baxın"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Bu cihaz <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> təşkilatına məxsusdur.\n\nIT admininiz cihaz və cihaz məkan məlumatı ilə əlaqəli ayarlara, korporativ girişə, tətbiqə və dataya nəzarət edə və idarə edə bilər.\n\nƏtraflı məlumat üçün IT admini ilə əlaqə saxlayın."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Bu cihaz təşkilatınıza məxsusdur.\n\nIT admininiz cihaz və cihaz məkan məlumatı ilə əlaqəli ayarlara, korporativ girişə, tətbiqə və dataya nəzarət edə və idarə edə bilər.\n\nƏtraflı məlumat üçün IT admini ilə əlaqə saxlayın."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Təşkilat bu cihazda sertifikat səlahiyyəti quraşdırdı. Təhlükəsiz şəbəkə ötürülməsinə nəzarət edilə və ya dəyişdirilə bilər."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Admin, cihazdakı trafikə nəzarət edən şəbəkə loqlarını aktiv etdi.\n\nƏtraflı məlumat üçün administrator ilə əlaqə saxlayın."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"VPN bağlantısı quraşdırmağa icazə vermisiniz.\n\nBu tətbiq cihazınızı və şəbəkə fəaliyyətinizi, həmçinin, e-məktubları, tətbiq və veb saytları izləyə bilər."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tərəfindən idarə olunur.\n\nAdmin e-poçt, tətbiq və veb saytlar daxil olmaqla şəbəkə fəaliyətinizə nəzarət etməyə qadirdir.\n\nƏtraflı məlumat üçün administrator ilə əlaqə saxlayın.\n\nEyni zamanda, şəbəkə fəaliyyətinizə nəzarət edən VPN\'ə qoşulusunuz."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Bu cihaz valideyniniz tərəfindən idarə olunur. Valideyniniz istifadə etdiyiniz tətbiqlər, məkanınız və ekran vaxtınız kimi məlumatları görə və idarə edə bilər."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN (Virtual Şəxsi Şəbəkələr)"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"E-poçt, tətbiq və veb saytlar da daxil olmaqla şəbəkə fəaliyyətinə nəzarət edən <xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə qoşulusunuz."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə qoşulmusunuz və o, e-məktublar, tətbiq və veb saytlar daxil olmaqla şəxsi şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yeni cihazı qoşalaşdırın"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versiya nömrəsi"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versiya nömrəsi mübadilə buferinə kopyalandı."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 68ef1a3..48e5b72 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Baterija od dve crte."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Baterija od tri crte."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Baterija je puna."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Nema telefona."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Signal telefona ima jednu crtu."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Signal telefona od dve crte."</string>
@@ -523,6 +525,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profil se možda nadgleda"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Mreža se možda nadgleda"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Mreža se možda nadgleda"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Ovim uređajem upravlja roditelj"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Organizacija je vlasnik uređaja i može da nadgleda mrežni saobraćaj"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> je vlasnik ovog uređaja i može da nadgleda mrežni saobraćaj"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Ovaj uređaj pripada organizaciji i povezan je sa aplikacijom <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -547,6 +550,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Onemogući VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Prekini vezu sa VPN-om"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Prikaži smernice"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Prikaži kontrole"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Ovaj uređaj pripada organizaciji <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nIT administrator može da nadgleda podešavanja, korporativni pristup, aplikacije, podatke povezane sa uređajem i informacije o lokaciji uređaja, kao i da upravlja njima.\n\nViše informacija potražite od IT administratora."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Ovaj uređaj pripada organizaciji.\n\nIT administrator može da nadgleda podešavanja, korporativni pristup, aplikacije, podatke povezane sa uređajem i informacije o lokaciji uređaja, kao i da upravlja njima.\n\nViše informacija potražite od IT administratora."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Organizacija je na ovom uređaju instalirala autoritet za izdavanje sertifikata. Bezbedni mrežni saobraćaj može da se prati ili menja."</string>
@@ -570,6 +574,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Administrator je uključio evidentiranje mreže, koje prati saobraćaj na uređaju.\n\nKontaktirajte administratora za više informacija."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Dali ste dozvolu aplikaciji da podešava VPN vezu.\n\nTa aplikacija može da nadgleda aktivnosti na uređaju i mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> upravlja poslovnim profilom.\n\nAdministrator može da prati aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nKontaktirajte administratora za više informacija.\n\nPovezani ste i sa VPN-om, koji može da prati aktivnosti na mreži."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Ovim uređajem upravlja roditelj. Roditelj može da vidi informacije, kao što su aplikacije koje koristiš, tvoju lokaciju i vreme ispred ekrana, i da upravlja njima."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
@@ -1095,4 +1100,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Upari novi uređaj"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj verzije"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Broj verzije je kopiran u privremenu memoriju."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 6396cbe..ed57fb3 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"2 планкі акумулятара."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Тры планкі акумулятара."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Акумулятар поўны."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Няма тэлефона."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Адна планка на тэлефоне."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"2 планкі тэлефона."</string>
@@ -526,6 +528,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"За профілем могуць назіраць"</string>
<string name="vpn_footer" msgid="3457155078010607471">"За сеткай могуць назіраць"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"За сеткай могуць назіраць"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Гэта прылада знаходзіцца пад кантролем вашых бацькоў"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Ваша арганізацыя валодае гэтай прыладай і можа кантраляваць сеткавы трафік"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> валодае гэтай прыладай і можа кантраляваць сеткавы трафік"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Гэта прылада належыць вашай арганізацыі і падключана да праграмы \"<xliff:g id="VPN_APP">%1$s</xliff:g>\""</string>
@@ -550,6 +553,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Адключыць VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Адлучыць VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Праглядзець палітыку"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Праглядзець даныя пра кантроль"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Гэта прылада належыць арганізацыі \"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>\".\n\nВаш ІТ-адміністратар можа адсочваць налады, карпаратыўны доступ, праграмы, даныя, звязаныя з вашай прыладай, і звесткі пра яе месцазнаходжанне, а таксама кіраваць імі.\n\nПа дадатковую інфармацыю звярніцеся да ІТ-адміністратара."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Гэта прылада належыць вашай арганізацыі.\n\nВаш ІТ-адміністратар можа адсочваць налады, карпаратыўны доступ, праграмы, даныя, звязаныя з вашай прыладай, і звесткі пра яе месцазнаходжанне, а таксама кіраваць імі.\n\nПа дадатковую інфармацыю звярніцеся да ІТ-адміністратара."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Ваша арганізацыя ўсталявала на гэтай прыладзе цэнтр сертыфікацыі. Ваш абаронены сеткавы трафік могуць праглядваць ці змяняць."</string>
@@ -573,6 +577,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Ваш адміністратар уключыў вядзенне журнала сеткі, з дапамогай якога адсочваецца трафік на вашай прыладзе.\n\nДля атрымання дадатковай інфармацыі звярніцеся да адміністратара."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Вы далі праграме дазвол на наладжванне злучэння VPN.\n\nГэта праграма можа сачыць за актыўнасцю вашай прылады і вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Ваш працоўны профіль знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nВаш адміністратар можа сачыць за вашай сеткавай дзейнасцю, уключаючы электронную пошту, праграмы і вэб-сайты.\n\nДля атрымання дадатковай інфармацыі звярніцеся да адміністратара.\n\nВы таксама падключаны да сеткі VPN, якая можа сачыць за вашай сеткавай дзейнасцю."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Гэта прылада знаходзіцца пад кантролем вашых бацькоў. Бацькі могуць праглядаць і кантраляваць вашу інфармацыю, напрыклад пра праграмы, якія вы выкарыстоўваеце, даныя пра ваша месцазнаходжанне і час карыстання прыладай."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Вы падключаны да праграмы <xliff:g id="APPLICATION">%1$s</xliff:g>, якая можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Вы падлучаны да праграмы <xliff:g id="APPLICATION">%1$s</xliff:g>, якая сачыць за вашай асабістай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
@@ -1101,4 +1106,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Спалучыць з новай прыладай"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Нумар зборкі"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Нумар зборкі скапіраваны ў буфер абмену."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 26a313a..c968e6d 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Батерията е с две чертички."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Батерията е с три чертички."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Батерията е пълна."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Няма телефон."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Телефонът е с една чертичка."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Телефонът е с две чертички."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Възможно е потребителският профил да се наблюдава"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Мрежата може да се наблюдава"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Мрежата може да се наблюдава"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Това устройство се управлява от родителя ви"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Организацията ви притежава това устройство и може да наблюдава трафика в мрежата"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> притежава това устройство и може да наблюдава трафика в мрежата"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Това устройство принадлежи на организацията ви и е свързано с(ъс) <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Деактивиране на VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Прекратяване на връзката с VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Преглед на правилата"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Преглед на контролите"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Това устройство принадлежи на <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nСистемният ви администратор може да наблюдава и управлява настройките, корпоративния достъп, приложенията, свързаните с устройството данни и информацията за местоположението му.\n\nЗа повече информация се обърнете към него."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Това устройство принадлежи на организацията ви.\n\nСистемният ви администратор може да наблюдава и управлява настройките, корпоративния достъп, приложенията, свързаните с устройството данни и информацията за местоположението му.\n\nЗа повече информация се обърнете към него."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Организацията ви е инсталирала сертифициращ орган на това устройство. Трафикът в защитената ви мрежа може да бъде наблюдаван или променян."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Администраторът ви е включил функцията за регистриране на мрежовата активност, която следи трафика на устройството ви.\n\nЗа повече информация се свържете с администратора си."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Разрешихте на приложение да настрои връзка с виртуална частна мрежа (VPN).\n\nТова приложение може да наблюдава активността ви на устройството и в мрежата, включително имейли, приложения и уебсайтове."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Служебният ви потребителски профил се управлява от <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nАдминистраторът ви може да наблюдава активността ви в мрежата, включително имейли, приложения и уебсайтове.\n\nЗа повече информация се свържете с администратора си.\n\nСъщо така е установена връзка с виртуална частна мрежа (VPN) и активността ви в нея може да се наблюдава."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Това устройство се управлява от родителя ви. Той може да вижда и управлява информация, като например приложенията, които използвате, местоположението ви и времето на ползване."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Установена е връзка с приложението <xliff:g id="APPLICATION">%1$s</xliff:g>, което може да наблюдава активността ви в мрежата, включително имейли, приложения и уебсайтове."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Установена е връзка с приложението <xliff:g id="APPLICATION">%1$s</xliff:g>, което може да наблюдава личната ви активност в мрежата, включително имейли, приложения и уебсайтове."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Сдвояване на ново устройство"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер на компилацията"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Номерът на компилацията е копиран в буферната памет."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index c4c6a0c..c225fd3 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"দুই দন্ড ব্যাটারি রয়েছে৷"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"তিন দন্ড ব্যাটারি রয়েছে৷"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"ব্যাটারি পূর্ণ রয়েছে৷"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"কোনো ফোনের সংকেত নেই৷"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"এক দন্ড ফোনের সংকেত রয়েছে৷"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"দুই দন্ড ফোনের সংকেত রয়েছে৷"</string>
@@ -520,6 +522,8 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"প্রোফাইল পর্যবেক্ষণ করা হতে পারে"</string>
<string name="vpn_footer" msgid="3457155078010607471">"নেটওয়ার্ক নিরীক্ষণ করা হতে পারে"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"নেটওয়ার্ক নিরীক্ষণ করা হতে পারে"</string>
+ <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
+ <skip />
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"এই ডিভাইসটি আপনার প্রতিষ্ঠানের এবং এরা ডিভাইসের নেটওয়ার্ক ট্রাফিক মনিটর করতে পারে"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> এই ডিভাইসের মালিক এবং এটির নেটওয়ার্ক ট্রাফিক মনিটর করতে পারে"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"এই ডিভাইসটি আপনার প্রতিষ্ঠানের এবং <xliff:g id="VPN_APP">%1$s</xliff:g>-এ কানেক্ট করা আছে"</string>
@@ -544,6 +548,8 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN অক্ষম করুন"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN এর সংযোগ বিচ্ছিন্ন করুন"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"নীতিগুলি দেখুন"</string>
+ <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
+ <skip />
<string name="monitoring_description_named_management" msgid="505833016545056036">"এই ডিভাইসটি <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>-এর।\n\nআপনার আইটি অ্যাডমিন এই ডিভাইসের সেটিংস, কর্পোরেট অ্যাক্সেস, অ্যাপ, ডিভাইসের সাথে সম্পর্কিত ডেটা এবং ডিভাইসের লোকেশন সম্পর্কিত ডেটা মনিটর ও ম্যানেজ করতে পারে।\n\nআরও তথ্যের জন্য আপনার আইটি অ্যাডমিনের সাথে যোগাযোগ করুন।"</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"এই ডিভাইসটি আপনার প্রতিষ্ঠানের।\n\nআপনার আইটি অ্যাডমিন এই ডিভাইসের সেটিংস, কর্পোরেট অ্যাক্সেস, অ্যাপ, ডিভাইসের সাথে সম্পর্কিত ডেটা এবং ডিভাইসের লোকেশন সম্পর্কিত ডেটা মনিটর ও ম্যানেজ করতে পারে।\n\nআরও তথ্যের জন্য আপনার আইটি অ্যাডমিনের সাথে যোগাযোগ করুন।"</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"আপনার প্রতিষ্ঠান আপনার অফিস প্রোফাইলে একটি সার্টিফিকেট কর্তৃপক্ষ ইনস্টল করেছে।আপনার সুরক্ষিত নেটওয়ার্ক ট্রাফিক নিরীক্ষণ বা পরিবর্তন করা হতে পারে।"</string>
@@ -567,6 +573,8 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"আপনার প্রশাসক নেটওয়ার্ক লগিং চালু করেছেন, যা আপনার ডিভাইসের ট্রাফিক নিরীক্ষণ করে।\n\nআরও তথ্যের জন্য আপনার প্রশাসকের সাথে যোগাযোগ করুন।"</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"আপনি VPN সংযোগ সেট-আপ করার জন্য একটি অ্যাপ্লিকেশানকে অনুমতি দিন৷\n\nএই অ্যাপ্লিকেশানটি ইমেল, অ্যাপ্লিকেশান ও ওয়েবসাইটগুলি সহ আপনার ডিভাইস এবং নেটওয়ার্কের অ্যাক্টিভিটি নিরীক্ষণ করতে পারে।"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"আপনার কর্মস্থলের প্রোফাইলটি <xliff:g id="ORGANIZATION">%1$s</xliff:g> দ্বারা পরিচালিত হয়।\n\nআপনার প্রশাসক আপনার ইমেল, অ্যাপ্স ও ওয়েবসাইট সহ কর্মস্থলের নেটওয়ার্ক অ্যাক্টিভিটি নিরীক্ষণ করতে পারেন।\n\nআরও তথ্যের জন্য আপনার প্রশাসকের সঙ্গে যোগাযোগ করুন।\n\nএছাড়া আপনি একটি VPN এর সাথেও সংযুক্ত যা আপনার নেটওয়ার্ক অ্যাক্টিভিটি নিরীক্ষণ করতে পারে।"</string>
+ <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
+ <skip />
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> এর সাথে সংযুক্ত রয়েছেন, যেটি ইমেল, অ্যাপ, এবং ওয়েবসাইট সহ আপনার নেটওয়ার্ক কার্যকলাপে নজর রাখতে পারে৷"</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> -এ সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ্লিকেশান এবং ওয়েবসাইটগুলি সমেত আপনার ব্যক্তিগত নেটওয়ার্ক অ্যাক্টিভিটি নিরীক্ষণ করতে পারে৷"</string>
@@ -1089,4 +1097,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"নতুন ডিভাইস পেয়ার করুন"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"বিল্ড নম্বর"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"বিল্ড নম্বর ক্লিপবোর্ডে কপি করা হয়েছে।"</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 75a2d1c..344bb63 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Baterija na dvije crtice."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Baterija na tri crtice."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Baterija je puna."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Nema telefonskog signala."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefonski signal na jednoj crtici."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefonski signal na dvije crtice."</string>
@@ -523,6 +525,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profil može biti nadziran"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Mreža može biti nadzirana"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Mreža može biti nadzirana"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Ovim uređajem upravlja tvoj roditelj"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Vaša organizacija je vlasnik ovog uređaja i može nadzirati mrežni saobraćaj"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> upravlja ovim uređajem i može nadzirati mrežni saobraćaj"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Ovaj uređaj pripada vašoj organizaciji i povezan je s aplikacijom <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -547,6 +550,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Isključi VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Prekini VPN vezu"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Prikaži pravila"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Prikaži kontrole"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Ovaj uređaj pripada organizaciji <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nVaš IT administrator može nadzirati postavke, korporativni pristup, aplikacije, podatke povezane s vašim uređajem i informacije o lokaciji uređaja te njima upravljati.\n\nZa više informacija kontaktirajte IT administratora."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Ovaj uređaj pripada vašoj organizaciji.\n\nVaš IT administrator može nadzirati postavke, korporativni pristup, aplikacije, podatke povezane s vašim uređajem i informacije o lokaciji uređaja te njima upravljati.\n\nZa više informacija kontaktirajte IT administratora."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Vaša organizacija je instalirala CA certifikat na ovom uređaju. Vaš saobraćaj preko sigurne mreže može se pratiti."</string>
@@ -570,6 +574,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Vaš administrator je uključio zapisivanje na mreži, čime se prati saobraćaj na vašem uređaju.\n\nZa više informacija, obratite se administratoru."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Jednoj aplikaciji ste dali odobrenje da uspostavi VPN vezu.\n\nTa aplikacija može pratiti vašu aktivnost na uređaju i mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Vašim radnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVaš administrator može pratiti vašu aktivnost na radnoj mreži, uključujući e-poruke, aplikacije i web lokacije.\n\nZa više informacija, obratite se administratoru.\n\nPovezani ste i na VPN, koji može pratiti vašu aktivnost na mreži."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Ovim uređajem upravlja tvoj roditelj. Roditelj može vidjeti i upravljati informacijama kao što su aplikacije koje koristiš, lokacija i vrijeme korištenja uređaja."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Povezani ste s aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može pratiti vašu aktivnost na mreži, uključujući e-poruke, aplikacije i web lokacije."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može pratiti vašu aktivnost na privatnoj mreži, uključujući e-mailove, aplikacije i web-lokacije."</string>
@@ -1095,4 +1100,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uparite novi uređaj"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj verzije"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Broj verzije je kopiran u međumemoriju."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 2b6dfd5..0ed3ac1 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Bateria: dues barres."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Bateria: tres barres."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Bateria carregada."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"No hi ha senyal de telèfon."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Senyal de telèfon: una barra"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Senyal de telèfon: dues barres."</string>
@@ -446,7 +448,7 @@
<string name="zen_priority_introduction" msgid="3159291973383796646">"No t\'interromprà cap so ni cap vibració, tret dels de les alarmes, recordatoris, esdeveniments i trucades de les persones que especifiquis. Continuaràs sentint tot allò que decideixis reproduir, com ara música, vídeos i jocs."</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"No t\'interromprà cap so ni cap vibració, tret dels de les alarmes. Continuaràs sentint tot allò que decideixis reproduir, com ara música, vídeos i jocs."</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"Personalitza"</string>
- <string name="zen_silence_introduction_voice" msgid="853573681302712348">"Es bloquejaran TOTS els sons i totes les vibracions, inclosos els de vídeos, jocs, alarmes i música. Encara podràs fer trucades."</string>
+ <string name="zen_silence_introduction_voice" msgid="853573681302712348">"Es bloquejaran TOTS els sons i totes les vibracions, inclosos els de vídeos, jocs, alarmes i música. Encara podràs fer trucades telefòniques."</string>
<string name="zen_silence_introduction" msgid="6117517737057344014">"Es bloquejaran TOTS els sons i totes les vibracions, inclosos els de vídeos, jocs, alarmes i música."</string>
<string name="keyguard_more_overflow_text" msgid="5819512373606638727">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="7248696377626341060">"Notificacions menys urgents a continuació"</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"El perfil es pot supervisar"</string>
<string name="vpn_footer" msgid="3457155078010607471">"És possible que la xarxa estigui supervisada."</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"És possible que la xarxa estigui supervisada"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"El teu pare o la teva mare gestionen aquest dispositiu"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"La teva organització és propietària del dispositiu i és possible que supervisi el trànsit de xarxa"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> és propietària d\'aquest dispositiu i és possible que supervisi el trànsit de xarxa"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Aquest dispositiu pertany a la teva organització i està connectat a <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Desactiva la VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Desconnecta la VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Consulta les polítiques"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Mostra els controls"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"El dispositiu pertany a <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nL\'administrador de TI pot supervisar i gestionar la configuració, l\'accés corporatiu, les aplicacions, les dades associades al dispositiu i la informació d\'ubicació.\n\nPer obtenir més informació, contacta amb l\'administrador de TI."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"El dispositiu pertany a la teva organització.\n\nL\'administrador de TI pot supervisar i gestionar la configuració, l\'accés corporatiu, les aplicacions, les dades associades al dispositiu i la informació d\'ubicació.\n\nPer obtenir més informació, contacta amb l\'administrador de TI."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"La teva organització ha instal·lat una autoritat de certificació en aquest dispositiu. És possible que el trànsit a la xarxa segura se supervisi o es modifiqui."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"L\'administrador ha activat el registre de xarxa, que supervisa el trànsit del teu dispositiu.\n\nPer obtenir més informació, contacta amb l\'administrador."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Has donat permís a una aplicació per configurar una connexió VPN.\n\nAquesta aplicació pot supervisar el dispositiu i l\'activitat a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona el teu perfil de treball.\n\nL\'administrador pot supervisar la teva activitat a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web.\n\nPer obtenir més informació, contacta amb l\'administrador.\n\nA més, estàs connectat a una VPN, que també pot supervisar la teva activitat a la xarxa."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"El teu pare o la teva mare gestionen aquest dispositiu, i poden veure i gestionar informació com ara les aplicacions que utilitzes, la teva ubicació i el teu temps de connexió."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Estàs connectat a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pot supervisar la teva activitat a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Estàs connectat a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pot supervisar la teva activitat personal a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincula un dispositiu nou"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilació"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"El número de compilació s\'ha copiat al porta-retalls."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index f00c279..156b65d 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Dvě čárky baterie."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Tři čárky baterie."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Baterie je nabitá."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Žádná telefonní síť."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Jedna čárka signálu telefonní sítě."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Dvě čárky signálu telefonní sítě."</string>
@@ -526,6 +528,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profil může být monitorován"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Síť může být sledována"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Síť může být monitorována"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Toto zařízení spravuje rodič"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Toto zařízení vlastní vaše organizace, která může sledovat síťový provoz"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"Toto zařízení spravuje organizace <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>, která může sledovat síťový provoz"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Toto zařízení patří vaší organizaci a je připojené k síti <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -550,6 +553,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Deaktivovat VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Odpojit VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Zobrazit zásady"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Zobrazit ovládací prvky"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Toto zařízení patří organizaci <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nVáš administrátor IT může sledovat a spravovat nastavení, firemní přístup, aplikace, data přidružená k tomuto zařízení a jeho polohu.\n\nDalší informace vám poskytne váš administrátor IT."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Toto zařízení patří vaší organizaci\n\nVáš administrátor IT může sledovat a spravovat nastavení, firemní přístup, aplikace, data přidružená k tomuto zařízení a jeho polohu.\n\nDalší informace vám poskytne váš administrátor IT."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Organizace do tohoto zařízení nainstalovala certifikační autoritu. Zabezpečený síťový provoz může být sledován nebo upravován."</string>
@@ -573,6 +577,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Administrátor zapnul protokolování sítě, které monitoruje síťový provoz v zařízení.\n\nDalší informace vám poskytne administrátor."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Udělili jste aplikaci oprávnění k nastavení připojení VPN.\n\nTato aplikace může sledovat vaši aktivitu v zařízení a v síti, včetně e-mailů, aplikací a webů."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Váš pracovní profil spravuje organizace <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrátor může monitorovat vaši síťovou aktivitu, včetně e-mailů, aplikací a webů.\n\nDalší informace vám poskytne administrátor.\n\nJste také připojeni k síti VPN, která může sledovat vaši aktivitu v síti."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Toto zařízení spravuje rodič. Rodič může zobrazit údaje, jako jsou používané aplikace, tvá poloha a čas strávený na zařízení."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Jste připojeni k aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g>, která může sledovat vaši aktivitu v síti, včetně e-mailů, aplikací a webů."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Jste připojeni k aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g>, která může sledovat vaši osobní aktivitu v síti, včetně e-mailů, aplikací a webů."</string>
@@ -1101,4 +1106,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Spárovat nové zařízení"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Číslo sestavení"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Číslo sestavení bylo zkopírováno do schránky."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 9d365c3..d4761d5 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Batteri to bjælker."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Batteri tre bjælker."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batteri fuldt."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Ingen telefon."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefon en bjælke."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefon to bjælker."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profilen kan overvåges"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Netværket kan være overvåget"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Netværket kan være overvåget"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Denne enhed administreres af din forælder"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Din organisation ejer denne enhed og overvåger muligvis netværkstrafikken"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ejer denne enhed og overvåger muligvis netværkstrafikken"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Denne enhed tilhører din organisation og har forbindelse til <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Deaktiver VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Afbryd VPN-forbindelse"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Se politikker"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Se styringselementer"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Denne enhed tilhører <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nDin it-administrator kan overvåge og administrere indstillinger, virksomhedsadgang, apps, data, der er tilknyttet din enhed, og din enheds placeringsdata.\n\nKontakt din it-administrator for at få mere at vide."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Denne enhed tilhører din organisation.\n\nDin it-administrator kan overvåge og administrere indstillinger, virksomhedsadgang, apps, data, der er tilknyttet din enhed, og din enheds placeringsdata.\n\nKontakt din it-administrator for at få mere at vide."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Din organisation har installeret et nøglecenter på denne enhed. Din sikre netværkstrafik kan overvåges eller ændres."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Din administrator har aktiveret netværksregistrering, som overvåger trafik på din enhed.\n\nKontakt din administrator for at få flere oplysninger."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Du gav en app tilladelse til at konfigurere en VPN-forbindelse.\n\nDenne app kan overvåge din enhed og netværksaktivitet, bl.a. e-mails, apps og websites."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Din arbejdsprofil administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nDin administrator kan overvåge din netværksaktivitet, bl.a. e-mails, apps og websites.\n\nKontakt din administrator for at få flere oplysninger.\n\nDu har også forbindelse til et VPN, som kan overvåge din netværksaktivitet."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Denne enhed administreres af din forælder. Din forælder kan se og administrere oplysninger såsom de apps, du bruger, din placering og din skærmtid."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Du har forbindelse til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåge din netværksaktivitet, bl.a. mails, apps og websites."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Du har forbindelse til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåge din private netværksaktivitet, bl.a. e-mails, apps og websites."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Par ny enhed"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Buildnummeret blev kopieret til udklipsholderen."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 55e7d17..3aff4c8 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Akku - zwei Balken"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Akku - drei Balken"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Akku voll"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Kein Telefon"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefonsignal - ein Balken"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefonsignal - zwei Balken"</string>
@@ -520,6 +522,8 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profil wird eventuell überwacht."</string>
<string name="vpn_footer" msgid="3457155078010607471">"Das Netzwerk wird eventuell überwacht."</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Das Netzwerk wird eventuell überwacht"</string>
+ <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
+ <skip />
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Deine Organisation verwaltet dieses Gerät und kann den Netzwerkverkehr überwachen"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ist der Eigentümer dieses Geräts und kann den Netzwerkverkehr überwachen"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Dieses Gerät gehört deiner Organisation und ist mit <xliff:g id="VPN_APP">%1$s</xliff:g> verbunden"</string>
@@ -544,6 +548,8 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN deaktivieren"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN-Verbindung trennen"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Richtlinien ansehen"</string>
+ <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
+ <skip />
<string name="monitoring_description_named_management" msgid="505833016545056036">"Dieses Gerät gehört <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nDein IT-Administrator kann Einstellungen, Zugriffsrechte im Unternehmen, Apps, mit diesem Gerät verknüpfte Daten und die Standortdaten deines Geräts sehen und verwalten.\n\nWeitere Informationen erhältst du von deinem IT-Administrator."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Dieses Gerät gehört deiner Organisation.\n\nDein IT-Administrator kann Einstellungen, Zugriffsrechte im Unternehmen, Apps, mit diesem Gerät verknüpfte Daten und die Standortdaten deines Geräts sehen und verwalten.\n\nWeitere Informationen erhältst du von deinem IT-Administrator."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Deine Organisation hat ein Zertifikat einer Zertifizierungsstelle auf deinem Gerät installiert. Eventuell wird dein sicherer Netzwerkverkehr überwacht oder bearbeitet."</string>
@@ -567,6 +573,8 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Dein Administrator hat die Netzwerkprotokollierung aktiviert. Damit wird der Verkehr auf deinem Gerät erfasst.\n\nWeitere Informationen erhältst du von deinem Administrator."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Du hast einer App gestattet, eine VPN-Verbindung einzurichten.\n\nDiese App kann dein Gerät und deine Netzwerkaktivitäten überwachen, einschließlich E-Mails, Apps und Websites."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Dein Arbeitsprofil wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet.\n\nDein Administrator kann deine Netzwerkaktivitäten einschließlich E-Mails, Apps und Websites überwachen.\n\nWeitere Informationen erhältst du von deinem Administrator.\n\nAußerdem bist du mit einem VPN verbunden, das deine Netzwerkaktivitäten erfassen kann."</string>
+ <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
+ <skip />
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Du bist mit <xliff:g id="APPLICATION">%1$s</xliff:g> verbunden, die deine Netzwerkaktivitäten überwachen kann, einschließlich E-Mails, Apps und Websites."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Du bist mit der App <xliff:g id="APPLICATION">%1$s</xliff:g> verbunden, die deine persönliche Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites."</string>
@@ -1089,4 +1097,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Neues Gerät koppeln"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build-Nummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build-Nummer in Zwischenablage kopiert."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 3bb15ff..1a6998e 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Δύο γραμμές μπαταρίας."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Τρεις γραμμές μπαταρίας."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Πλήρης μπαταρία."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Δεν υπάρχει τηλέφωνο."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Μία γραμμή τηλεφώνου."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Δύο γραμμές τηλεφώνου."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Το προφίλ ενδέχεται να παρακολουθείται"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Το δίκτυο ενδέχεται να παρακολουθείται"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Το δίκτυο ενδέχεται να παρακολουθείται"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Αυτή η συσκευή είναι διαχειριζόμενη από τον γονέα σου"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Ο οργανισμός σας κατέχει αυτήν τη συσκευή και μπορεί να παρακολουθεί την επισκεψιμότητα δικτύου."</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"Ο οργανισμός <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> κατέχει αυτήν τη συσκευή και μπορεί να παρακολουθεί την επισκεψιμότητα δικτύου."</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Αυτή η συσκευή ανήκει στον οργανισμό σας και είναι συνδεδεμένη στην εφαρμογή <xliff:g id="VPN_APP">%1$s</xliff:g>."</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Απενεργοποίηση VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Αποσύνδεση VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Προβολή πολιτικών"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Προβολή στοιχείων ελέγχου"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Αυτή η συσκευή ανήκει στον οργανισμό <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nΟ διαχειριστής IT μπορεί να παρακολουθεί και να διαχειρίζεται τις ρυθμίσεις, την εταιρική πρόσβαση, τις εφαρμογές, τα δεδομένα που σχετίζονται με τη συσκευή καθώς και τις πληροφορίες τοποθεσίας της συσκευής σας.\n\nΓια περισσότερες πληροφορίες, επικοινωνήστε με τον διαχειριστή IT."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Αυτή η συσκευή ανήκει στον οργανισμό σας.\n\nΟ διαχειριστής IT μπορεί να παρακολουθεί και να διαχειρίζεται τις ρυθμίσεις, την εταιρική πρόσβαση, τις εφαρμογές, τα δεδομένα που σχετίζονται με τη συσκευή καθώς και τις πληροφορίες τοποθεσίας της συσκευής σας.\n\nΓια περισσότερες πληροφορίες, επικοινωνήστε με τον διαχειριστή IT."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Ο οργανισμός σας εγκατέστησε μια αρχή έκδοσης πιστοποιητικών σε αυτήν τη συσκευή. Η ασφαλής επισκεψιμότητα δικτύου σας μπορεί να παρακολουθείται ή να τροποποιείται."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Ο διαχειριστής σας έχει ενεργοποιήσει την καταγραφή δικτύου, η οποία παρακολουθεί την επισκεψιμότητα στη συσκευή σας.\n\nΓια περισσότερες πληροφορίες, επικοινωνήστε με τον διαχειριστή σας."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Παραχωρήσατε σε μια εφαρμογή άδεια για τη ρύθμιση σύνδεσης VPN.\n\nΑυτή η εφαρμογή μπορεί να παρακολουθεί τη δραστηριότητα της συσκευής και του δικτύου σας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστοτόπων."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Η διαχείριση του προφίλ εργασίας γίνεται από τον οργανισμό <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nΟ διαχειριστής έχει τη δυνατότητα παρακολούθησης της δραστηριότητας του δικτύου σας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστοτόπων.\n\nΓια περισσότερες πληροφορίες, επικοινωνήστε με τον διαχειριστή.\n\nΕπίσης, είστε συνδεδεμένοι σε VPN, το οποίο μπορεί να παρακολουθεί τη δραστηριότητα του δικτύου σας."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Αυτή η συσκευή είναι διαχειριζόμενη από τον γονέα σου. Ο γονέας σου μπορεί να βλέπει και να διαχειρίζεται πληροφορίες όπως οι εφαρμογές που χρησιμοποιείς, η τοποθεσία σου και ο χρόνος χρήσης."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Έχετε συνδεθεί στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του δικτύου σας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστοτόπων."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Έχετε συνδεθεί στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του προσωπικού σας δικτύου, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστοτόπων."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Σύζευξη νέας συσκευής"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Αριθμός έκδοσης"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Ο αριθμός έκδοσης αντιγράφηκε στο πρόχειρο."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index a743bbe..fe1d841 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -182,6 +182,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Battery two bars."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Battery three bars."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Battery full."</string>
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"No phone."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Phone one bar."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Phone two bars."</string>
@@ -520,6 +521,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profile may be monitored"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Network may be monitored"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Network may be monitored"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"This device is managed by your parent"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Your organisation owns this device and may monitor network traffic"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> owns this device and may monitor network traffic"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"This device belongs to your organisation and is connected to <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +546,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Disable VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Disconnect VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"View Policies"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"View controls"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nYour IT admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nFor more information, contact your IT admin."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"This device belongs to your organisation.\n\nYour IT admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nFor more information, contact your IT admin."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Your organisation installed a certificate authority on this device. Your secure network traffic may be monitored or modified."</string>
@@ -567,6 +570,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Your admin has turned on network logging, which monitors traffic on your device.\n\nFor more information, contact your admin."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"You gave an app permission to set up a VPN connection.\n\nThis app can monitor your device and network activity, including emails, apps and websites."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour admin is capable of monitoring your network activity including emails, apps and websites.\n\nFor more information, contact your admin.\n\nYou\'re also connected to a VPN, which can monitor your network activity."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"This device is managed by your parent. Your parent can see and manage information such as the apps that you use, your location and your screen time."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your network activity, including emails, apps and websites."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
@@ -1089,4 +1093,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem reading your battery meter"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tap for more information"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 3fe7a6a..a2307e7 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -182,6 +182,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Battery two bars."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Battery three bars."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Battery full."</string>
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"No phone."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Phone one bar."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Phone two bars."</string>
@@ -520,6 +521,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profile may be monitored"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Network may be monitored"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Network may be monitored"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"This device is managed by your parent"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Your organisation owns this device and may monitor network traffic"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> owns this device and may monitor network traffic"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"This device belongs to your organisation and is connected to <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +546,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Disable VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Disconnect VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"View Policies"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"View controls"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nYour IT admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nFor more information, contact your IT admin."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"This device belongs to your organisation.\n\nYour IT admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nFor more information, contact your IT admin."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Your organisation installed a certificate authority on this device. Your secure network traffic may be monitored or modified."</string>
@@ -567,6 +570,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Your admin has turned on network logging, which monitors traffic on your device.\n\nFor more information, contact your admin."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"You gave an app permission to set up a VPN connection.\n\nThis app can monitor your device and network activity, including emails, apps and websites."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour admin is capable of monitoring your network activity including emails, apps and websites.\n\nFor more information, contact your admin.\n\nYou\'re also connected to a VPN, which can monitor your network activity."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"This device is managed by your parent. Your parent can see and manage information such as the apps that you use, your location and your screen time."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your network activity, including emails, apps and websites."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
@@ -1089,4 +1093,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem reading your battery meter"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tap for more information"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index a743bbe..50288b2 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Battery two bars."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Battery three bars."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Battery full."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"No phone."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Phone one bar."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Phone two bars."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profile may be monitored"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Network may be monitored"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Network may be monitored"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"This device is managed by your parent"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Your organisation owns this device and may monitor network traffic"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> owns this device and may monitor network traffic"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"This device belongs to your organisation and is connected to <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Disable VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Disconnect VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"View Policies"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"View controls"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nYour IT admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nFor more information, contact your IT admin."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"This device belongs to your organisation.\n\nYour IT admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nFor more information, contact your IT admin."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Your organisation installed a certificate authority on this device. Your secure network traffic may be monitored or modified."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Your admin has turned on network logging, which monitors traffic on your device.\n\nFor more information, contact your admin."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"You gave an app permission to set up a VPN connection.\n\nThis app can monitor your device and network activity, including emails, apps and websites."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour admin is capable of monitoring your network activity including emails, apps and websites.\n\nFor more information, contact your admin.\n\nYou\'re also connected to a VPN, which can monitor your network activity."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"This device is managed by your parent. Your parent can see and manage information such as the apps that you use, your location and your screen time."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your network activity, including emails, apps and websites."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index a743bbe..50288b2 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Battery two bars."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Battery three bars."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Battery full."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"No phone."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Phone one bar."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Phone two bars."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profile may be monitored"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Network may be monitored"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Network may be monitored"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"This device is managed by your parent"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Your organisation owns this device and may monitor network traffic"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> owns this device and may monitor network traffic"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"This device belongs to your organisation and is connected to <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Disable VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Disconnect VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"View Policies"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"View controls"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nYour IT admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nFor more information, contact your IT admin."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"This device belongs to your organisation.\n\nYour IT admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nFor more information, contact your IT admin."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Your organisation installed a certificate authority on this device. Your secure network traffic may be monitored or modified."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Your admin has turned on network logging, which monitors traffic on your device.\n\nFor more information, contact your admin."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"You gave an app permission to set up a VPN connection.\n\nThis app can monitor your device and network activity, including emails, apps and websites."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour admin is capable of monitoring your network activity including emails, apps and websites.\n\nFor more information, contact your admin.\n\nYou\'re also connected to a VPN, which can monitor your network activity."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"This device is managed by your parent. Your parent can see and manage information such as the apps that you use, your location and your screen time."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your network activity, including emails, apps and websites."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 78006fd..fe7f4e0 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -182,6 +182,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Battery two bars."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Battery three bars."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Battery full."</string>
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"No phone."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Phone one bar."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Phone two bars."</string>
@@ -520,6 +521,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profile may be monitored"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Network may be monitored"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Network may be monitored"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"This device is managed by your parent"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Your organization owns this device and may monitor network traffic"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> owns this device and may monitor network traffic"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"This device belongs to your organization and is connected to <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +546,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Disable VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Disconnect VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"View Policies"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"View controls"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nYour IT admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nFor more information, contact your IT admin."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"This device belongs to your organization.\n\nYour IT admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nFor more information, contact your IT admin."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Your organization installed a certificate authority on this device. Your secure network traffic may be monitored or modified."</string>
@@ -567,6 +570,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Your admin has turned on network logging, which monitors traffic on your device.\n\nFor more information, contact your admin."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"You gave an app permission to set up a VPN connection.\n\nThis app can monitor your device and network activity, including emails, apps, and websites."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour admin is capable of monitoring your network activity including emails, apps, and websites.\n\nFor more information, contact your admin.\n\nYou\'re also connected to a VPN, which can monitor your network activity."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"This device is managed by your parent. Your parent can see and manage information such as the apps you use, your location, and your screen time."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your network activity, including emails, apps, and websites."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps, and websites."</string>
@@ -1089,4 +1093,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem reading your battery meter"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tap for more information"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index d30a395..d6c5e15 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Dos barras de batería"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Tres barras de batería"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batería completa"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Sin teléfono"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Una barra de teléfono"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Dos barras de teléfono"</string>
@@ -520,6 +522,8 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Es posible que se supervise el perfil."</string>
<string name="vpn_footer" msgid="3457155078010607471">"Es posible que la red esté supervisada."</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Es posible que la red esté supervisada"</string>
+ <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
+ <skip />
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Tu organización es propietaria de este dispositivo y podría controlar el tráfico de red"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> es la organización propietaria de este dispositivo y podría controlar el tráfico de red"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Este dispositivo pertenece a tu organización y está conectado a <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +548,8 @@
<string name="disable_vpn" msgid="482685974985502922">"Inhabilitar VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Desconectar VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Ver políticas"</string>
+ <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
+ <skip />
<string name="monitoring_description_named_management" msgid="505833016545056036">"Este dispositivo pertenece a <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nTu administrador de TI puede controlar y administrar la configuración, el acceso corporativo, las apps, los datos asociados al dispositivo y la información de ubicación.\n\nPara obtener más información, comunícate con el administrador de TI."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Este dispositivo pertenece a tu organización.\n\nTu administrador de TI puede controlar y administrar la configuración, el acceso corporativo, las apps, los datos asociados al dispositivo y la información de ubicación.\n\nPara obtener más información, comunícate con el administrador de TI."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Tu organización instaló una autoridad de certificación en este dispositivo. Es posible que se controle o modifique el tráfico de tu red segura."</string>
@@ -567,6 +573,8 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Tu administrador activó el registro de red, que controla el tráfico en tu dispositivo.\n\nComunícate con él para obtener más información."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Permitiste que una aplicación configurara una conexión VPN.\n\nEsta aplicación puede supervisar la actividad de la red y del dispositivo, incluidos los correos electrónicos, las aplicaciones y los sitios web."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> administra tu perfil de trabajo.\n\nTu administrador puede controlar tu actividad en la red, como los correos electrónicos, las apps y los sitios web.\n\nComunícate con él para obtener más información.\n\nTambién estás conectado a una VPN, que puede controlar tu actividad en la red."</string>
+ <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
+ <skip />
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede controlar la actividad de la red, incluidos los correos electrónicos, las apps y los sitios web."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Tienes conexión a la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede supervisar la actividad de la red personal, incluidos los correos electrónicos, las aplicaciones y los sitios web."</string>
@@ -1089,4 +1097,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincular dispositivo nuevo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Se copió el número de compilación en el portapapeles."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 875c310..9726134 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Dos barras de batería"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Tres barras de batería"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batería completa"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Sin teléfono"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Una barra de cobertura"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Dos barras de cobertura"</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Es posible que se supervise el perfil"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Puede que la red esté supervisada"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Puede que la red esté supervisada"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Este dispositivo lo gestionan tu padre o tu madre"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"El dispositivo pertenece a tu organización, que puede monitorizar su tráfico de red"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"El dispositivo pertenece a <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>, que puede monitorizar su tráfico de red"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Este dispositivo pertenece a tu organización y está conectado a <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Inhabilitar VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Desconectar VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Ver políticas"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Ver controles"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"El dispositivo pertenece a <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nEl administrador de TI puede monitorizar y gestionar los ajustes, el acceso corporativo, las aplicaciones, la información de ubicación del dispositivo y los datos asociados a él.\n\nPara obtener más información, ponte en contacto con el administrador de TI."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"El dispositivo pertenece a tu organización.\n\nEl administrador de TI puede monitorizar y gestionar los ajustes, el acceso corporativo, las aplicaciones, la información de ubicación del dispositivo y los datos asociados a él.\n\nPara obtener más información, ponte en contacto con el administrador de TI."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Tu organización ha instalado una entidad de certificación en este dispositivo. Es posible que se supervise o se modifique tu tráfico de red seguro."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Tu administrador ha activado el registro de la red para supervisar el tráfico en tu dispositivo.\n\nPonte en contacto con él para obtener más información."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Has concedido permiso a una aplicación para configurar una conexión VPN.\n\nEsta aplicación puede controlar tu dispositivo y tu actividad de red, como correos electrónicos, aplicaciones y sitios web."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"El administrador de tu perfil de trabajo es <xliff:g id="ORGANIZATION">%1$s</xliff:g>,\n\n que puede supervisar tu actividad de red, como correos electrónicos, aplicaciones y sitios web.\n\nPara obtener más información, ponte en contacto con tu administrador.\n\nTambién estás conectado a una red VPN, que puede supervisar tu actividad de red."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Tu padre o madre gestionan este dispositivo y pueden ver y controlar cierta información, como las aplicaciones que utilizas, tu ubicación y tu tiempo de pantalla."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Te has conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede supervisar tu actividad de red, como los correos electrónicos, las aplicaciones y los sitios web."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Estas conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede controlar tu actividad de red personal, como correos electrónicos, aplicaciones y sitios web."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincular nuevo dispositivo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número de compilación copiado en el portapapeles."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index f9940a3..d8ec8be 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Aku: kaks pulka."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Aku: kolm pulka."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Aku täis."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Telefonisignaal puudub"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefonisignaal: üks pulk."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefonisignaal: kaks pulka."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profiili võidakse jälgida"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Võrku võidakse jälgida"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Võrku võidakse jälgida"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Seda seadet haldab sinu vanem"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Teie organisatsioon on selle seadme omanik ja võib jälgida võrguliiklust"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> on selle seadme omanik ja võib jälgida võrguliiklust"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"See seade kuulub teie organisatsioonile ja on ühendatud rakendusega <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Keela VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Katkesta VPN-i ühendus"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Kuva eeskirjad"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Kuva järelevalve haldamine"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"See seade kuulub organisatsioonile <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nIT-administraator saab jälgida ning hallata seadeid, ettevõttesisest juurdepääsu, rakendusi, seadmega seotud andmeid ja seadme asukohateavet.\n\nLisateabe saamiseks võtke ühendust IT-administraatoriga."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"See seade kuulub teie organisatsioonile.\n\nIT-administraator saab jälgida ning hallata seadeid, ettevõttesisest juurdepääsu, rakendusi, seadmega seotud andmeid ja seadme asukohateavet.\n\nLisateabe saamiseks võtke ühendust IT-administraatoriga."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Teie organisatsioon installis sellesse seadmesse sertifikaadi volituse. Teie turvalist võrguliiklust võidakse jälgida ja muuta."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Teie administraator on sisse lülitanud võrgu logimise funktsiooni, mis jälgib teie seadmes liiklust.\n\nLisateabe saamiseks võtke ühendust administraatoriga."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Andsite rakendusele loa VPN-i ühenduse seadistamiseks.\n\nSee rakendus võib jälgida teie seadet ja võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Teie tööprofiili haldab <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministraator saab jälgida teie töökoha võrgutegevusi, sh meile, rakendusi ja veebisaite.\n\nLisateabe saamiseks võtke ühendust administraatoriga.\n\nTeil on ühendus ka VPN-iga, mis saab teie võrgutegevusi jälgida."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Seda seadet haldab sinu vanem. Sinu vanem näeb ja saab hallata teavet, näiteks kasutatavaid rakendusi, asukohta ja ekraaniaega."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Olete ühendatud rakendusega <xliff:g id="APPLICATION">%1$s</xliff:g>, mis võib jälgida teie võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Teie seade on ühendatud rakendusega <xliff:g id="APPLICATION">%1$s</xliff:g>, mis võib jälgida teie isiklikke võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uue seadme sidumine"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Järgunumber"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Järgunumber kopeeriti lõikelauale."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index cb86a16..8aa247f 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Bateriak bi barra ditu."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Bateriak hiru barra ditu."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Bateria beteta dago."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Ez dago telefono-zenbakirik."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefono-seinaleak barra bat du."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefono-seinaleak bi barra ditu."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Baliteke profila kontrolatuta egotea"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Baliteke sarea kontrolatuta egotea"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Baliteke sarea kontrolatuta egotea"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Zure gurasoak kudeatzen du gailua"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Gailu hau zure erakundearena da, eta baliteke hark sareko trafikoa gainbegiratzea"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"Gailu hau <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> erakundearena da, eta baliteke sareko trafikoa gainbegiratzea"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Gailu hau zure erakundearena da, eta <xliff:g id="VPN_APP">%1$s</xliff:g> sarera dago konektatuta"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Desgaitu VPN konexioa"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Deskonektatu VPN sarea"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Ikusi gidalerroak"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Ikusi kontrolatzeko aukerak"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Gailu hau <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> erakundearena da.\n\nIKT saileko administratzaileak gainbegiratu eta kudeatu egin ditzake ezarpenak, enpresa-sarbidea, aplikazioak, gailuarekin erlazionatutako datuak eta gailuaren kokapen-informazioa.\n\nInformazio gehiago lortzeko, jarri IKT saileko administratzailearekin harremanetan."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Gailu hau zure erakundearena da.\n\nIKT saileko administratzaileak gainbegiratu eta kudeatu egin ditzake ezarpenak, enpresa-sarbidea, aplikazioak, gailuarekin erlazionatutako datuak eta gailuaren kokapen-informazioa.\n\nInformazio gehiago lortzeko, jarri IKT saileko administratzailearekin harremanetan."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Erakundeak ziurtagiri-emaile bat instalatu du gailuan. Baliteke sareko trafiko segurua gainbegiratzea edo aldatzea."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Administratzaileak sare-erregistroak aktibatu ditu; horrela, zure gailuko trafikoa gainbegira dezake.\n\nInformazio gehiago lortzeko, jarri administratzailearekin harremanetan."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Aplikazio bati VPN konexio bat konfiguratzeko baimena eman diozu.\n\nAplikazio horrek gailuko eta sareko jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> erakundeak kudeatzen du zure laneko profila.\n\nAdministratzaileak sareko jarduerak kontrola diezazkizuke, besteak beste, posta elektronikoa, aplikazioak eta webguneak.\n\nInformazio gehiago lortzeko, jarri administratzailearekin harremanetan.\n\nHorrez gain, VPN batera zaude konektatuta, eta hark ere kontrola ditzake zure sareko jarduerak."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Zure gurasoak kudeatzen du gailua. Zure gurasoak gailuko informazioa ikus eta kudea dezake; besteak beste, zer aplikazio erabiltzen dituzun, zure kokapena zein den eta pantaila aurrean zenbat eta noiz egoten zaren."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN konexioa"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikaziora konektatuta zaude. Aplikazio horrek sarean egiten dituzun jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikaziora konektatuta zaude. Aplikazio horrek sarean egiten dituzun jarduera pertsonalak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parekatu beste gailu batekin"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Konpilazio-zenbakia"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Kopiatu da konpilazio-zenbakia arbelean."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index afa0759..d4f6252 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"دو نوار برای باتری."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"سه نوار برای باتری."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"باتری پر است."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"بدون تلفن."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"یک نوار برای تلفن."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"دو نوار برای تلفن."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"شاید نمایه کنترل شود"</string>
<string name="vpn_footer" msgid="3457155078010607471">"ممکن است شبکه کنترل شود"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"ممکن است شبکه کنترل شود"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"این دستگاه را ولیتان مدیریت میکند"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"مالک این دستگاه سازمان شما است و ممکن است ترافیک شبکه را پایش کند"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"مالک این دستگاه <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> است و ممکن است ترافیک شبکه را پایش کند"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"این دستگاه به سازمان شما تعلق دارد و به <xliff:g id="VPN_APP">%1$s</xliff:g> متصل است"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"غیرفعال کردن VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"قطع اتصال VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"مشاهده خطمشیها"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"مشاهده کنترلها"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"این دستگاه به <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> تعلق دارد.\n\nسرپرست فناوری اطلاعات میتواند تنظیمات، دسترسی شرکتی، برنامهها، دادههای مرتبط با دستگاه، و اطلاعات مکان دستگاهتان را کنترل و مدیریت کند.\n\nبرای اطلاعات بیشتر، با سرپرست فناوری و اطلاعات تماس بگیرید."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"این دستگاه به سازمان شما تعلق دارد.\n\nسرپرست فناوری اطلاعات میتواند تنظیمات، دسترسی شرکتی، برنامهها، و دادههای مرتبط با دستگاه و اطلاعات مکان دستگاهتان را کنترل و مدیریت کند.\n\nبرای اطلاعات بیشتر، با سرپرست فناوری و اطلاعات تماس بگیرید."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"سازمان شما مرجع گواهینامهای در این دستگاه نصب کرده است. ممکن است ترافیک امن شبکه شما پایش یا تغییر داده شود."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"سرپرست سیستم شما گزارشگیری شبکه را (که بر ترافیک دستگاهتان نظارت میکند) روشن کرده است.\n\nبرای اطلاعات بیشتر، با سرپرست خود تماس بگیرید."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"شما به برنامهای برای تنظیم اتصال VPN اجازه دادید.\n\n این برنامه میتواند دستگاه و فعالیت شبکهتان را کنترل کند، از جمله ایمیل، برنامه و وبسایتها."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"نمایه کاری شما توسط <xliff:g id="ORGANIZATION">%1$s</xliff:g> مدیریت میشود.\n\nسرپرست سیستم شما میتواند بر فعالیت شبکه شما (ازجمله ایمیلها، برنامهها و وبسایتها) نظارت داشته باشد.\n\nبرای اطلاعات بیشتر، با سرپرست خود تماس بگیرید.\n\nهمچنین به VPN متصل هستید که میتواند بر فعالیت شبکه شما نظارت داشته باشد."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"این دستگاه را ولیتان مدیریت میکند. ولیتان میتواند اطلاعاتی مثل برنامههایی که استفاده میکنید، مکانتان، و مدت تماشای صفحهتان را ببیند و مدیریت کند."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"شما به <xliff:g id="APPLICATION">%1$s</xliff:g> متصل هستید، که میتواند فعالیت شما در شبکه (ازجمله ایمیل، برنامه و وبسایتها) را پایش کند."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"شما به <xliff:g id="APPLICATION">%1$s</xliff:g> وصل شدهاید، که میتواند فعالیت شبکه شخصی شما از جمله ایمیل، برنامه و وبسایتها را کنترل کند."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"مرتبط کردن دستگاه جدید"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"شماره ساخت"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"شماره ساخت در بریدهدان کپی شد."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 11c7e19..0ed1509 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Akun virta - kaksi palkkia."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Akun virta - kolme palkkia."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Akku täynnä."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Ei puhelinverkkoyhteyttä."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Puhelinverkkosignaali - yksi palkki."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Puhelinverkkosignaali - kaksi palkkia."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profiilia saatetaan valvoa"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Verkkoa saatetaan valvoa"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Verkkoa saatetaan valvoa"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Vanhempasi ylläpitää tätä laitetta"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Organisaatiosi omistaa laitteen ja voi valvoa verkkoliikennettä"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> omistaa laitteen ja voi valvoa verkkoliikennettä"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Organisaatiosi omistaa laitteen, joka on yhdistetty tähän: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Poista VPN käytöstä"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Katkaise VPN-yhteys"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Näytä säännöt"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Katso asetukset"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> omistaa tämän laitteen.\n\nJärjestelmänvalvoja voi valvoa ja muuttaa asetuksia, yrityskäyttöä, sovelluksia sekä laitteeseen yhdistettyjä tietoja ja sen sijaintitietoja.\n\nSaat lisätietoja järjestelmänvalvojalta."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Organisaatiosi omistaa tämän laitteen.\n\nJärjestelmänvalvoja voi valvoa ja muuttaa asetuksia, yrityskäyttöä, sovelluksia sekä laitteeseen yhdistettyjä tietoja ja sen sijaintitietoja.\n\nSaat lisätietoja järjestelmänvalvojalta."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Organisaatiosi asensi laitteeseen varmenteen myöntäjän. Suojattua verkkoliikennettäsi voidaan valvoa tai muuttaa."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Järjestelmänvalvoja on ottanut käyttöön verkkolokitietojen tallentamisen. Sen avulla seurataan laitteellasi tapahtuvaa liikennettä.\n\nPyydä lisätietoja järjestelmänvalvojalta."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Olet myöntänyt sovellukselle oikeuden VPN-yhteyden muodostamiseen.\n\nSovellus voi valvoa laitettasi ja toimintaasi verkossa, esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Työprofiiliasi hallitsee <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJärjestelmänvalvoja voi valvoa sähköpostin, sovellusten ja verkkosivustojen käyttöä sekä muuta toimintaasi verkossa.\n\nPyydä lisätietoja järjestelmänvalvojalta.\n\nOlet myös yhteydessä VPN:ään, joka voi valvoa toimintaasi verkossa."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Vanhempasi ylläpitää tätä laitetta. Vanhempasi voi nähdä ja ylläpitää tietoja, esim. käyttämiäsi sovelluksia, sijaintiasi ja käyttöaikaasi."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Olet muodostanut yhteyden sovellukseen <xliff:g id="APPLICATION">%1$s</xliff:g>, joka voi valvoa toimintaasi verkossa, esimerkiksi sähköposteja, sovelluksia ja verkkosivustoja."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Olet muodostanut yhteyden sovellukseen <xliff:g id="APPLICATION">%1$s</xliff:g>, joka voi valvoa henkilökohtaista toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Muodosta uusi laitepari"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Koontiversion numero"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Koontiversion numero kopioitu leikepöydälle"</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index b8ea6ac..c7e827f 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Niveau de batterie : moyen"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Niveau de batterie : bon"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batterie pleine"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Aucun signal"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Signal : faible"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Signal : moyen"</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"le profil peut être contrôlé"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Le réseau peut être surveillé"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Le réseau peut être surveillé"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Cet appareil est géré par votre parent"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Votre organisation possède cet appareil et peut contrôler le trafic réseau"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> possède cet appareil et peut contrôler le trafic réseau"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Cet appareil appartient à votre organisation et est connecté à <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Désactiver le RPV"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Déconnecter le RPV"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Afficher les politiques"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Afficher les commandes"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Votre appareil appartient à <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nVotre administrateur informatique peut contrôler et gérer les paramètres, l\'accès aux données d\'entreprise, les applications, les données associées à l\'appareil et les renseignements sur sa position.\n\nPour obtenir plus d\'information, communiquez avec votre administrateur informatique."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Cet appareil appartient à votre organisation.\n\nVotre administrateur informatique peut contrôler et gérer les paramètres, l\'accès aux données d\'entreprise, les applications, les données associées à votre appareil et les renseignements sur sa position.\n\nPour obtenir plus d\'information, communiquez avec votre administrateur informatique."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Votre entreprise a installé une autorité de certification sur cet appareil. Votre trafic sur le réseau sécurisé peut être contrôlé ou modifié."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Votre administrateur a activé la journalisation réseau, qui surveille le trafic sur votre appareil.\n\nPour en savoir plus, communiquez avec lui."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Vous avez autorisé une application à configurer une connexion RPV.\n\nCette application peut contrôler l\'activité de votre appareil et votre activité sur le réseau, y compris les courriels, les applications et les sites Web."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVotre administrateur peut surveiller votre activité sur le réseau, y compris les courriels que vous échangez, les applications que vous utilisez et les sites Web que vous visitez.\n\nPour en savoir plus, communiquez avec votre administrateur.\n\nVous êtes aussi connecté à un RPV, qui peut surveiller votre activité sur le réseau."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Cet appareil est géré par ton parent. Ton parent peut voir et gérer de l\'information, comme les applications que tu utilises, ta position et ton temps d\'utilisation des écrans."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"RPV"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité sur le réseau, y compris les courriels, les applications et les sites Web."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris les courriels, les applications et les sites Web."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Associer un autre appareil"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numéro de version"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Le numéro de version a été copié dans le presse-papiers."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 289ce40..781a43ce 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Niveau de batterie : moyen"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Niveau de batterie : bon"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batterie pleine"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Aucun signal"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Signal : faible"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Signal : moyen"</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Le profil peut être contrôlé."</string>
<string name="vpn_footer" msgid="3457155078010607471">"Il est possible que le réseau soit surveillé."</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Il est possible que le réseau soit surveillé."</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Cet appareil est géré par tes parents"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Cet appareil appartient à votre organisation, qui peut contrôler votre trafic réseau"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"Cet appareil appartient à <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>, qui peut contrôler votre trafic réseau"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Cet appareil appartient à votre organisation et il est connecté à <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Désactiver le VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Déconnecter le VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Afficher les règles"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Afficher les commandes"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Cet appareil appartient à <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nVotre administrateur informatique peut contrôler et gérer les paramètres, l\'accès aux données d\'entreprise, les applications, les données associées à l\'appareil et les informations sur sa localisation.\n\nPour plus d\'informations, contactez votre administrateur informatique."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Cet appareil appartient à votre organisation.\n\nVotre administrateur informatique peut contrôler et gérer les paramètres, l\'accès aux données d\'entreprise, les applications, les données associées à l\'appareil et les informations sur sa localisation.\n\nPour plus d\'informations, contactez votre administrateur informatique."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Votre entreprise a installé une autorité de certification sur cet appareil. Votre trafic sur le réseau sécurisé peut être contrôlé ou modifié."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Votre administrateur a activé la journalisation réseau, qui surveille le trafic sur votre appareil.\n\nPour en savoir plus, contactez-le."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Vous avez autorisé une application à configurer une connexion VPN.\n\nCette application peut contrôler l\'activité de votre appareil et votre activité sur le réseau, y compris votre activité relative aux e-mails, aux applications et aux sites Web."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVotre administrateur peut contrôler votre activité sur le réseau, y compris au niveau des e-mails, des applications et des sites Web.\n\nPour en savoir plus, contactez-le.\n\nVous êtes également connecté à un VPN qui peut contrôler votre activité sur le réseau."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Cet appareil est géré par tes parents. Ils peuvent voir et gérer certaines informations, telles que les applications que tu utilises, ta position et ton temps d\'utilisation de l\'appareil."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité sur le réseau, y compris l\'activité relative aux e-mails, aux applications et aux sites Web."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris votre activité relative aux e-mails, aux applications et aux sites Web."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Associer un nouvel appareil"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numéro de build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numéro de build copié dans le presse-papiers."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index e3d3755..80fb402 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Dúas barras de batería"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Tres barras de batería"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batería cargada"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Sen teléfono"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Unha barra de cobertura"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Dúas barras de cobertura"</string>
@@ -520,6 +522,8 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"O perfil pódese supervisar"</string>
<string name="vpn_footer" msgid="3457155078010607471">"É posible que se supervise a rede"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"É posible que se supervise a rede"</string>
+ <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
+ <skip />
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"A túa organización é propietaria deste dispositivo e pode controlar o tráfico de rede"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> é a organización propietaria deste dispositivo e pode controlar o tráfico de rede"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Este dispositivo pertence á túa organización e está conectado a <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +548,8 @@
<string name="disable_vpn" msgid="482685974985502922">"Desactivar VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Desconectar VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Ver políticas"</string>
+ <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
+ <skip />
<string name="monitoring_description_named_management" msgid="505833016545056036">"Este dispositivo pertence a <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nO teu administrador de TI pode supervisar e xestionar a configuración, o acceso corporativo, as aplicacións, os datos asociados co teu dispositivo e a información de localización deste último.\n\nPara obter máis información, contacta co teu administrador de TI."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Este dispositivo pertence á túa organización.\n\nO teu administrador de TI pode supervisar e xestionar a configuración, o acceso corporativo, as aplicacións, os datos asociados co teu dispositivo e a información de localización deste último.\n\nPara obter máis información, contacta co teu administrador de TI."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"A túa organización instalou unha autoridade de certificación neste dispositivo. É posible que se controle ou se modifique o teu tráfico de rede segura."</string>
@@ -567,6 +573,8 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"O administrador activou o rexistro na rede, que controla o tráfico do teu dispositivo.\n\nPara obter máis información, contacta co administrador."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Outorgaches permiso a unha aplicación para configurar unha conexión VPN.\n\nEsta aplicación pode supervisar a túa actividade na rede, incluídos os correos electrónicos, as aplicacións e os sitios web."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> xestiona o teu perfil de traballo.\n\nO administrador pode controlar a túa actividade na rede, mesmo os correos electrónicos, as aplicacións e os sitios web.\n\nPara obter máis información, ponte en contacto co administrador.\n\nTamén estás conectado a unha VPN, que pode controlar a túa actividade na rede."</string>
+ <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
+ <skip />
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode controlar a túa actividade na rede, mesmo os correos electrónicos, as aplicacións e os sitios web."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode supervisar a túa actividade persoal na rede, incluídos os correos electrónicos, as aplicacións e os sitios web."</string>
@@ -1089,4 +1097,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincular dispositivo novo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Copiouse o número de compilación no portapapeis."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 02c72db..85a084d 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"બૅટરી બે બાર."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"બૅટરી ત્રણ બાર."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"બૅટરી પૂર્ણ."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"કોઈ ફોન નથી."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"ફોન એક બાર."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"ફોન બે બાર."</string>
@@ -331,10 +333,10 @@
<string name="notification_summary_message_format" msgid="5158219088501909966">"<xliff:g id="CONTACT_NAME">%1$s</xliff:g>: <xliff:g id="MESSAGE_CONTENT">%2$s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="6818779631806163080">"સૂચનાઓની સેટિંગ્સ"</string>
<string name="status_bar_notification_app_settings_title" msgid="5050006438806013903">"<xliff:g id="APP_NAME">%s</xliff:g> સેટિંગ"</string>
- <string name="accessibility_rotation_lock_off" msgid="3880436123632448930">"સ્ક્રીન આપમેળે ફરશે."</string>
+ <string name="accessibility_rotation_lock_off" msgid="3880436123632448930">"સ્ક્રીન ઑટોમૅટિક રીતે ફરશે."</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"સ્ક્રીન લેન્ડસ્કેપ ઓરિએન્ટેશનમાં લૉક કરેલ છે."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"સ્ક્રીન પોટ્રેટ ઓરિએન્ટેશનમાં લૉક કરેલ છે."</string>
- <string name="accessibility_rotation_lock_off_changed" msgid="5772498370935088261">"સ્ક્રીન હવે આપમેળે ફરશે."</string>
+ <string name="accessibility_rotation_lock_off_changed" msgid="5772498370935088261">"સ્ક્રીન હવે ઑટોમૅટિક રીતે ફરશે."</string>
<string name="accessibility_rotation_lock_on_landscape_changed" msgid="5785739044300729592">"સ્ક્રીન હવે લેન્ડસ્કેપ ઓરિએન્ટેશનમાં લૉક કરેલ છે."</string>
<string name="accessibility_rotation_lock_on_portrait_changed" msgid="5580170829728987989">"સ્ક્રીન હવે પોટ્રેટ ઓરિએન્ટેશનમાં લૉક કરેલ છે."</string>
<string name="dessert_case" msgid="9104973640704357717">"ડેઝર્ટ કેસ"</string>
@@ -520,6 +522,8 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"પ્રોફાઇલ મૉનિટર કરી શકાય છે"</string>
<string name="vpn_footer" msgid="3457155078010607471">"નેટવર્ક મૉનિટર કરી શકાય છે"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"નેટવર્ક મૉનિટર કરવામાં આવી શકે છે"</string>
+ <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
+ <skip />
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"તમારી સંસ્થા આ ડિવાઇસની માલિકી ધરાવે છે અને નેટવર્ક ટ્રાફિકનું નિરીક્ષણ કરી શકે છે"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"આ ડિવાઇસ <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>ની માલિકીનું છે અને નેટવર્ક ટ્રાફિકનું નિરીક્ષણ કરી શકે છે"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"આ ડિવાઇસ તમારી સંસ્થાની માલિકીનું છે અને <xliff:g id="VPN_APP">%1$s</xliff:g>થી કનેક્ટ કરેલું છે"</string>
@@ -544,6 +548,8 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN અક્ષમ કરો"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN ડિસ્કનેક્ટ કરો"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"નીતિઓ જુઓ"</string>
+ <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
+ <skip />
<string name="monitoring_description_named_management" msgid="505833016545056036">"આ ડિવાઇસ <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>ની માલિકીનું છે.\n\nતમારા IT વ્યવસ્થાપક સેટિંગ, કૉર્પોરેટ ઍક્સેસ, ઍપ, તમારા ડિવાઇસ સાથે સંકળાયેલો ડેટા અને તમારા ડિવાઇસની સ્થાન માહિતીનું નિરીક્ષણ તેમજ તેને મેનેજ કરી શકે છે.\n\nવધુ માહિતી માટે, તમારા IT વ્યવસ્થાપકનો સંપર્ક કરો."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"આ ડિવાઇસ તમારી સંસ્થાની માલિકીનું છે.\n\nતમારા IT વ્યવસ્થાપક સેટિંગ, કૉર્પોરેટ ઍક્સેસ, ઍપ, તમારા ડિવાઇસ સાથે સંકળાયેલો ડેટા અને તમારા ડિવાઇસની સ્થાન માહિતીનું નિરીક્ષણ તેમજ તેને મેનેજ કરી શકે છે.\n\nવધુ માહિતી માટે, તમારા IT વ્યવસ્થાપકનો સંપર્ક કરો."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"તમારી સંસ્થાએ આ ઉપકરણ પર પ્રમાણપત્ર સત્તાધિકારી ઇન્સ્ટૉલ કર્યું છે. તમારા સુરક્ષિત નેટવર્ક ટ્રાફિકનું નિયમન થઈ શકે છે અથવા તેમાં ફેરફાર કરવામાં આવી શકે છે."</string>
@@ -567,6 +573,8 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"તમારા વ્યવસ્થાપકે નેટવર્ક લૉગિંગ ચાલુ કર્યુ છે, જે તમારા ઉપકરણ પર ટ્રાફિકનું નિરીક્ષણ કરે છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"તમે VPN કનેક્શન સેટ કરવા માટે ઍપ્લિકેશન પરવાનગી આપી.\n\nઆ ઍપ્લિકેશન ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિત તમારા ઉપકરણ અને નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"તમારી કાર્ય પ્રોફાઇલનું સંચાલન <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા કરવામાં આવે છે.\n\n તમારા વ્યવસ્થાપક ઇમેઇલ, ઍપ્લિકેશનો, અને વેબસાઇટો સહિતની તમારી કાર્ય નેટવર્ક પ્રવૃત્તિનું નિરીક્ષણ કરવામાં સક્ષમ છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો.\n\nતમે VPN સાથે પણ કનેક્ટ કરેલ છે, જે તમારી નેટવર્ક પ્રવૃત્તિનું નિરીક્ષણ કરી શકે છે."</string>
+ <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
+ <skip />
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયા છો, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટો સહિતની તમારી નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
@@ -585,7 +593,7 @@
<string name="accessibility_volume_settings" msgid="1458961116951564784">"સાઉન્ડ સેટિંગ"</string>
<string name="accessibility_volume_expand" msgid="7653070939304433603">"વિસ્તૃત કરો"</string>
<string name="accessibility_volume_collapse" msgid="2746845391013829996">"સંકુચિત કરો"</string>
- <string name="volume_odi_captions_tip" msgid="8825655463280990941">"મીડિયામાં કૅપ્શન આપમેળે ઉમેરો"</string>
+ <string name="volume_odi_captions_tip" msgid="8825655463280990941">"મીડિયામાં કૅપ્શન ઑટોમૅટિક રીતે ઉમેરો"</string>
<string name="accessibility_volume_close_odi_captions_tip" msgid="8924753283621160480">"કૅપ્શન ટિપ બંધ કરો"</string>
<string name="volume_odi_captions_content_description" msgid="4172765742046013630">"કૅપ્શન ઓવરલે"</string>
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ચાલુ કરો"</string>
@@ -903,11 +911,11 @@
<string name="tuner_lock_screen" msgid="2267383813241144544">"લૉક સ્ક્રીન"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"ફોન વધુ પડતી ગરમીને લીધે બંધ થઇ ગયો છે"</string>
<string name="thermal_shutdown_message" msgid="6142269839066172984">"તમારો ફોન હવે સામાન્યપણે કાર્ય કરી રહ્યો છે.\nવધુ માહિતી માટે ટૅપ કરો"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"તમારો ફોન અત્યંત ગરમ હતો, તેથી તે ઠંડો થવા આપમેળે બંધ થઇ ગયો છે. તમારો ફોન હવે સામાન્યપણે કાર્ય કરી રહ્યો છે.\n\nતમારો ફોન અત્યંત ગરમ થઇ શકે છે, જો તમે:\n • એવી ઍપ્લિકેશન વાપરતા હો જે સંસાધન સઘન રીતે વાપરતી હોય (જેમ કે ગેમિંગ, વીડિઓ, અથવા નેવિગેટ કરતી ઍપ્લિકેશનો)\n • મોટી ફાઇલો અપલોડ અથવા ડાઉનલોડ કરતા હો\n • તમારા ફોનનો ઉપયોગ ઉચ્ચ તાપમાનમાં કરતા હો"</string>
+ <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"તમારો ફોન અત્યંત ગરમ હતો, તેથી તે ઠંડો થવા ઑટોમૅટિક રીતે બંધ થઈ ગયો છે. તમારો ફોન હવે સામાન્યપણે કાર્ય કરી રહ્યો છે.\n\nતમારો ફોન અત્યંત ગરમ થઈ શકે છે, જો તમે:\n • એવી ઍપ વાપરતા હો જે સંસાધન સઘન રીતે વાપરતી હોય (જેમ કે ગેમિંગ, વીડિયો, અથવા નેવિગેટ કરતી ઍપ)\n • મોટી ફાઇલો અપલોડ અથવા ડાઉનલોડ કરતા હો\n • તમારા ફોનનો ઉપયોગ ઉચ્ચ તાપમાનમાં કરતા હો"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"સારસંભાળના પગલાં જુઓ"</string>
<string name="high_temp_title" msgid="2218333576838496100">"ફોન ગરમ થઈ રહ્યો છે"</string>
<string name="high_temp_notif_message" msgid="1277346543068257549">"ફોન ઠંડો થાય ત્યાં સુધી અમુક સુવિધાઓ મર્યાદિત હોય છે.\nવધુ માહિતી માટે ટૅપ કરો"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"તમારો ફોન આપમેળે ઠંડો થવાનો પ્રયાસ કરશે. તમે હજી પણ તમારા ફોનનો ઉપયોગ કરી શકો છો, પરંતુ તે કદાચ થોડો ધીમો ચાલે.\n\nતમારો ફોન ઠંડો થઈ જવા પર, તે સામાન્ય રીતે ચાલશે."</string>
+ <string name="high_temp_dialog_message" msgid="3793606072661253968">"તમારો ફોન ઑટોમૅટિક રીતે ઠંડો થવાનો પ્રયાસ કરશે. તમે હજી પણ તમારા ફોનનો ઉપયોગ કરી શકો છો, પરંતુ તે કદાચ થોડો ધીમો ચાલે.\n\nતમારો ફોન ઠંડો થઈ જવા પર, તે સામાન્ય રીતે ચાલશે."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"સારસંભાળના પગલાં જુઓ"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"ચાર્જરને અનપ્લગ કરો"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"આ ડિવાઇસને ચાર્જ કરવામાં કોઈ સમસ્યા છે. પાવર અડૅપ્ટર અનપ્લગ કરો અને કાળજી લેજો કદાચ કેબલ થોડો ગરમ થયો હોઈ શકે છે."</string>
@@ -1089,4 +1097,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"નવા ડિવાઇસ સાથે જોડાણ કરો"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"બિલ્ડ નંબર"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"બિલ્ડ નંબર ક્લિપબૉર્ડ પર કૉપિ કર્યો."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 3f497e7..9eeba17 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"बैटरी दो बार."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"बैटरी तीन बार."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"बैटरी पूरी है."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"कोई फ़ोन नहीं."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"फ़ोन एक बार."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"फ़ोन दो बार."</string>
@@ -522,6 +524,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"प्रोफ़ाइल को मॉनीटर किया जा सकता है"</string>
<string name="vpn_footer" msgid="3457155078010607471">"नेटवर्क को मॉनीटर किया जा सकता है"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"नेटवर्क को मॉनिटर किया जा सकता है"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"इस डिवाइस का प्रबंधन आपके अभिभावक करते हैं"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"इस डिवाइस का मालिकाना हक आपके संगठन के पास है. आपका संगठन, नेटवर्क के ट्रैफ़िक की निगरानी कर सकता है"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"इस डिवाइस का मालिकाना हक <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> के पास है. आपका संगठन, नेटवर्क के ट्रैफ़िक की निगरानी कर सकता है"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"इस डिवाइस का मालिकाना हक आपके संगठन के पास है. इस डिवाइस को <xliff:g id="VPN_APP">%1$s</xliff:g> से कनेक्ट किया गया है"</string>
@@ -546,6 +549,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN अक्षम करें"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN डिस्कनेक्ट करें"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"नीतियां देखें"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"कंट्रोल देखें"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"इस डिवाइस का मालिकाना हक <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> के पास है.\n\nआपके संगठन का आईटी एडमिन कुछ चीज़ों की निगरानी और उन्हें प्रबंधित कर सकता है, जैसे कि सेटिंग, कॉर्पोरेट ऐक्सेस, ऐप्लिकेशन, आपके डिवाइस से जुड़ा डेटा, और आपके डिवाइस की जगह की जानकारी.\n\nज़्यादा जानकारी के लिए, अपने आईटी एडमिन से संपर्क करें."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"इस डिवाइस का मालिकाना हक आपके संगठन के पास है.\n\nआपके संगठन का आईटी एडमिन कुछ चीज़ों की निगरानी और उन्हें प्रबंधित कर सकता है, जैसे कि सेटिंग, कॉर्पोरेट ऐक्सेस, ऐप्लिकेशन, आपके डिवाइस से जुड़ा डेटा, और आपके डिवाइस की जगह की जानकारी.\n\nज़्यादा जानकारी के लिए, अपने आईटी एडमिन से संपर्क करें."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"आपके संगठन ने इस डिवाइस पर एक प्रमाणपत्र अनुमति इंस्टॉल की है. आपके सुरक्षित नेटवर्क पर ट्रेफ़िक की निगरानी या उसमें बदलाव किया जा सकता है."</string>
@@ -569,6 +573,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"आपके एडमिन ने नेटवर्क लॉग करना चालू कर दिया है, जो आपके डिवाइस पर ट्रैफ़िक की निगरानी करता है.\n\nज़्यादा जानकारी के लिए अपने एडमिन से संपर्क करें."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"आपने किसी ऐप को VPN कनेक्शन सेट करने की अनुमति दी है.\n\nयह ऐप ईमेल, ऐप्स और सुरक्षित वेबसाइटों सहित आपके डिवाइस और नेटवर्क की गतिविधि की निगरानी कर सकता है."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> आपकी वर्क प्रोफ़ाइल को प्रबंधित करता है.\n\n आपका एडमिन ईमेल, ऐप्लिकेशन और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकता है.\n\nऔर जानकारी के लिए अपने एडमिन से संपर्क करें.\n\nआप ऐसे VPN से भी कनेक्ट हैं, जो आपकी नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"इस डिवाइस का प्रबंधन आपके अभिभावक करते हैं. अभिभावक आपके डिवाइस से जुड़ी जानकारी देख सकते हैं और उस जानकारी को प्रबंधित कर सकते हैं. इनमें, आपके इस्तेमाल किए गए ऐप्लिकेशन की जानकारी, आपकी जगह की जानकारी, और डिवाइस के इस्तेमाल में बिताए गए समय जैसी जानकारी शामिल हैं."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"वीपीएन"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्ट हैं, जो ईमेल, ऐप्लिकेशन और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्ट हैं, जो ईमेल, ऐप्स और वेबसाइटों सहित आपकी व्यक्तिगत नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
@@ -1091,4 +1096,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नया डिवाइस जोड़ें"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नंबर को क्लिपबोर्ड पर कॉपी किया गया."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 9958a2c..86523ec 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Baterija dva stupca."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Baterija tri stupca."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Baterija je puna."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Nema telefona."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefonski signal jedan stupac."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefonski signal dva stupca."</string>
@@ -523,6 +525,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profil se možda nadzire"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Mreža se možda nadzire"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Mreža se možda nadzire"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Ovim uređajem upravlja vaš roditelj"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Vaša je organizacija vlasnik ovog uređaja i može nadzirati mrežni promet"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"Organizacija <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> vlasnik je ovog uređaja i može nadzirati mrežni promet"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Ovaj uređaj pripada vašoj organizaciji i povezan je s mrežom <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -547,6 +550,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Onemogući VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Prekini vezu s VPN-om"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Prikaži pravila"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Prikaz kontrola"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Ovaj uređaj pripada organizaciji <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nVaš IT administrator može nadzirati postavke, korporacijski pristup, aplikacije, podatke o uređaju i lokaciji uređaja te upravljati njima.\n\nZa više informacija obratite se IT administratoru."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Ovaj uređaj pripada vašoj organizaciji.\n\nVaš IT administrator može nadzirati postavke, korporacijski pristup, aplikacije, podatke o uređaju i lokaciji uređaja te upravljati njima.\n\nZa više informacija obratite se IT administratoru."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Vaša je organizacija instalirala izdavač certifikata na ovom uređaju. Vaš sigurni mrežni promet možda se nadzire ili modificira."</string>
@@ -570,6 +574,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Administrator je uključio mrežni zapisnik koji prati promet na vašem uređaju.\n\nViše informacija možete saznati od administratora."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Dali ste dopuštenje aplikaciji za postavljanje VPN veze.\n\nTa aplikacija može nadzirati vašu aktivnost na uređaju i mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Vašim radnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVaš administrator može nadzirati vašu mrežnu aktivnost, uključujući e-poštu, aplikacije i web-lokacije.\n\nViše informacija možete saznati od administratora.\n\nPovezani ste i s VPN-om koji može nadzirati vašu mrežnu aktivnost."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Ovim uređajem upravlja vaš roditelj. Vaš roditelj može vidjeti podatke, kao što su aplikacije koje koristite, lokacija i vrijeme upotrebe te upravljati njima."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Povezani ste s aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g> koja može nadzirati vašu aktivnost na mreži, uključujući e-poruke, aplikacije i web-lokacije."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Povezani ste s aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g> koja može nadzirati vašu osobnu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
@@ -1095,4 +1100,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Upari novi uređaj"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj međuverzije"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Broj međuverzije kopiran je u međuspremnik."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 0159ec6..32ca37d 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Akkumulátor két sáv."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Akkumulátor három sáv."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Akkumulátor feltöltve."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Nincs telefon."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefon egy sáv."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefon két sáv."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profilját felügyelhetik"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Lehet, hogy a hálózatot figyelik"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Lehet, hogy a hálózat felügyelt"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Az eszközt a szülőd felügyeli"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Az eszköz az Ön szervezetének tulajdonában van, és lehetséges, hogy a hálózati forgalmat is figyelik"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"Az eszköz a(z) <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> tulajdonában van, és lehetséges, hogy a hálózati forgalmat is figyelik"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Ez az eszköz az Ön szervezetének tulajdonában van, és össze van kapcsolva a(z) <xliff:g id="VPN_APP">%1$s</xliff:g> alkalmazással"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN letiltása"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN-kapcsolat bontása"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Házirendek megtekintése"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Vezérlők megtekintése"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Ez az eszköz a(z) <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> tulajdonában van.\n\nA rendszergazda figyelheti és kezelheti az eszköz beállításait, vállalati hozzáférését, alkalmazásait, adatait és helyadatait.\n\nHa további információra van szüksége, vegye fel a kapcsolatot a rendszergazdával."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Ez az eszköz az Ön szervezetének tulajdonában van.\n\nA rendszergazda figyelheti és kezelheti az eszköz beállításait, vállalati hozzáférését, alkalmazásait, adatait és helyadatait.\n\nHa további információra van szüksége, vegye fel a kapcsolatot a rendszergazdával."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Szervezete tanúsítványkibocsátót telepített az eszközre. Ezáltal figyelhetik és befolyásolhatják az Ön biztonságos hálózati forgalmát."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"A rendszergazda bekapcsolta az eszköz forgalmát figyelő hálózati naplózást.\n\nHa további információra van szüksége, forduljon a rendszergazdához."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Engedélyezte egy alkalmazásnak, hogy VPN-kapcsolatot létesítsen.\n\nEz az alkalmazás (az e-mailekre, alkalmazásokra és a webhelyekre is kiterjedően) figyelemmel kísérheti az Ön eszközét és hálózati tevékenységét."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Munkaprofilját a(z) <xliff:g id="ORGANIZATION">%1$s</xliff:g> kezeli.\n\nA rendszergazda figyelheti hálózati tevékenységét, köztük az e-maileket, az alkalmazásokat és a webhelyeket.\n\nHa további információra van szüksége, forduljon a rendszergazdához.\n\nVPN-hez is kapcsolódik, amely szintén figyelheti hálózati tevékenységét."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Az eszközt a szülőd felügyeli. A szülőd megtekintheti és kezelheti például a használt alkalmazásokra, a tartózkodási helyre és a képernyőidőre vonatkozó adatokat."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Ön csatlakozik a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazáshoz, amely figyelheti hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Csatlakoztatta a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazást, amely figyelheti személyes hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Új eszköz párosítása"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildszám"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Buildszám a vágólapra másolva."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 1d80192..15fbf70 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Մարտկոցի երկու գիծ:"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Մարտկոցի երեք գիծ:"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Մարտկոցը լիքն է:"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Հեռախոս չկա:"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Հեռախոսի մեկ գիծ:"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Հեռախոսի երկու գիծ:"</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Պրոֆիլը կարող է վերահսկվել"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Ցանցը կարող է վերահսկվել"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Ցանցը կարող է վերահսկվել"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Այս սարքը կառավարում է ձեր ծնողը"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Ձեր կազմակերպությունը այս սարքի սեփականատերն է և կարող է վերահսկել ցանցային թրաֆիկը"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"«<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>» կազմակերպությունը այս սարքի սեփականատերն է և կարող է վերահսկել ցանցային թրաֆիկը"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Այս սարքը պատկանում է ձեր կազմակերպությանը և միացված է <xliff:g id="VPN_APP">%1$s</xliff:g> ցանցին"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Անջատել VPN-ը"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Անջատել VPN-ը"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Դիտել քաղաքականությունները"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Դիտել կառավարման տարրերը"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Այս սարքը պատկանում է «<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>» կազմակերպությանը։\n\nՁեր ՏՏ ադմինիստրատորը կարող է վերահսկել և կառավարել կարգավորումները, կորպորատիվ ռեսուրսներից օգտվելու թույլտվությունները, հավելվածները, սարքի հետ կապված տվյալները և սարքի տեղադրության տվյալները։\n\nԼրացուցիչ տեղեկությունների համար դիմեք ձեր ՏՏ ադմինիստրատորին։"</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Այս սարքը պատկանում է ձեր կազմակերպությանը։\n\nՁեր ՏՏ ադմինիստրատորը կարող է վերահսկել և կառավարել կարգավորումները, կորպորատիվ ռեսուրսներից օգտվելու թույլտվությունները, հավելվածները, սարքի հետ կապված տվյալները և սարքի տեղադրության տվյալները։\n\nԼրացուցիչ տեղեկությունների համար դիմեք ձեր ՏՏ ադմինիստրատորին։"</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Ձեր կազմակերպությունը այս սարքում տեղադրել է վկայագրման կենտրոն։ Ձեր ցանցի ապահով թրաֆիկը կարող է վերահսկվել կամ փոփոխվել։"</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Ձեր ադմինիստրատորը միացրել է ցանցային իրադարձությունների գրանցումը, որը վերահսկում է ձեր սարքի թրաֆիկը։\n\nԼրացուցիչ տեղեկություններ ստանալու համար դիմեք ձեր ադմինիստրատորին։"</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Ինչ-որ հավելվածի թույլ եք տվել հաստատել VPN կապակցում:\n\nԱյդ հավելվածը կարող է վերահսկել ձեր սարքի և ցանցի գործունեությունը, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Ձեր աշխատանքային պրոֆիլի կառավարիչն է <xliff:g id="ORGANIZATION">%1$s</xliff:g> կազմակերպությունը։\n\nԱդմինիստրատորը կարող է վերահսկել ձեր ցանցային գործունեությունը, այդ թվում նաև էլփոստը, հավելվածները և կայքերը։\n\nԼրացուցիչ տեղեկությունների համար դիմեք ադմինիստրատորին։\n\nԴուք կապակցված են նաև VPN ցանցին, որը կարող է վերահսկել ձեր ցանցային գործունեությունը։"</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Այս սարքը կառավարում է ձեր ծնողը։ Նա կարող է տեսնել և կառավարել որոշակի տեղեկություններ, օրինակ՝ հավելվածները, որոնք դուք օգտագործում եք, ձեր տեղադրությունը և սարքի օգտագործման ժամանակը։"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Դուք կապակցված եք <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին, որը կարող է վերահսկել ձեր ցանցային գործունեությունը, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:"</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Դուք կապակցված եք <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին, որը կարող է վերահսկել անձնական ցանցում կատարած ձեր գործողությունները, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:"</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Նոր սարքի զուգակցում"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Կառուցման համարը"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Կառուցման համարը պատճենվեց սեղմատախտակին։"</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 9aaf270..cf6a20d 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Baterai dua batang."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Baterai tiga batang."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Baterai penuh."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Tidak dapat melakukan panggilan."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Ponsel satu batang."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Ponsel dua batang."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profil dapat dipantau"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Jaringan mungkin dipantau"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Jaringan mungkin dipantau"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Perangkat ini dikelola oleh orang tua"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Organisasi Anda memiliki perangkat ini dan mungkin memantau traffic jaringan"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> memiliki perangkat ini dan mungkin memantau traffic jaringan"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Perangkat ini milik organisasi Anda dan terhubung ke <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Nonaktifkan VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Putuskan sambungan VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Lihat Kebijakan"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Lihat kontrol"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Perangkat ini milik <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nAdmin IT Anda dapat memantau dan mengelola setelan, akses perusahaan, aplikasi, data yang terkait dengan perangkat, dan informasi lokasi perangkat.\n\nUntuk informasi selengkapnya, hubungi admin IT Anda."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Perangkat ini milik organisasi Anda.\n\nAdmin IT Anda dapat memantau dan mengelola setelan, akses perusahaan, aplikasi, data yang terkait dengan perangkat, dan informasi lokasi perangkat.\n\nUntuk informasi selengkapnya, hubungi admin IT Anda."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Organisasi Anda menginstal otoritas sertifikat di perangkat ini. Traffic jaringan aman Anda mungkin dipantau atau diubah."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Admin telah mengaktifkan pencatatan log jaringan, yang memantau traffic di perangkat.\n\nUntuk informasi selengkapnya, hubungi admin."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Anda memberikan izin kepada aplikasi untuk menyiapkan sambungan VPN.\n\nAplikasi ini ini dapat memantau aktivitas perangkat dan jaringan, termasuk email, aplikasi, dan situs web."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Profil kerja dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdmin dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web.\n\nUntuk informasi selengkapnya, hubungi admin.\n\nAnda juga tersambung ke VPN, yang dapat memantau aktivitas jaringan."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Perangkat ini dikelola oleh orang tua. Orang tua Anda dapat melihat dan mengelola informasi, seperti aplikasi yang digunakan, lokasi, dan waktu pemakaian perangkat."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi, termasuk email, aplikasi, dan situs web."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sambungkan perangkat baru"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nomor versi"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nomor versi disalin ke papan klip."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index bf49e97..ca40b6f 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Tvö strik á rafhlöðu."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Þrjú strik á rafhlöðu."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Rafhlaða fullhlaðin."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Ekkert símasamband."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Styrkur símasambands er eitt strik."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Styrkur símasambands er tvö strik."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Hugsanlega er fylgst með þessu sniði"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Hugsanlega er fylgst með netinu"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Hugsanlega er fylgst með netinu"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Foreldri þitt stjórnar þessu tæki"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Fyrirtækið þitt á þetta tæki og fylgist hugsanlega með netumferð"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> á þetta tæki og fylgist hugsanlega með netumferð"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Þetta tæki tilheyrir fyrirtækinu þínu og er tengt við <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Slökkva á VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Aftengja VPN-net"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Skoða stefnur"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Skoða stýringar"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Þetta tæki tilheyrir <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nKerfisstjórinn getur fylgst með og breytt stillingum, fyrirtækjaaðgangi, forritum, gögnum sem tengjast tækinu þínu og staðsetningarupplýsingum tækisins.\n\nHafðu samband við kerfisstjórann til að fá frekari upplýsingar."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Þetta tæki tilheyrir fyrirtækinu þínu.\n\nKerfisstjórinn getur fylgst með og breytt stillingum, fyrirtækjaaðgangi, forritum, gögnum sem tengjast tækinu þínu og staðsetningarupplýsingum tækisins.\n\nHafðu samband við kerfisstjórann til að fá frekari upplýsingar."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Fyrirtækið þitt setti upp CA-vottorð á þessu tæki. Eftirlit kann að vera haft með öruggri netnotkun þinni eða henni kann að vera breytt."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Kerfisstjóri hefur kveikt á eftirliti netkerfa, sem fylgist með netumferð á tækinu þínu.\n\nHafðu samband við kerfisstjóra til að fá frekari upplýsingar."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Þú veittir forriti heimild til að koma á VPN-tengingu.\n\nÞetta forrit getur fylgst með virkni þinni í tækinu og á netinu, þar á meðal tölvupósti, forritum og vefsvæðum."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> stýrir vinnusniðinu þínu.\n\nKerfisstjórinn getur fylgst með virkni þinni á netinu, þ.m.t. tölvupósti, forritum og vefsvæðum.\n\nHafðu samband við kerfisstjórann til að fá frekari upplýsingar.\n\nÞú ert einnig með VPN-tengingu, sem getur fylgst með virkni þinni á netinu."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Foreldri þitt stjórnar þessu tæki. Foreldri þitt getur séð og stjórnað upplýsingum eins og forritunum sem þú notar, staðsetningu þinni og skjátímanum."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Þú ert með tengingu við <xliff:g id="APPLICATION">%1$s</xliff:g>, sem getur fylgst með netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Þú ert með tengingu við <xliff:g id="APPLICATION">%1$s</xliff:g>, sem getur fylgst með persónulegri netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Para nýtt tæki"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Útgáfunúmer smíðar"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Útgáfunúmer smíðar afritað á klippiborð."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 8e665ec..f3436e9 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Batteria: due barre."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Batteria: tre barre."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batteria carica."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Nessun telefono."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefono: una barra."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefono: due barre."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Il profilo potrebbe essere monitorato"</string>
<string name="vpn_footer" msgid="3457155078010607471">"La rete potrebbe essere monitorata"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"La rete potrebbe essere monitorata"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Questo dispositivo è gestito da uno dei tuoi genitori"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Questo dispositivo appartiene alla tua organizzazione, che potrebbe monitorare il traffico di rete"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"Questo dispositivo appartiene a <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>, che potrebbe monitorare il traffico di rete"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Questo dispositivo appartiene alla tua organizzazione ed è collegato a <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Disattiva VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Scollega VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Visualizza le norme"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Visualizza controlli"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Questo dispositivo appartiene a <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nIl tuo amministratore IT può monitorare e gestire impostazioni, accesso aziendale, app, dati associati al dispositivo e informazioni sulla posizione del dispositivo.\n\nPer ulteriori informazioni, contatta il tuo amministratore IT."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Questo dispositivo appartiene alla tua organizzazione.\n\nIl tuo amministratore IT può monitorare e gestire impostazioni, accesso aziendale, app, dati associati al dispositivo e informazioni sulla posizione del dispositivo.\n\nPer ulteriori informazioni, contatta il tuo amministratore IT."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"La tua organizzazione ha installato un\'autorità di certificazione sul dispositivo. Il tuo traffico di rete protetto potrebbe essere monitorato o modificato."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"L\'amministratore ha attivato i log di rete, che consentono di monitorare il traffico sul dispositivo.\n\nPer ulteriori informazioni, contatta l\'amministratore."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Hai autorizzato l\'app a configurare una connessione VPN.\n\nQuesta app può monitorare il tuo dispositivo e l\'attività di rete, inclusi email, app e siti web."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Il tuo profilo di lavoro è gestito da <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nL\'amministratore può monitorare la tua attività di rete, inclusi siti web, email e app.\n\nPer ulteriori informazioni, contatta l\'amministratore.\n\nSei inoltre connesso a una VPN, da cui è possibile monitorare la tua attività di rete."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Questo dispositivo è gestito da uno dei tuoi genitori. Il genitore può visualizzare e gestire informazioni quali le app che usi, la tua posizione e il tuo tempo di utilizzo."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Sei collegato a <xliff:g id="APPLICATION">%1$s</xliff:g>, da cui è possibile monitorare la tua attività di rete, inclusi siti web, email e app."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Sei connesso a <xliff:g id="APPLICATION">%1$s</xliff:g>, da cui è possibile monitorare la tua attività di rete personale, inclusi email, app e siti web."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Accoppia nuovo dispositivo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numero build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numero build copiato negli appunti."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 052b721..fc915a1 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"שני פסים של סוללה."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"שלושה פסים של סוללה."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"סוללה מלאה."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"אין טלפון."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"פס אחד של טלפון."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"שני פסים של טלפון."</string>
@@ -526,6 +528,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"ייתכן שהפרופיל נתון למעקב"</string>
<string name="vpn_footer" msgid="3457155078010607471">"ייתכן שהרשת נמצאת במעקב"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"ייתכן שהרשת מנוטרת"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"מכשיר זה מנוהל על ידי ההורה שלך"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"הארגון שלך הוא הבעלים של מכשיר זה והוא עשוי לנטר את התנועה ברשת"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"הארגון <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> הוא הבעלים של מכשיר זה והוא עשוי לנטר את התנועה ברשת"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"המכשיר הזה שייך לארגון שלך, והוא מחובר ל-<xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -550,6 +553,7 @@
<string name="disable_vpn" msgid="482685974985502922">"השבת VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"נתק את ה-VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"הצג מדיניות"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"לצפייה באמצעי בקרת ההורים"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"המכשיר הזה שייך לארגון <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nמנהל ה-IT יכול לנטר ולנהל הגדרות, גישה ארגונית, אפליקציות, נתונים המשויכים למכשיר ומידע על מיקום המכשיר.\n\nלמידע נוסף, יש לפנות למנהל ה-IT."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"המכשיר הזה שייך לארגון שלך.\n\nמנהל ה-IT יכול לנטר ולנהל הגדרות, גישה ארגונית, אפליקציות, נתונים המשויכים למכשיר ומידע על מיקום המכשיר.\n\nלמידע נוסף, יש לפנות למנהל ה-IT."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"הארגון שלך התקין רשות אישורים במכשיר. ניתן לעקוב אחר התנועה ברשת המאובטחת או לשנות אותה."</string>
@@ -573,6 +577,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"מנהל המערכת הפעיל את תכונת רישום התנועה ברשת, שמנטרת את תנועת הנתונים במכשיר.\n\nלמידע נוסף, צור קשר עם מנהל המערכת."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"נתת לאפליקציה כלשהי הרשאה להגדיר חיבור VPN.\n\nהאפליקציה הזו יכולה לעקוב אחר הפעילות שלך ברשת ובמכשיר, כולל הודעות אימייל, אפליקציות ואתרים."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"פרופיל העבודה שלך מנוהל על-ידי <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\n מנהל המערכת שלך יכול לעקוב אחרי הפעילות שלך ברשת, כולל פעילות באימייל, באפליקציות ובאתרים.\n\n למידע נוסף, צור קשר עם מנהל המערכת.\n\nבנוסף, אתה מחובר ל-VPN, שגם באמצעותו ניתן לעקוב אחרי הפעילות שלך ברשת."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"מכשיר זה מנוהל על ידי ההורה שלך. להורה שלך יש אפשרות לצפות בפרטים כמו האפליקציות שבשימוש, המיקום וזמן המסך שלך, ולנהל אותם."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"אתה מחובר לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת, כולל הודעות אימייל, אפליקציות ואתרים."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"אתה מחובר לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת הפרטית, כולל הודעות אימייל, אפליקציות ואתרים."</string>
@@ -1101,4 +1106,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"התאמה של מכשיר חדש"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"מספר Build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"מספר ה-Build הועתק ללוח."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 7e64155f..74fd16a 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"電池残量:レベル2"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"電池残量:レベル3"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"電池残量:満"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"電波状態:なし"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"電波状態:レベル1"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"電波状態:レベル2"</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"プロファイルが監視されている可能性があります"</string>
<string name="vpn_footer" msgid="3457155078010607471">"ネットワークが監視されている可能性があります"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"ネットワークが監視されている可能性があります"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"このデバイスは保護者によって管理されています"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"これは組織が所有するデバイスで、ネットワーク トラフィックが監視されることもあります"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"これは <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> が所有するデバイスで、ネットワーク トラフィックが監視されることもあります"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"これは組織が所有するデバイスで、<xliff:g id="VPN_APP">%1$s</xliff:g> に接続しています"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPNを無効にする"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPNを切断"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"ポリシーを見る"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"使用制限を表示"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"これは <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> が所有するデバイスです。\n\nIT 管理者が、このデバイスに関連付けられている設定、コーポレート アクセス、アプリ、データのほか、デバイスの位置情報を監視、管理できます。\n\n詳しくは、IT 管理者にお問い合わせください。"</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"これは組織が所有するデバイスです。\n\nIT 管理者が、このデバイスに関連付けられている設定、コーポレート アクセス、アプリ、データのほか、デバイスの位置情報を監視、管理できます。\n\n詳しくは、IT 管理者にお問い合わせください。"</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"組織によってこのデバイスに認証局がインストールされました。保護されたネットワーク トラフィックが監視、変更される場合があります。"</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"管理者がネットワーク ログを有効にしているため、このデバイスのトラフィックは監視されています。\n\n詳しくは管理者にお問い合わせください。"</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"アプリにVPN接続の設定を許可しました。\n\nこのアプリはあなたのデバイスやネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"この仕事用プロファイルは、<xliff:g id="ORGANIZATION">%1$s</xliff:g> により管理されています。\n\n管理者は、このプロファイルでのネットワーク アクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。\n\n詳しくは管理者にお問い合わせください。\n\nまた、VPN に接続しているため、このネットワークでのあなたのネットワーク アクティビティも監視されます。"</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"このデバイスは保護者によって管理されています。使用しているアプリ、現在地、利用時間などの情報を保護者が確認、管理できます。"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"<xliff:g id="APPLICATION">%1$s</xliff:g> に接続しています。このアプリはあなたのネットワーク アクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"<xliff:g id="APPLICATION">%1$s</xliff:g>に接続しています。このアプリはあなたの個人のネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"新しいデバイスとのペア設定"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ビルド番号"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ビルド番号をクリップボードにコピーしました。"</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 97aea29..b32937e 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"ბატარეა ორ ზოლზე."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"ბატარეა სამ ზოლზე."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"ბატარეა სავსეა."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"ტელეფონი არ არის."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"ტელეფონის სიგნალი ერთ ზოლზეა."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"ტელეფონის სიგნალი ორ ზოლზეა."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"შესაძლოა პროფილზე ხორციელდებოდეს მონიტორინგი"</string>
<string name="vpn_footer" msgid="3457155078010607471">"შესაძლოა ქსელზე ხორციელდება მონიტორინგი"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"ქსელზე შესაძლოა მონიტორინგი ხორციელდებოდეს"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ამ მოწყობილობას თქვენი მშობელი მართავს"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"ამ მოწყობილობას ფლობს თქვენი ორგანიზაცია და მას ქსელის ტრაფიკის მონიტორინგი შეუძლია"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"ამ მოწყობილობას ფლობს <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> და მას ქსელის ტრაფიკის მონიტორინგი შეუძლია"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"ამ მოწყობილობას ფლობს თქვენი ორგანიზაცია და ის დაკავშირებულია <xliff:g id="VPN_APP">%1$s</xliff:g>-თან"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN-ის გაუქმება"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN-ის გათიშვა"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"წესების ნახვა"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"მართვის საშუალებების ნახვა"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"ეს მოწყობილობას ფლობს <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nთქვენს IT ადმინისტრატორს შეუძლია მოწყობილობასთან დაკავშირებული პარამეტრების, კორპორაციული წვდომის, აპებისა და მონაცემების (მათ შორის, თქვენი მოწყობილობის მდებარეობის ინფორმაციის) მონიტორინგი და მართვა.\n\nდამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს IT ადმინისტრატორს."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"ამ მოწყობილობას ფლობს თქვენი ორგანიზაცია.\n\nთქვენს IT ადმინისტრატორს შეუძლია მოწყობილობასთან დაკავშირებული პარამეტრების, კორპორაციული წვდომის, აპებისა და მონაცემების (მათ შორის, თქვენი მოწყობილობის მდებარეობის ინფორმაციის) მონიტორინგი და მართვა.\n\nდამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს IT ადმინისტრატორს."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"თქვენმა ორგანიზაციამ ამ მოწყობილობაზე სერტიფიცირების ორგანო დააინსტალირა. თქვენი ქსელის დაცული ტრაფიკი შეიძლება შეიცვალოს, ან მასზე მონიტორინგი განხორციელდეს."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"თქვენმა ადმინისტრატორმა ქსელის ჟურნალირება ჩართო, რომელიც თქვენი მოწყობილობის ტრაფიკის მონიტორინგს ახორციელებს.\n\nდამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"თქვენ მიეცით ნებართვა აპს, დააყენოს VPN კავშირი.\n\nამ აპს შეუძლია თქვენი მოწყობილობის და ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"თქვენს სამსახურის პროფილს მართავს <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nთქვენს ადმინისტრატორს შეუძლია თქვენი ქსელის აქტივობის (მათ შორის, ელფოსტის, აპებისა და ვებსაიტების) მონიტორინგი.\n\nდამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს.\n\nგარდა ამისა, თქვენ დაკავშირებული ხართ VPN-თან, რომელსაც ასევე შეუძლია თქვენი ქსელის აქტივობის მონიტორინგი."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ამ მოწყობილობას თქვენი მშობელი მართავს. თქვენი მშობელი ხედავს და მართავს ისეთ ინფორმაციას, როგორიც არის თქვენ მიერ გამოყენებული აპები, თქვენი მდებარეობა და თქვენ მიერ ეკრანთან გატარებული დრო."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"თქვენ დაკავშირებული ხართ <xliff:g id="APPLICATION">%1$s</xliff:g>-თან, რომელსაც შეუძლია თქვენი ქსელის აქტივობის (მათ შორის, ელფოსტის, აპებისა და ვებსაიტების) მონიტორინგი."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"თქვენ დაუკავშირდით <xliff:g id="APPLICATION">%1$s</xliff:g>-ს, რომელსაც შეუძლია თქვენი პირადი ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ახალი მოწყობილობის დაწყვილება"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ანაწყობის ნომერი"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ანაწყობის ნომერი დაკოპირებულია გაცვლის ბუფერში."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index a6376e3..c01af11 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Батарея екі баған."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Батарея үш баған."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Батарея толы."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Телефон жоқ."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Телефон бір баған."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Телефон екі баған."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Профиль бақылануы мүмкін"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Желі бақылауда болуы мүмкін"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Желі бақылауда болуы мүмкін"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Бұл құрылғыны ата-анаңыз басқарады."</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Ұйымыңыз осы құрылғыны басқарады және желі трафигін бақылауы мүмкін."</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> осы құрылғыны басқарады және желі трафигін бақылауы мүмкін."</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Бұл құрылғы ұйымыңызға тиесілі және <xliff:g id="VPN_APP">%1$s</xliff:g> қолданбасына қосылған."</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN функциясын өшіру"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN желісін ажырату"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Саясаттарды көру"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Басқару элементтерін көру"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Бұл құрылғы <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ұйымына тиесілі.\n\nӘкімші параметрлерді, корпоративтік кіру құқығын, қолданбаларды, құрылғыңызбен байланысты деректерді және құрылғыңыздың орналасқан жері туралы ақпаратты бақылай және басқара алады.\n\nҚосымша ақпарат алу үшін әкімшіге хабарласыңыз."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Бұл құрылғы ұйымыңызға тиесілі.\n\nӘкімші параметрлерді, корпоративтік кіру құқығын, қолданбаларды, құрылғыңызбен байланысты деректерді және құрылғыңыздың орналасқан жері туралы ақпаратты бақылай және басқара алады.\n\nҚосымша ақпарат алу үшін әкімшіге хабарласыңыз."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Ұйымыңыз осы құрылғыда сертификат орнатқан. Қорғалған желі трафигіңіз бақылануы немесе өзгертілуі мүмкін."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Әкімші құрылғыдағы трафикті қадағалау үшін желі журналын жүргізуді қосып қойған.\n\nТолығырақ ақпарат алу үшін әкімшімен хабарласыңыз."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Қолданбаға VPN байланысын орнату рұқсатын бердіңіз.\n\nБұл қолданба құрылғыңызды және желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алады."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Жұмыс профиліңізді <xliff:g id="ORGANIZATION">%1$s</xliff:g> басқарады.\n\nӘкімші желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және вебсайттарды бақылай алады.\n\nҚосымша ақпарат алу үшін әкімшіге хабарласыңыз.\n\nСондай-ақ сіз желідегі белсенділігіңізді бақылай алатын VPN желісіне қосылғансыз."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Бұл құрылғыны ата-анаңыз басқарады. Ата-анаңыз сіз пайдаланатын қолданбалар, геодерегіңіз және пайдалану уақытыңыз сияқты ақпаратты көре және басқара алады."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Сіз желідегі белсенділігіңізді, соның ішінде электрондық хабарларды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына қосылғансыз."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Сіз жеке желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына қосылғансыз."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Жаңа құрылғыны жұптау"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Құрама нөмірі"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Құрама нөмірі буферге көшірілді."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index b8d2fa8..652bf25 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -28,15 +28,15 @@
<string name="battery_low_percent_format" msgid="4276661262843170964">"នៅសល់ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="battery_low_percent_format_hybrid" msgid="3985614339605686167">"នៅសល់ <xliff:g id="PERCENTAGE">%1$s</xliff:g> អាចប្រើបានប្រហែល <xliff:g id="TIME">%2$s</xliff:g> ទៀតផ្អែកលើការប្រើប្រាស់របស់អ្នក"</string>
<string name="battery_low_percent_format_hybrid_short" msgid="5917433188456218857">"នៅសល់ <xliff:g id="PERCENTAGE">%1$s</xliff:g> អាចប្រើបានប្រហែល <xliff:g id="TIME">%2$s</xliff:g> ទៀត"</string>
- <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"នៅសល់ <xliff:g id="PERCENTAGE">%s</xliff:g> ។ កម្មវិធីសន្សំថ្មបានបើក។"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"នៅសល់ <xliff:g id="PERCENTAGE">%s</xliff:g>។ មុខងារសន្សំថ្មត្រូវបានបើក។"</string>
<string name="invalid_charger" msgid="4370074072117767416">"មិនអាចសាកតាម USB បានទេ។ សូមប្រើឆ្នាំងសាកដែលភ្ជាប់មកជាមួយឧបករណ៍របស់អ្នក។"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"មិនអាចសាកតាម USB បានទេ"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"សូមប្រើឆ្នាំងសាកដែលភ្ជាប់មកជាមួយឧបករណ៍របស់អ្នក"</string>
<string name="battery_low_why" msgid="2056750982959359863">"ការកំណត់"</string>
- <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"បើកកម្មវិធីសន្សំថ្ម?"</string>
- <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"អំពីកម្មវិធីសន្សំថ្ម"</string>
+ <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"បើកមុខងារសន្សំថ្ម?"</string>
+ <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"អំពីមុខងារសន្សំថ្ម"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"បើក"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"បើកកម្មវិធីសន្សំថ្ម"</string>
+ <string name="battery_saver_start_action" msgid="4553256017945469937">"បើកមុខងារសន្សំថ្ម"</string>
<string name="status_bar_settings_settings_button" msgid="534331565185171556">"ការកំណត់"</string>
<string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"វ៉ាយហ្វាយ"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"បង្វិលអេក្រង់ស្វ័យប្រវត្តិ"</string>
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"ថ្មពីរកាំ។"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"ថ្មទាំងបីកាំ។"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"ថ្មពេញហើយ។"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"គ្មានទូរស័ព្ទ។"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"សេវាទូរស័ព្ទមួយកាំ។"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"សេវាទូរស័ព្ទពីរកាំ។"</string>
@@ -498,9 +500,9 @@
<string name="user_remove_user_title" msgid="9124124694835811874">"យកអ្នកប្រើចេញ?"</string>
<string name="user_remove_user_message" msgid="6702834122128031833">"កម្មវិធី និងទិន្នន័យទាំងអស់របស់អ្នកប្រើនេះនឹងត្រូវបានលុប។"</string>
<string name="user_remove_user_remove" msgid="8387386066949061256">"យកចេញ"</string>
- <string name="battery_saver_notification_title" msgid="8419266546034372562">"កម្មវិធីសន្សំថ្មបានបើក"</string>
+ <string name="battery_saver_notification_title" msgid="8419266546034372562">"មុខងារសន្សំថ្មបានបើក"</string>
<string name="battery_saver_notification_text" msgid="2617841636449016951">"ការបន្ថយការប្រតិបត្តិ និងទិន្នន័យផ្ទៃខាងក្រោយ"</string>
- <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"បិទកម្មវិធីសន្សំថ្ម"</string>
+ <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"បិទមុខងារសន្សំថ្ម"</string>
<string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> នឹងមានសិទ្ធិចូលប្រើព័ត៌មានទាំងអស់ដែលអាចមើលឃើញនៅលើអេក្រង់របស់អ្នក ឬដែលចាក់ពីឧបករណ៍របស់អ្នក នៅពេលកំពុងថត ឬភ្ជាប់។ ព័ត៌មាននេះមានដូចជា ពាក្យសម្ងាត់ ព័ត៌មានលម្អិតអំពីការទូទាត់ប្រាក់ រូបថត សារ និងសំឡេងដែលអ្នកចាក់ជាដើម។"</string>
<string name="media_projection_dialog_service_text" msgid="958000992162214611">"សេវាកម្មដែលផ្ដល់មុខងារនេះនឹងមានសិទ្ធិចូលប្រើព័ត៌មានទាំងអស់ដែលអាចមើលឃើញនៅលើអេក្រង់របស់អ្នក ឬដែលចាក់ពីឧបករណ៍របស់អ្នក នៅពេលកំពុងថត ឬភ្ជាប់។ ព័ត៌មាននេះមានដូចជា ពាក្យសម្ងាត់ ព័ត៌មានលម្អិតអំពីការទូទាត់ប្រាក់ រូបថត សារ និងសំឡេងដែលអ្នកចាក់ជាដើម។"</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ចាប់ផ្ដើមថត ឬបញ្ជូនមែនទេ?"</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"ប្រវត្តិរូបអាចត្រូវបានតាមដាន"</string>
<string name="vpn_footer" msgid="3457155078010607471">"បណ្ដាញអាចត្រូវបានត្រួតពិនិត្យ"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"បណ្ដាញអាចត្រូវបានត្រួតពិនិត្យ"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ឧបករណ៍នេះស្ថិតក្រោមការគ្រប់គ្រងរបស់មាតាបិតាអ្នក"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"ស្ថាប័នរបស់អ្នកជាម្ចាស់ឧបករណ៍នេះ ហើយអាចនឹងតាមដានចរាចរណ៍បណ្តាញ"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ជាម្ចាស់ឧបករណ៍នេះ ហើយអាចនឹងតាមដានចរាចរណ៍បណ្តាញ"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"ឧបករណ៍នេះគឺជាកម្មសិទ្ធិរបស់ស្ថាប័នអ្នក និងត្រូវបានភ្ជាប់ទៅ <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"បិទ VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"ផ្ដាច់ VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"មើលគោលការណ៍"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"មើលការគ្រប់គ្រង"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"ឧបករណ៍នេះជាគឺកម្មសិទ្ធិរបស់ <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>។\n\nអ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នកអាចតាមដាន និងគ្រប់គ្រងការកំណត់ ការចូលប្រើជាលក្ខណៈក្រុមហ៊ុន កម្មវិធី ទិន្នន័យដែលពាក់ព័ន្ធនឹងឧបករណ៍របស់អ្នក និងព័ត៌មានទីតាំងរបស់ឧបករណ៍អ្នក។\n\nសម្រាប់ព័ត៌មានបន្ថែម សូមទាក់ទងអ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នក។"</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"ឧបករណ៍នេះគឺជាកម្មសិទ្ធិរបស់ស្ថាប័នអ្នក។\n\nអ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នកអាចតាមដាន និងគ្រប់គ្រងការកំណត់ ការចូលប្រើជាលក្ខណៈក្រុមហ៊ុន កម្មវិធី ទិន្នន័យដែលពាក់ព័ន្ធនឹងឧបករណ៍របស់អ្នក និងព័ត៌មានទីតាំងរបស់ឧបករណ៍អ្នក។\n\nសម្រាប់ព័ត៌មានបន្ថែម សូមទាក់ទងអ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នក។"</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"ស្ថាប័នរបស់អ្នកបានដំឡើងអាជ្ញាធរវិញ្ញាបនបត្រនៅលើឧបករណ៍នេះ។ ចរាចរណ៍បណ្តាញដែលមានសុវត្ថិភាពរបស់អ្នកអាចត្រូវបានតាមដាន ឬកែសម្រួល។"</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"អ្នកគ្រប់គ្រងរបស់អ្នកបានបើកការធ្វើកំណត់ហេតុបណ្តាញ ដែលនឹងតាមដានចរាចរណ៍នៅលើឧបករណ៍របស់អ្នក។\n\nសម្រាប់ព័ត៌មានបន្ថែម សូមទាក់ទងអ្នកគ្រប់គ្រងរបស់អ្នក។"</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"អ្នកបានអនុញ្ញាតឲ្យកម្មវិធីដំឡើងការតភ្ជាប់ VPN។\n\nកម្មវិធីនេះអាចឃ្លាំមើលឧបករណ៍ និងសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"កម្រងព័ត៌មានការងាររបស់អ្នកស្ថិតក្រោមការគ្រប់គ្រងរបស់ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ។\n\nអ្នកគ្រប់គ្រងរបស់អ្នកមានលទ្ធភាពតាមដានសកម្មភាពនៅលើបណ្តាញរបស់អ្នក រួមទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។\n\nសម្រាប់ព័ត៌មានបន្ថែម សូមទាក់ទងអ្នកគ្រប់គ្រងរបស់អ្នក។\n\nអ្នកក៏ត្រូវបានភ្ជាប់ទៅ VPN ដែលអាចតាមដានសកម្មភាពនៅលើបណ្តាញរបស់អ្នកផងដែរ។"</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ឧបករណ៍នេះស្ថិតក្រោមការគ្រប់គ្រងរបស់មាតាបិតាអ្នក។ មាតាបិតារបស់អ្នកអាចមើល និងគ្រប់គ្រងព័ត៌មានដូចជា កម្មវិធីដែលអ្នកប្រើ ទីតាំងរបស់អ្នក និងរយៈពេលប្រើប្រាស់ឧបករណ៍របស់អ្នកជាដើម។"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"អ្នកត្រូវបានតភ្ជាប់ទៅ <xliff:g id="APPLICATION">%1$s</xliff:g> ដែលអាចតាមដានសកម្មភាពបណ្តាញរបស់អ្នក រួមទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រផងដែរ។"</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"អ្នកត្រូវបានតភ្ជាប់ទៅ <xliff:g id="APPLICATION">%1$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។"</string>
@@ -774,7 +779,7 @@
<item quantity="one">%d នាទី</item>
</plurals>
<string name="battery_panel_title" msgid="5931157246673665963">"ការប្រើប្រាស់ថ្ម"</string>
- <string name="battery_detail_charging_summary" msgid="8821202155297559706">"កម្មវិធីសន្សំថ្មមិនអាចប្រើបានអំឡុងពេលសាកថ្មទេ"</string>
+ <string name="battery_detail_charging_summary" msgid="8821202155297559706">"មិនអាចប្រើមុខងារសន្សំថ្មបានទេក្នុងអំឡុងពេលសាកថ្ម"</string>
<string name="battery_detail_switch_title" msgid="6940976502957380405">"មុខងារសន្សំថ្ម"</string>
<string name="battery_detail_switch_summary" msgid="3668748557848025990">"កាត់បន្ថយប្រតិបត្តិការ និងទិន្នន័យផ្ទៃខាងក្រោយ"</string>
<string name="keyboard_key_button_template" msgid="8005673627272051429">"ប៊ូតុង <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -962,11 +967,11 @@
<string name="slice_permission_checkbox" msgid="4242888137592298523">"អនុញ្ញាតឱ្យ <xliff:g id="APP">%1$s</xliff:g> បង្ហាញស្ថិតិប្រើប្រាស់ពីកម្មវិធីនានា"</string>
<string name="slice_permission_allow" msgid="6340449521277951123">"អនុញ្ញាត"</string>
<string name="slice_permission_deny" msgid="6870256451658176895">"បដិសេធ"</string>
- <string name="auto_saver_title" msgid="6873691178754086596">"ចុចដើម្បីកំណត់កាលវិភាគកម្មវិធីសន្សំថ្ម"</string>
+ <string name="auto_saver_title" msgid="6873691178754086596">"ចុចដើម្បីកំណត់កាលវិភាគមុខងារសន្សំថ្ម"</string>
<string name="auto_saver_text" msgid="3214960308353838764">"បើកនៅពេលថ្មទំនងជាអស់"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"ទេ អរគុណ"</string>
- <string name="auto_saver_enabled_title" msgid="4294726198280286333">"កាលវិភាគកម្មវិធីសន្សំថ្មបានបើកហើយ"</string>
- <string name="auto_saver_enabled_text" msgid="7889491183116752719">"កម្មវិធីសន្សំថ្មនឹងបើកដោយស្វ័យប្រវត្តិ នៅពេលថ្មនៅសល់តិចជាង <xliff:g id="PERCENTAGE">%d</xliff:g>%% ។"</string>
+ <string name="auto_saver_enabled_title" msgid="4294726198280286333">"កាលវិភាគមុខងារសន្សំថ្មបានបើកហើយ"</string>
+ <string name="auto_saver_enabled_text" msgid="7889491183116752719">"មុខងារសន្សំថ្មនឹងបើកដោយស្វ័យប្រវត្តិ នៅពេលថ្មនៅសល់តិចជាង <xliff:g id="PERCENTAGE">%d</xliff:g>%%។"</string>
<string name="open_saver_setting_action" msgid="2111461909782935190">"ការកំណត់"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"យល់ហើយ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"ចម្លង SysUI Heap"</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ផ្គូផ្គងឧបករណ៍ថ្មី"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"លេខកំណែបង្កើត"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"បានចម្លងលេខកំណែបង្កើតទៅឃ្លីបបត។"</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 5c502ac..aa6c34e 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"ಬ್ಯಾಟರಿ ಎರಡು ಪಟ್ಟಿಗಳು."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"ಬ್ಯಾಟರಿ ಮೂರು ಪಟ್ಟಿಗಳು."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"ಬ್ಯಾಟರಿ ಭರ್ತಿಯಾಗಿದೆ."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"ಯಾವುದೇ ಫೋನ್ ಇಲ್ಲ."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"ಪೋನ್ ಒಂದು ಪಟ್ಟಿ."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"ಫೋನ್ ಎರಡು ಪಟ್ಟಿಗಳು."</string>
@@ -520,6 +522,8 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"ಪ್ರೊಫೈಲ್ ಅನ್ನು ಪರಿವೀಕ್ಷಿಸಬಹುದಾಗಿದೆ"</string>
<string name="vpn_footer" msgid="3457155078010607471">"ನೆಟ್ವರ್ಕ್ ಅನ್ನು ವೀಕ್ಷಿಸಬಹುದಾಗಿ"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"ನೆಟ್ವರ್ಕ್ ಅನ್ನು ವೀಕ್ಷಿಸಬಹುದಾಗಿರುತ್ತದೆ"</string>
+ <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
+ <skip />
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"ನಿಮ್ಮ ಸಂಸ್ಥೆಯು ಈ ಸಾಧನದ ಮಾಲೀಕತ್ವವನ್ನು ಹೊಂದಿದೆ ಮತ್ತು ಅದು ನೆಟ್ವರ್ಕ್ ಟ್ರಾಫಿಕ್ನ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ಈ ಸಾಧನದ ಮಾಲೀಕತ್ವವನ್ನು ಹೊಂದಿದೆ ಮತ್ತು ಅದು ನೆಟ್ವರ್ಕ್ ಟ್ರಾಫಿಕ್ನ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"ಈ ಸಾಧನವು ನಿಮ್ಮ ಸಂಸ್ಥೆಗೆ ಸೇರಿದೆ ಮತ್ತು <xliff:g id="VPN_APP">%1$s</xliff:g> ಗೆ ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string>
@@ -544,6 +548,8 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN ಸಂಪರ್ಕಕಡಿತಗೊಳಿಸಿ"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"ಕಾರ್ಯನೀತಿಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
+ <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
+ <skip />
<string name="monitoring_description_named_management" msgid="505833016545056036">"ಈ ಸಾಧನವು <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ಗೆ ಸೇರಿದೆ.\n\nಸೆಟ್ಟಿಂಗ್ಗಳು, ಕಾರ್ಪೊರೇಟ್ ಪ್ರವೇಶ, ಆ್ಯಪ್ಗಳು, ನಿಮ್ಮ ಸಾಧನಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಡೇಟಾ ಮತ್ತು ನಿಮ್ಮ ಸಾಧನದ ಸ್ಥಳದ ಮಾಹಿತಿಯನ್ನು ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು ಮತ್ತು ನಿರ್ವಹಿಸಬಹುದು.\n\nಹೆಚ್ಚಿನ ಮಾಹಿತಿಗಾಗಿ ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"ಈ ಸಾಧನವು ನಿಮ್ಮ ಸಂಸ್ಥೆಗೆ ಸೇರಿದೆ.\n\nಸೆಟ್ಟಿಂಗ್ಗಳು, ಕಾರ್ಪೊರೇಟ್ ಪ್ರವೇಶ, ಆ್ಯಪ್ಗಳು, ನಿಮ್ಮ ಸಾಧನಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಡೇಟಾ ಮತ್ತು ನಿಮ್ಮ ಸಾಧನದ ಸ್ಥಳದ ಮಾಹಿತಿಯನ್ನು ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು ಮತ್ತು ನಿರ್ವಹಿಸಬಹುದು.\n\nಹೆಚ್ಚಿನ ಮಾಹಿತಿಗಾಗಿ ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"ನಿಮ್ಮ ಸಂಸ್ಥೆಯು ಈ ಸಾಧನದಲ್ಲಿ ಪ್ರಮಾಣಪತ್ರ ಅಂಗೀಕಾರವನ್ನು ಸ್ಥಾಪಿಸಿದೆ. ನಿಮ್ಮ ಸುರಕ್ಷಿತ ನೆಟ್ವರ್ಕ್ ಟ್ರಾಫಿಕ್ ಅನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು ಅಥವಾ ಮಾರ್ಪಡಿಸಬಹುದು."</string>
@@ -567,6 +573,8 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ನೆಟ್ವರ್ಕ್ ಲಾಗಿಂಗ್ ಆನ್ ಮಾಡಿದ್ದಾರೆ. ಇದು ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿನ ಟ್ರಾಫಿಕ್ ಮೇಲೆ ನಿಗಾ ಇರಿಸುತ್ತದೆ.\n\nಹೆಚ್ಚಿನ ಮಾಹಿತಿಗೆ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"ನೀವು VPN ಸಂಪರ್ಕ ಹೊಂದಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿ ನೀಡಿರುವಿರಿ.\n\nಈ ಅಪ್ಲಿಕೇಶನ್ ಇಮೇಲ್ಗಳು, ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ವೆಬ್ಸೈಟ್ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ನೆಟ್ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು <xliff:g id="ORGANIZATION">%1$s</xliff:g> ನಿರ್ವಹಿಸುತ್ತಿದೆ.\n\nಇಮೇಲ್ಗಳು, ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ವೆಬ್ಸೈಟ್ಗಳೂ ಸೇರಿದಂತೆ ನಿಮ್ಮ ನೆಟ್ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲೆ ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ನಿಗಾ ಇರಿಸಬಲ್ಲರು.\n\nಹೆಚ್ಚಿನ ಮಾಹಿತಿಗಾಗಿ, ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ.\n\nಅಲ್ಲದೇ, ನಿಮ್ಮ ನೆಟ್ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ನಿಗಾ ವಹಿಸುವ VPN ಗೂ ಸಹ ನೀವು ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
+ <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
+ <skip />
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"ನೀವು <xliff:g id="APPLICATION">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ. ಇದು ನಿಮ್ಮ ಇಮೇಲ್ಗಳು, ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ವೆಬ್ಸೈಟ್ಗಳೂ ಸೇರಿದಂತೆ ನೆಟ್ವರ್ಕ್ ಚಟುವಟಿಕೆಯನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"ನೀವು ಇಮೇಲ್ಗಳು, ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ವೆಬ್ಸೈಟ್ಗಳು ಸೇರಿದಂತೆ ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ನೆಟ್ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
@@ -1089,4 +1097,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ಹೊಸ ಸಾಧನವನ್ನು ಜೋಡಿಸಿ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ಬಿಲ್ಡ್ ಸಂಖ್ಯೆ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ಬಿಲ್ಡ್ ಸಂಖ್ಯೆಯನ್ನು ಕ್ಲಿಪ್ಬೋರ್ಡ್ನಲ್ಲಿ ನಕಲಿಸಲಾಗಿದೆ."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index cef5158..38648d0 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"배터리 막대가 두 개입니다."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"배터리 막대가 세 개입니다."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"배터리 충전이 완료되었습니다."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"휴대전화의 신호가 없습니다."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"휴대전화 신호 막대가 하나입니다."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"휴대전화 신호 막대가 두 개입니다."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"프로필이 모니터링될 수 있음"</string>
<string name="vpn_footer" msgid="3457155078010607471">"네트워크가 모니터링될 수 있음"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"네트워크가 모니터링될 수 있음"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"부모님이 관리하는 기기입니다."</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"내 조직에서 이 기기를 소유하며 네트워크 트래픽을 모니터링할 수 있습니다."</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>에서 이 기기를 소유하며 네트워크 트래픽을 모니터링할 수 있습니다."</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"내 조직에 속한 기기이며 <xliff:g id="VPN_APP">%1$s</xliff:g>에 연결되었습니다."</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN 사용 중지"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN 연결 해제"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"정책 보기"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"제어 기능 보기"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>에 속한 기기입니다.\n\nIT 관리자가 설정, 기업 액세스, 앱, 기기와 연결된 데이터, 기기 위치 정보를 모니터링 및 관리할 수 있습니다.\n\n자세한 정보를 확인하려면 IT 관리자에게 문의하세요."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"내 조직에 속한 기기입니다.\n\nIT 관리자가 설정, 기업 액세스, 앱, 기기와 연결된 데이터, 기기 위치 정보를 모니터링 및 관리할 수 있습니다.\n\n자세한 정보를 확인하려면 IT 관리자에게 문의하세요."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"조직에서 이 기기에 인증기관을 설치했습니다. 보안 네트워크 트래픽을 모니터링 또는 수정할 수 있습니다."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"관리자가 기기에서 발생하는 트래픽을 모니터링하는 네트워크 로깅을 사용 설정했습니다.\n\n자세한 정보는 관리자에게 문의하세요."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"VPN 연결을 설정할 수 있는 권한을 앱에 부여했습니다.\n\n이 앱에서 이메일, 앱, 웹사이트와 같은 내 네트워크 활동 및 기기를 모니터링할 수 있습니다."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g>에서 직장 프로필을 관리합니다.\n\n관리자가 이메일, 앱, 웹사이트를 비롯한 네트워크 활동을 모니터링할 수 있습니다.\n\n자세한 정보는 관리자에게 문의하세요.\n\n또한 VPN에 연결되어 있으며, VPN에서 네트워크 활동을 모니터링할 수 있습니다."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"부모님이 관리하는 기기입니다. 부모님이 내가 사용하는 앱, 위치, 기기 사용 시간과 같은 정보를 보고 관리할 수 있습니다."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"<xliff:g id="APPLICATION">%1$s</xliff:g>에 연결되었습니다. 이 앱은 이메일, 앱, 웹사이트와 같은 내 네트워크 활동을 모니터링할 수 있습니다."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"<xliff:g id="APPLICATION">%1$s</xliff:g>에 연결되었습니다. 이 앱은 이메일, 앱, 웹사이트와 같은 내 네트워크 활동을 모니터링할 수 있습니다."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"새 기기와 페어링"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"빌드 번호"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"빌드 번호가 클립보드에 복사되었습니다."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 572c3e7..2a4e077 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Эки таякча батарея."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Үч таякча батарея."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Батарея толук."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Телефон сигналы жок."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Телефон сигналы бир таякча."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Телефон сигналы эки таякча."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Профилди көзөмөлдөсө болот"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Тармак көзөмөлдөнүшү мүмкүн"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Тармак көзөмөлдөнүшү мүмкүн"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Бул түзмөктү ата-энең башкарат"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Бул түзмөк уюмуңузга таандык. Уюмуңуз тармактын трафигин көзөмөлдөй алат"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"Бул түзмөк <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> уюмуна таандык. Уюм тармактын трафигин көзөмөлдөй алат"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Бул түзмөк уюмуңузга таандык жана <xliff:g id="VPN_APP">%1$s</xliff:g> колдонмосуна туташтырылган"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN\'ди өчүрүү"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN\'ди ажыратуу"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Саясаттарды карап көрүү"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Башкаруу элементтерин көрүү"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Бул түзмөк <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> уюмуна таандык.\n\nIT администраторуңуз жөндөөлөрдү, корпоративдик мүмкүнчүлүктү, колдонмолорду, түзмөгүңүзгө байланыштуу дайын-даректерди жана түзмөгүңүздүн жайгашкан жери тууралуу маалыматты көзөмөлдөп жана башкара алат.\n\nТолугураак маалымат алуу үчүн, IT администраторуңузга кайрылыңыз."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Бул түзмөк уюмуңузга таандык.\n\nIT администраторуңуз жөндөөлөрдү, корпоративдик мүмкүнчүлүктү, колдонмолорду, түзмөгүңүзгө байланыштуу дайын-даректерди жана түзмөгүңүздүн жайгашкан жери тууралуу маалыматты көзөмөлдөп жана башкара алат.\n\nТолугураак маалымат алуу үчүн, IT администраторуңузга кайрылыңыз."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Ишканаңыз бул түзмөккө тастыктоочу борборду орнотту. Коопсуз тармагыңыздын трафиги көзөмөлдөнүп же өзгөртүлүшү мүмкүн."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Администраторуңуз тармактын таржымалын алууну иштетти, андыктан түзмөгүңүздөгү трафик көзөмөлгө алынды.\n\nКеңири маалымат алуу үчүн администраторуңузга кайрылыңыз."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Колдонмого VPN туташуусун орнотууга уруксат бердиңиз.\n\nБул колдонмо түзмөгүңүздү жана электрондук почталар, колдонмолор жана вебсайттар сыяктуу тармактагы аракеттериңизди көзөмөлдөй алат."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Жумуш профилиңизди <xliff:g id="ORGANIZATION">%1$s</xliff:g> башкарат.\n\nАдминистраторуңуздун тармактагы аракетиңизди, анын ичинде электрондук почталар, колдонмолор жана вебсайттарды көзөмөлдөө мүмкүнчүлүгү бар.\n\nКөбүрөөк маалымат үчүн, администраторуңузга кайрылыңыз.\n\nСиз тармактагы жеке аракетиңизди көзөмөлдөй турган VPN\'ге да туташкансыз."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Бул түзмөктү ата-энең башкарат. Ата-энең сен иштеткен колдонмолорду, кайда жүргөнүңдү жана түзмөктү канча убакыт колдонгонуңду көрүп, башкарып турат."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Электрондук почта, колдонмолор жана вебсайттар сыяктуу тармактык аракеттерди көзөмөлдөй турган <xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосуна туташып турасыз."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Электрондук почта, колдонмолор жана вебсайттар сыяктуу тармактагы жеке аракеттериңизди көзөмөлдөй турган <xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосуна туташып турасыз."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Жаңы түзмөктү жупташтыруу"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Курама номери"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Курама номери алмашуу буферине көчүрүлдү."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index b584dfe..e45f4eb 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -36,10 +36,6 @@
<dimen name="volume_tool_tip_right_margin">136dp</dimen>
<dimen name="volume_tool_tip_top_margin">12dp</dimen>
- <!-- Padding between status bar and bubbles when displayed in expanded state, smaller
- value in landscape since we have limited vertical space-->
- <dimen name="bubble_padding_top">4dp</dimen>
-
<dimen name="controls_activity_view_top_offset">25dp</dimen>
<dimen name="biometric_dialog_button_negative_max_width">140dp</dimen>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 1cc1b4e..93ecff09 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -182,6 +182,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"ແບັດເຕີຣີສອງຂີດ."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"ແບັດເຕີຣີສາມຂີດ."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"ແບັດເຕີຣີເຕັມ."</string>
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ບໍ່ຮູ້ເປີເຊັນແບັດເຕີຣີ."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"ບໍ່ມີໂທລະສັບ."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"ສັນຍານນຶ່ງຂີດ."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"ສັນຍານສອງຂີດ."</string>
@@ -520,6 +521,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"ໂປຣໄຟລ໌ອາດຖືກເຝົ້າຕິດຕາມຢູ່"</string>
<string name="vpn_footer" msgid="3457155078010607471">"ເຄືອຂ່າຍອາດມີການເຝົ້າຕິດຕາມ"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"ການນຳໃຊ້ເຄືອຂ່າຍອາດມີການກວດສອບຕິດຕາມ"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ອຸປະກອນນີ້ແມ່ນຈັດການໂດຍພໍ່ແມ່ຂອງທ່ານ"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"ອົງການຂອງທ່ານເປັນເຈົ້າຂອງອຸປະກອນນີ້ ແລະ ສາມາດຕິດຕາມທຣາບຟິກເຄືອຂ່າຍໄດ້"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ເປັນເຈົ້າຂອງອຸປະກອນນີ້ ແລະ ສາມາດຕິດຕາມທຣາບຟິກເຄືອຂ່າຍໄດ້"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"ອຸປະກອນນີ້ເປັນຂອງອົງການທ່ານ ແລະ ເຊື່ອມຕໍ່ຫາ <xliff:g id="VPN_APP">%1$s</xliff:g> ແລ້ວ"</string>
@@ -544,6 +546,7 @@
<string name="disable_vpn" msgid="482685974985502922">"ປິດການໃຊ້ VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"ຕັດການເຊື່ອມຕໍ່ VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"ເບິ່ງນະໂຍບາຍ"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"ເບິ່ງການຄວບຄຸມ"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"ອຸປະກອນນີ້ເປັນຂອງ <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nຜູ້ເບິ່ງແຍງໄອທີຂອງທ່ານສາມາດເຝົ້າຕິດຕາມ ແລະ ຈັດການການຕັ້ງຄ່າ, ສິດເຂົ້າເຖິງອົງກອນ, ແອັບ, ຂໍ້ມູນທີ່ເຊື່ອມໂຍງກັບອຸປະກອນຂອງທ່ານໄດ້.\n\nສຳລັບຂໍ້ມູນເພີ່ມເຕີມ, ກະລຸນາຕິດຕໍ່ຜູ້ເບິ່ງແຍງໄອທີຂອງທ່ານ."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"ອຸປະກອນນີ້ເປັນຂອງອົງການທ່ານ.\n\nຜູ້ເບິ່ງແຍງໄອທີຂອງທ່ານສາມາດເຝົ້າຕິດຕາມ ແລະ ຈັດການການຕັ້ງຄ່າ, ສິດເຂົ້າເຖິງອົງກອນ, ແອັບ, ຂໍ້ມູນທີ່ເຊື່ອມໂຍງກັບອຸປະກອນຂອງທ່ານໄດ້.\n\nສຳລັບຂໍ້ມູນເພີ່ມເຕີມ, ກະລຸນາຕິດຕໍ່ຜູ້ເບິ່ງແຍງໄອທີຂອງທ່ານ."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"ອົງກອນຂອງທ່ານຕິດຕັ້ງອຳນາດໃບຮັບຮອງໄວ້ໃນອຸປະກອນນີ້. ທຣາບຟິກເຄືອຂ່າຍທີ່ເຂົ້າລະຫັດໄວ້ຂອງທ່ານອາດຖືກຕິດຕາມ ຫຼື ແກ້ໄຂໄດ້."</string>
@@ -567,6 +570,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Your admin has turned on network logging, which monitors traffic on your device.\n\nFor more information, contact your admin."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"ທ່ານໄດ້ອະນຸຍາດໃຫ້ແອັບຕັ້ງການເຊື່ອມຕໍ່ VPN.\n\nແອັບນີ້ສາມາດຕິດຕາມການເຄື່ອນໄຫວຂອງອຸປະກອນ ແລະເຄືອຂ່າຍຂອງທ່ານ ເຊິ່ງລວມທັງອີເມວ, ແອັບ ແລະເວັບໄຊທ໌."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour admin is capable of monitoring your network activity including emails, apps, and websites.\n\nFor more information, contact your admin.\n\nYou\'re also connected to a VPN, which can monitor your network activity."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ອຸປະກອນນີ້ແມ່ນຈັດການໂດຍພໍ່ແມ່ຂອງທ່ານ. ພໍ່ແມ່ຂອງທ່ານສາມາດເບິ່ງ ແລະ ຈັດການຂໍ້ມູນໄດ້ ເຊັ່ນ: ແອັບທີ່ທ່ານໃຊ້, ສະຖານທີ່ ແລະ ເວລາໜ້າຈໍຂອງທ່ານ."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"ທ່ານເຊື່ອມຕໍ່ຫາ <xliff:g id="APPLICATION">%1$s</xliff:g> ແລ້ວ, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍຂອງທ່ານ ຮວມທັງອີເມວ, ແອັບ ແລະ ເວັບໄຊ."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"ທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION">%1$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍສ່ວນຕົວຂອງທ່ານ ລວມທັງອີເມວ, ແອັບ ແລະເວັບໄຊທ໌."</string>
@@ -1089,4 +1093,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ຈັບຄູ່ອຸປະກອນໃໝ່"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ໝາຍເລກສ້າງ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ສຳເນົາໝາຍເລກສ້າງໄປໃສ່ຄລິບບອດແລ້ວ."</string>
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ເກີດບັນຫາໃນການອ່ານຕົວວັດແທກແບັດເຕີຣີຂອງທ່ານ"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ແຕະເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 152a532..ec102b7 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Dvi akumuliatoriaus juostos."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Trys akumuliatoriaus juostos."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Akumuliatorius įkrautas."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Nėra telefono."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Viena telefono juosta."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Dvi telefono juostos."</string>
@@ -526,6 +528,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profilis gali būti stebimas"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Tinklas gali būti stebimas"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Tinklas gali būti stebimas"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Šį įrenginį tvarko vienas iš tavo tėvų"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Šis įrenginys priklauso jūsų organizacijai ir ji gali stebėti tinklo srautą"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"Šis įrenginys priklauso „<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>“ ir ji gali stebėti tinklo srautą"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Šis įrenginys priklauso jūsų organizacijai ir yra susietas su „<xliff:g id="VPN_APP">%1$s</xliff:g>“"</string>
@@ -550,6 +553,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Išjungti VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Atjungti VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Žr. politiką"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Rodinio valdikliai"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Šis įrenginys priklauso „<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>“.\n\nIT administratorius gali stebėti ir tvarkyti nustatymus, įmonės prieigą, programas, su įrenginiu susietus duomenis ir įrenginio vietovės informaciją.\n\nDaugiau informacijos galite gauti susisiekę su IT administratoriumi."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Šis įrenginys priklauso jūsų organizacijai.\n\nIT administratorius gali stebėti ir tvarkyti nustatymus, įmonės prieigą, programas, su įrenginiu susietus duomenis ir įrenginio vietovės informaciją.\n\nDaugiau informacijos galite gauti susisiekę su IT administratoriumi."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Jūsų organizacija įdiegė šiame įrenginyje sertifikato įgaliojimą. Jūsų saugaus tinklo srautas gali būti stebimas arba keičiamas."</string>
@@ -573,6 +577,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Administratorius įjungė tinklo duomenų įrašymą į žurnalą. Įjungus šią funkciją stebimas srautas jūsų įrenginyje.\n\nJei reikia daugiau informacijos, susisiekite su administratoriumi."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Suteikėte programai leidimą nustatyti VPN ryšį.\n\nŠi programa gali stebėti įrenginio ir tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Jūsų darbo profilį tvarko „<xliff:g id="ORGANIZATION">%1$s</xliff:g>“.\n\nJūsų administratorius gali stebėti jūsų tinklo veiklą, įskaitant el. laiškus, programas ir svetaines.\n\nJei reikia daugiau informacijos, susisiekite su administratoriumi.\n\nTaip pat esate prisijungę prie VPN, kuris gali stebėti jūsų tinklo veiklą."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Šį įrenginį tvarko vienas iš tavo tėvų. Jis gali peržiūrėti ir tvarkyti informaciją, pvz., tavo naudojamas programas, vietovę ir įrenginio naudojimo laiką."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Esate prisijungę prie „<xliff:g id="APPLICATION">%1$s</xliff:g>“, kuri gali stebėti tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Esate prisijungę prie programos „<xliff:g id="APPLICATION">%1$s</xliff:g>“, kuri gali stebėti asmeninio profilio tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
@@ -1101,4 +1106,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Naujo įrenginio susiejimas"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijos numeris"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versijos numeris nukopijuotas į iškarpinę."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index ae67d0f..9c12665 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Akumulators: divas joslas."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Akumulators: trīs joslas."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Akumulators ir pilnīgi uzlādēts."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Nav tālruņa."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Tālrunis: viena josla."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Tālrunis: divas joslas."</string>
@@ -523,6 +525,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profilu var pārraudzīt"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Iespējams, tīklā veiktās darbības tiek pārraudzītas."</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Var tikt pārraudzītas tīklā veiktās darbības."</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Šo ierīci pārvalda viens no jūsu vecākiem."</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Šī ierīce pieder jūsu organizācijai, un jūsu organizācija var uzraudzīt tīkla datplūsmu."</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"Šī ierīce pieder organizācijai<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>, un šī organizācija var uzraudzīt tīkla datplūsmu."</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Šī ierīce pieder jūsu organizācijai un ir saistīta ar: <xliff:g id="VPN_APP">%1$s</xliff:g>."</string>
@@ -547,6 +550,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Atspējot VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Atvienot VPN tīklu"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Skatīt politikas"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Skatīt vadīklas"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Šī ierīce pieder organizācijai <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nJūsu IT administrators var pārraudzīt un pārvaldīt iestatījumus, korporatīvo piekļuvi, lietotnes, ar ierīci saistītos datus un ierīces atrašanās vietas informāciju.\n\nLai iegūtu plašāku informāciju, sazinieties ar IT administratoru."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Šī ierīce pieder jūsu organizācijai.\n\nJūsu IT administrators var pārraudzīt un pārvaldīt iestatījumus, korporatīvo piekļuvi, lietotnes, ar ierīci saistītos datus un ierīces atrašanās vietas informāciju.\n\nLai iegūtu plašāku informāciju, sazinieties ar IT administratoru."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Jūsu organizācija instalēja sertifikātu šajā ierīcē. Jūsu drošā tīkla datplūsma var tikt uzraudzīta."</string>
@@ -570,6 +574,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Administrators ir ieslēdzis tīkla reģistrēšanu, kuru izmanto, lai pārraudzītu datplūsmu jūsu ierīcē.\n\nLai iegūtu plašāku informāciju, sazinieties ar administratoru."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Jūs piešķīrāt lietotnei atļauju izveidot savienojumu ar VPN tīklu.\n\nŠī lietotne var pārraudzīt jūsu ierīcē un tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Jūsu darba profilu pārvalda <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrators var pārraudzīt jūsu darbības darba tīklā, tostarp e-pastu, lietotnes un vietnes.\n\nLai iegūtu plašāku informāciju, sazinieties ar administratoru.\n\nIr izveidots savienojums arī ar VPN, kurā var pārraudzīt jūsu darbības tīklā."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Šo ierīci pārvalda viens no jūsu vecākiem. Vecāki var skatīt un pārvaldīt tādu informāciju kā jūsu izmantotās lietotnes, atrašanās vieta un izmantošanas ilgums."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Ir izveidots savienojums ar lietotni <xliff:g id="APPLICATION">%1$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Ir izveidots savienojums ar lietotni <xliff:g id="APPLICATION">%1$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās privātās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
@@ -1095,4 +1100,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Savienošana pārī ar jaunu ierīci"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijas numurs"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versijas numurs ir kopēts starpliktuvē."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index fca688d..a67e3b5 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Батерија две цртички."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Батерија три цртички."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Батеријата е полна."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Нема сигнал."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Телефон една цртичка.."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Телефон две цртички."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Профилот можеби се следи"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Мрежата може да се следи"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Мрежата може да се следи"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Родителот управува со уредов"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Организацијата е сопственик на уредов и може да го следи мрежниот сообраќај"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> е сопственик на уредов и може да го следи мрежниот сообраќај"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Уредов е во сопственост на организацијата и е поврзан со <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Оневозможи ВПН"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Исклучи ВПН"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Прикажи „Политики“"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Прикажи ги контролите"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Уредов е во сопственост на <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nIT-администраторот може да ги следи и да управува со поставките, корпоративниот пристап, апликациите, податоците поврзани со уредот и податоците за локацијата на уредот.\n\nЗа повеќе информации, контактирајте со IT-администраторот."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Уредов е во сопственост на организацијата.\n\nIT-администраторот може да ги следи и да управува со поставките, корпоративниот пристап, апликациите, податоците поврзани со уредот и податоците за локацијата на уредот.\n\nЗа повеќе информации, контактирајте со IT-администраторот."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Вашата организација инсталираше авторитет за сертификат на уредов. Сообраќајот на вашата безбедна мрежа можно е да се следи или изменува."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Вашиот администратор вклучил евиденција на мрежата, што подразбира следење на сообраќајот на вашиот уред.\n\nЗа повеќе информации, контактирајте со администраторот."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Дозволивте апликацијата да постави поврзување преку ВПН.\n\nАпликацијата може да го следи уредот и активноста на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> управува со вашиот работен профил.\n\nАдминистратор е во можност да ја следи вашата активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите.\n\nЗа повеќе информации, контактирајте со администраторот.\n\nYИсто така, поврзани сте на VPN којашто може да ја следи вашата активност на мрежата."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Родителот управува со уредов. Родителот може да прегледува и управува со податоците, како што се апликациите што ги користите, вашата локација и време поминато на уредот."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"ВПН"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Поврзани сте на <xliff:g id="APPLICATION">%1$s</xliff:g>, што може да ја следи вашата активност на мрежата, заедно со е-пораките, апликациите и веб-сајтовите."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Поврзани сте на <xliff:g id="APPLICATION">%1$s</xliff:g>, којашто може да ја следи вашата лична активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Спарете нов уред"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Број на верзија"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Бројот на верзијата е копиран во привремената меморија."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index cd75761..3b6c616 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"ബാറ്ററി രണ്ട് ബാർ."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"ബാറ്ററി മൂന്ന് ബാർ."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"ബാറ്ററി നിറഞ്ഞു."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"ഫോൺ സിഗ്നൽ ഒന്നുമില്ല."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"ഫോണിൽ ഒരു ബാർ."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"ഫോണിൽ രണ്ട് ബാർ."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"പ്രൊഫൈൽ നിരീക്ഷിക്കപ്പെടാം"</string>
<string name="vpn_footer" msgid="3457155078010607471">"നെറ്റ്വർക്ക് നിരീക്ഷിക്കപ്പെടാം"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"നെറ്റ്വർക്ക് നിരീക്ഷിക്കപ്പെടാം"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ഈ ഉപകരണം മാനേജ് ചെയ്യുന്നത് നിങ്ങളുടെ രക്ഷിതാവാണ്"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"ഈ ഉപകരണം നിങ്ങളുടെ സ്ഥാപനത്തിന്റെ ഉടമസ്ഥതയിലായതിനാൽ നെറ്റ്വർക്ക് ട്രാഫിക്ക് നിരീക്ഷിച്ചേക്കാം"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"ഈ ഉപകരണം <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> എന്ന സ്ഥാപനത്തിന്റെ ഉടമസ്ഥതയിലായതിനാൽ നെറ്റ്വർക്ക് ട്രാഫിക്ക് നിരീക്ഷിച്ചേക്കാം"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"ഈ ഉപകരണം നിങ്ങളുടെ സ്ഥാപനത്തിന്റേതാണ്, കൂടാതെ <xliff:g id="VPN_APP">%1$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റ് ചെയ്തിരിക്കുന്നു"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN പ്രവർത്തനരഹിതമാക്കുക"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN വിച്ഛേദിക്കുക"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"നയങ്ങൾ കാണുക"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"നിയന്ത്രണങ്ങൾ കാണുക"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"ഈ ഉപകരണം <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>എന്ന സ്ഥാപനത്തിന്റേതാണ്.\n\nക്രമീകരണം, കോർപ്പറേറ്റ് ആക്സസ്, ആപ്പുകൾ, നിങ്ങളുടെ ഉപകരണവുമായി ബന്ധപ്പെട്ട ഡാറ്റ, ഉപകരണത്തിന്റെ ലൊക്കേഷൻ വിവരങ്ങൾ എന്നിവ നിരീക്ഷിക്കാനും മാനേജ് ചെയ്യാനും നിങ്ങളുടെ ഐടി അഡ്മിന് കഴിയും.\n\nകൂടുതൽ വിവരങ്ങൾക്ക് നിങ്ങളുടെ ഐടി അഡ്മിനെ ബന്ധപ്പെടുക."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"ഈ ഉപകരണം നിങ്ങളുടെ സ്ഥാപനത്തിന്റേതാണ്.\n\nക്രമീകരണം, കോർപ്പറേറ്റ് ആക്സസ്, ആപ്പുകൾ, നിങ്ങളുടെ ഉപകരണവുമായി ബന്ധപ്പെട്ട ഡാറ്റ, ഉപകരണത്തിന്റെ ലൊക്കേഷൻ വിവരങ്ങൾ എന്നിവ നിരീക്ഷിക്കാനും മാനേജ് ചെയ്യാനും നിങ്ങളുടെ ഐടി അഡ്മിന് കഴിയും.\n\nകൂടുതൽ വിവരങ്ങൾക്ക് നിങ്ങളുടെ ഐടി അഡ്മിനെ ബന്ധപ്പെടുക."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"ഈ ഉപകരണത്തിൽ നിങ്ങളുടെ സ്ഥാപനമൊരു സർട്ടിഫിക്കറ്റ് അതോറിറ്റി ഇൻസ്റ്റാൾ ചെയ്തിരിക്കുന്നു. നിങ്ങളുടെ സുരക്ഷിത നെറ്റ്വർക്ക് ട്രാഫിക്ക് നിരീക്ഷിക്കപ്പെടുകയോ പരിഷ്കരിക്കപ്പെടുയോ ചെയ്തേക്കാം."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"നിങ്ങളുടെ ഉപകരണത്തിലെ ട്രാഫിക്ക് നിരീക്ഷിക്കുന്ന നെറ്റ്വർക്ക് ലോഗിംഗ് അഡ്മിൻ ഓണാക്കിയിട്ടുണ്ട്.\n\nകൂടുതൽ വിവരങ്ങൾക്ക് അഡ്മിനുമായി ബന്ധപ്പെടുക."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"VPN കണക്ഷൻ സജ്ജീകരിക്കാൻ നിങ്ങൾ ഒരു ആപ്പിന് അനുമതി നൽകി.\n\nഈ ആപ്പിന് നിങ്ങളുടെ ഇമെയിലുകളും ആപ്സും വെബ്സൈറ്റുകളും ഉൾപ്പെടെ, ഉപകരണവും നെറ്റ്വർക്ക് പ്രവർത്തനവും നിരീക്ഷിക്കാൻ കഴിയും."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ നിയന്ത്രിക്കുന്നത് <xliff:g id="ORGANIZATION">%1$s</xliff:g> ആണ്.\n\nഇമെയിലുകൾ, ആപ്സ്, വെബ്സൈറ്റുകൾ എന്നിവയടങ്ങുന്ന നിങ്ങളുടെ നെറ്റ്വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാൻ അഡ്മിന് കഴിയും.\n\nകൂടുതൽ വിവരങ്ങൾക്ക് അഡ്മിനുമായി ബന്ധപ്പെടുക.\n\nനെറ്റ്വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാൻ സാധിക്കുന്ന ഒരു VPN-ലേക്ക് കൂടി നിങ്ങൾ കണക്റ്റ് ചെയ്യപ്പെട്ടിരിക്കുന്നു."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ഈ ഉപകരണം മാനേജ് ചെയ്യുന്നത് നിങ്ങളുടെ രക്ഷിതാവാണ്. നിങ്ങൾ ഉപയോഗിക്കുന്ന ആപ്പുകൾ, സ്ക്രീൻ സമയം, ലൊക്കേഷൻ എന്നിവ പോലുള്ള വിവരങ്ങൾ നിങ്ങളുടെ രക്ഷിതാവിന് കാണാം, നിയന്ത്രിക്കാം."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"നിങ്ങൾ <xliff:g id="APPLICATION">%1$s</xliff:g> ആപ്പിലേക്ക് കണക്റ്റുചെയ്തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്പുകൾ, വെബ്സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ നെറ്റ്വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാനാകും."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"നിങ്ങൾ <xliff:g id="APPLICATION">%1$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്സ്, വെബ്സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ സ്വകാര്യ നെറ്റ്വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"പുതിയ ഉപകരണവുമായി ജോടിയാക്കുക"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ബിൽഡ് നമ്പർ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ക്ലിപ്പ്ബോർഡിലേക്ക് ബിൽഡ് നമ്പർ പകർത്തി."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 4eb2fb1..ef110e9 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Батерей хоёр баганатай."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Батерей гурван баганатай."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Батерей дүүрэн."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Утас байхгүй."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Утас нэг баганатай."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Утас хоёр баганатай."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Профайлыг хянаж байж болзошгүй"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Сүлжээ хянагдаж байж болзошгүй"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Сүлжээг хянаж байж болзошгүй"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Энэ төхөөрөмжийг таны эцэг эх удирддаг"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Танай байгууллага энэ төхөөрөмжийг эзэмшдэг бөгөөд сүлжээний ачааллыг хянаж болно"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> энэ төхөөрөмжийг эзэмшдэг бөгөөд сүлжээний ачааллыг хянаж болно"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Энэ төхөөрөмж танай байгууллагад харьяалагддаг бөгөөд <xliff:g id="VPN_APP">%1$s</xliff:g>-д холбогдсон байна"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN идэвхгүйжүүлэх"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN таслах"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Удирдамж харах"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Хяналтыг харах"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Энэ төхөөрөмж <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>-д харьяалагддаг.\n\nТанай IT админ тохиргоо, байгууллагын хандалт, аппууд, таны төхөөрөмжтэй холбоотой өгөгдөл, таны төхөөрөмжийн байршлын мэдээллийг хянах, удирдах боломжтой.\n\nНэмэлт мэдээлэл авахын тулд IT админтайгаа холбогдоно уу."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Энэ төхөөрөмж танай байгууллагад харьяалагддаг.\n\nТанай IT админ тохиргоо, байгууллагын хандалт, аппууд, таны төхөөрөмжтэй холбоотой өгөгдөл, таны төхөөрөмжийн байршлын мэдээллийг хянах, удирдах боломжтой.\n\nНэмэлт мэдээлэл авахын тулд IT админтайгаа холбогдоно уу."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Таны байгууллага энэ төхөөрөмжид сертификатын зөвшөөрлийг суулгасан байна. Таны аюулгүй сүлжээний ачааллыг өөрчлөх эсвэл хянах боломжтой."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Таны админ төхөөрөмжийн ачааллыг хянадаг сүлжээний логийг асаасан байна.\n\nДэлгэрэнгүй мэдээлэл авах бол админтайгаа холбогдоно уу."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Та апп-д VPN холболт хийхийг зөвшөөрсөн байна.\n\nЭнэхүү апп нь таны имэйл, апп, вебсайт зэрэг төхөөрөмж болон сүлжээний үйл ажиллагааг хянах боломжтой."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> таны ажлын профайлыг удирддаг.\n\nТаны админ имэйл, апп болон веб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой.\n\nДэлгэрэнгүй мэдээлэл авах бол админтайгаа холбогдоно уу.\n\nТа сүлжээний үйл ажиллагааг хянах боломжтой VPN-д холбогдсон байна."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Энэ төхөөрөмжийг таны эцэг эх удирддаг. Таны эцэг эх таны хэрэглэдэг апп, байршил, дэлгэцийн цаг зэрэг мэдээллийг харж, удирдах боломжтой."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вебсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вебсайт зэрэг сүлжээний хувийн үйл ажиллагааг хянах боломжтой."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Шинэ төхөөрөмж хослуулах"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Хийгдсэн дугаар"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Хийгдсэн дугаарыг түр санах ойд хуулсан."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 57c1e07..9b3ee71 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"बॅटरी दोन बार."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"बॅटरी तीन बार."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"बॅटरी पूर्ण भरली."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"कोणताही फोन नाही."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"फोन एक बार."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"फोन दोन बार."</string>
@@ -520,6 +522,8 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"प्रोफाईलचे परीक्षण केले जाऊ शकते"</string>
<string name="vpn_footer" msgid="3457155078010607471">"नेटवर्कचे परीक्षण केले जाऊ शकते"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"नेटवर्कचे परीक्षण केले जाऊ शकते"</string>
+ <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
+ <skip />
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"तुमच्या संस्थेकडे या डिव्हाइसची मालकी आहे आणि ती नेटवर्क ट्रॅफिकचे परीक्षण करू शकते"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"हे डिव्हाइस <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> च्या मालकीचे आहे आणि ती नेटवर्क ट्रॅफिकचे परीक्षण करू शकते"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"हे डिव्हाइस तुमच्या संस्थेचे आहे आणि ते <xliff:g id="VPN_APP">%1$s</xliff:g> ला कनेक्ट केले आहे"</string>
@@ -544,6 +548,8 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN अक्षम करा"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN डिस्कनेक्ट करा"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"धोरणे पहा"</string>
+ <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
+ <skip />
<string name="monitoring_description_named_management" msgid="505833016545056036">"हे डिव्हाइस <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> चे आहे.\n\nतुमचा आयटी ॲडमिन सेटिंग्ज, कॉर्पोरेट अॅक्सेस, ॲप्स, तुमच्या डिव्हाइसशी संबंधित डेटा आणि तुमच्या डिव्हाइसच्या स्थानाची माहिती यांचे परीक्षण व व्यवस्थापन करू शकतो.\n\nअधिक माहितीसाठी तुमच्या आयटी ॲडमिनशी संपर्क साधा."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"हे डिव्हाइस तुमच्या संस्थेचे आहे.\n\nतुमचा आयटी ॲडमिन सेटिंग्ज, कॉर्पोरेट अॅक्सेस, ॲप्स, तुमच्या डिव्हाइसशी संबंधित डेटा आणि तुमच्या डिव्हाइसच्या स्थानाची माहिती यांचे परीक्षण व व्यवस्थापन करू शकतो.\n\nअधिक माहितीसाठी तुमच्या आयटी ॲडमिनशी संपर्क साधा."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"आपल्या संस्थेने या डिव्हाइसवर प्रमाणपत्र अधिकार इंस्टॉल केला आहे. आपल्या सुरक्षित नेटवर्क रहदारीचे परीक्षण केले जाऊ शकते किंवा ती सुधारली जाऊ शकते."</string>
@@ -567,6 +573,8 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"आपल्या प्रशासकाने नेटवर्क लॉगिंग सुरू केले आहे, जे आपल्या डिव्हाइसवरील रहदारीचे निरीक्षण करते.\n\nअधिक माहितीसाठी आपल्या प्रशासकाशी संपर्क साधा."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"तुम्ही VPN कनेक्शन सेट करण्यासाठी अॅपला परवानगी दिली.\n\nहा अॅप ईमेल, अॅप्स आणि वेबसाइटसह, तुमच्या डिव्हाइस आणि नेटवर्क ॲक्टिव्हिटीचे परीक्षण करू शकतो."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"तुमचे कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले जाते.\n\nतुमचा प्रशासक ईमेल, अॅप्स आणि वेबसाइटसह आपल्या नेटवर्क ॲक्टिव्हिटीचे निरीक्षण करण्यास सक्षम आहे.\n\nअधिक माहितीसाठी आपल्या प्रशासकाशी संपर्क साधा.\n\nतुम्ही VPN शी देखील कनेक्ट आहात, जे आपल्या नेटवर्क ॲक्टिव्हिटीचे निरीक्षण करू शकते."</string>
+ <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
+ <skip />
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"तुम्ही <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्ट केले आहे, जे ईमेल, अॅप्स आणि वेबसाइटसह आपल्या नेटवर्क क्रियाकलापाचे परीक्षण करू शकते."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"तुम्ही <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्ट केले आहे, जो ईमेल, अॅप्स आणि वेबसाइटसह आपल्या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
@@ -1089,4 +1097,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नवीन डिव्हाइससोबत पेअर करा"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नंबर क्लिपबोर्डवर कॉपी केला."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 058055f..55f1e32 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Bateri dua bar."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Bateri tiga bar."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Bateri penuh."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Tiada telefon."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefon satu bar."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefon dua bar."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profil mungkin dipantau"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Rangkaian mungkin dipantau"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Rangkaian mungkin dipantau"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Peranti ini diurus oleh ibu bapa anda"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Organisasi anda memiliki peranti ini dan mungkin memantau trafik rangkaian"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> memiliki peranti ini dan mungkin memantau trafik rangkaian"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Peranti ini milik organisasi anda dan dihubungkan dengan <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Lumpuhkan VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Putuskan sambungan VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Lihat Dasar"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Lihat kawalan"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Peranti ini milik <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nPentadbir IT anda boleh memantau dan mengurus tetapan, akses korporat, apl, data yang dikaitkan dengan peranti anda dan maklumat lokasi peranti anda.\n\nUntuk maklumat lanjut, hubungi pentadbir IT anda."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Peranti ini milik organisasi anda.\n\nPentadbir IT anda boleh memantau dan mengurus tetapan, akses korporat, apl, data yang dikaitkan dengan peranti anda dan maklumat lokasi peranti anda.\n\nUntuk maklumat lanjut, hubungi pentadbir IT anda."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Organisasi anda memasang sijil kuasa pada peranti ini. Trafik rangkaian selamat anda mungkin dipantau atau diubah suai."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Pentadbir anda telah menghidupkan pengelogan rangkaian yang memantau trafik pada peranti anda.\n\nUntuk mendapatkan maklumat lanjut, hubungi pentadbir anda."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Anda memberikan kebenaran kepada apl untuk menyediakan sambungan VPN.\n\nApl ini boleh memantau aktiviti peranti dan rangkaian anda, termasuk e-mel, apl dan tapak web."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Profil kerja anda diurus oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nPentadbir anda boleh memantau aktiviti rangkaian, termasuk e-mel, apl dan tapak web.\n\nUntuk mendapatkan maklumat lanjut, hubungi pentadbir anda.\n\nAnda juga disambungkan ke VPN, yang boleh memantau aktiviti rangkaian."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Peranti ini diurus oleh ibu bapa anda. Ibu bapa anda dapat melihat dan mengurus maklumat seperti apl yang anda gunakan, lokasi dan masa skrin anda."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Anda dihubungkan ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang boleh memantau aktiviti rangkaian anda, termasuk e-mel, apl dan tapak web."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Anda disambungkan ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang boleh memantau aktiviti rangkaian peribadi anda, termasuk e-mel, apl dan tapak web."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Gandingkan peranti baharu"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nombor binaan"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nombor binaan disalin ke papan keratan."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 5249efa..18e804b 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"ဘတ္တရီနှစ်ဘား။"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"ဘတ္တရီသုံးဘား။"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"ဘတ္တရီအပြည့်။"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"ဖုန်းလိုင်းမရှိပါ။"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"ဖုန်းလိုင်းတစ်ဘား။"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"ဖုန်းလိုင်းနှစ်ဘား။"</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"ပရိုဖိုင်ကို စောင့်ကြပ်နိုင်သည်"</string>
<string name="vpn_footer" msgid="3457155078010607471">"ကွန်ရက်ကို ကို စောင့်ကြပ် နိုင်ပါသည်"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"ကွန်ရက်ကို စောင့်ကြည့်စစ်ဆေးမှု ရှိနိုင်ပါသည်"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ဤစက်ပစ္စည်းကို သင့်မိဘက စီမံခန့်ခွဲသည်"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"ဤစက်ကို သင့်အဖွဲ့အစည်းကပိုင်ဆိုင်ပြီး ကွန်ရက်ဒေတာ စီးဆင်းမှုကို စောင့်ကြည့်နိုင်ပါသည်"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"ဤစက်ကို <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> က ပိုင်ဆိုင်ပြီး ကွန်ရက်ဒေတာ စီးဆင်းမှုကို စောင့်ကြည့်နိုင်ပါသည်"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"ဤစက်ကို သင့်အဖွဲ့အစည်းကပိုင်ဆိုင်ပြီး <xliff:g id="VPN_APP">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားပါသည်"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN ကို ပိတ်ထားရန်"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN ကို အဆက်ဖြတ်ရန်"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"မူဝါဒများကို ကြည့်ရန်"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"ထိန်းချုပ်မှုများကို ကြည့်ရန်"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"ဤစက်ကို <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> က ပိုင်ဆိုင်ပါသည်။\n\nဆက်တင်များ၊ ကော်ပိုရိတ် သုံးခွင့်၊ အက်ပ်များ၊ သင့်စက်နှင့် ဆက်စပ်နေသော ဒေတာများနှင့် သင့်စက်တည်နေရာတို့ကို သင်၏ IT စီမံခန့်ခွဲသူက စောင့်ကြည့် စီမံနိုင်သည်။\n\nနောက်ထပ်အချက်အလက်များအတွက် သင်၏ IT စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"ဤစက်ကို သင့်အဖွဲ့အစည်းက ပိုင်ဆိုင်သည်။\n\nဆက်တင်များ၊ ကော်ပိုရိတ် သုံးခွင့်၊ အက်ပ်များ၊ သင့်စက်နှင့် ဆက်စပ်နေသော ဒေတာများနှင့် သင့်စက်တည်နေရာတို့ကို သင်၏ IT စီမံခန့်ခွဲသူက စောင့်ကြည့် စီမံနိုင်သည်။\n\nနောက်ထပ်အချက်အလက်များအတွက် သင်၏ IT စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"သင်၏ အဖွဲ့အစည်းက ဤစက်ပစ္စည်းတွင် စီမံခန့်ခွဲမှုဆိုင်ရာ အသိအမှတ်ပြုလက်မှတ်ကို ထည့်သွင်းထားပါသည်။ လုံခြုံမှုရှိသော ကွန်ရက်ဒေတာစီးဆင်းမှုကို စောင့်ကြည့်ခြင်း သို့မဟုတ် ပြုပြင်ခြင်းများ ပြုလုပ်နိုင်ပါသည်။"</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"သင့်စီမံခန့်ခွဲသူသည် စက်ပစ္စည်းပေါ်ရှိ ဒေတာအသွားအလာကို စောင့်ကြည့်နိုင်သည့် ကွန်ရက်အတွက် မှတ်တမ်းတင်ခြင်းကို ဖွင့်ထားပါသည်။\n\nနောက်ထပ် အချက်အလက်များအတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"VPN ချိတ်ဆက်မှုပြုလုပ်ရန် အက်ပ်ကို သင်ခွင့်ပြုလိုက်သည်။ \n\n ဤအက်ပ်သည် အီးမေးလ်များ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောင်ချက်များကို စောင့်ကြည့်နိုင်သည်။"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"သင့်အလုပ်ပရိုဖိုင်ကို <xliff:g id="ORGANIZATION">%1$s</xliff:g> က စီမံခန့်ခွဲထားပါသည်။\n\nသင့်စီမံခန့်ခွဲသူသည် အီးမေးလ်၊ အက်ပ်နှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်ပါသည်။\n\nနောက်ထပ် အချက်အလက်များအတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။\n\nသင်သည် သင့်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်သည့် VPN သို့လည်း ချိတ်ဆက်ထားပါသေးသည်။"</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ဤစက်ပစ္စည်းကို သင့်မိဘက စီမံခန့်ခွဲသည်။ သင့်မိဘက သင်သုံးသောအက်ပ်များ၊ သင်၏တည်နေရာနှင့် အသုံးပြုချိန် ကဲ့သို့သော အချက်အလက်များကို မြင်နိုင်ပြီး စီမံခန့်ခွဲနိုင်သည်။"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"သင်သည် အီးမေး၊ အက်ပ်နှင့် ဝဘ်ဆိုက်များအပါအဝင် သင်၏ကွန်ရက် လုပ်ဆောင်ချက်များကို စောင့်ကြည့်နိုင်သည့် <xliff:g id="APPLICATION">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားပါသည်။"</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"သင်သည် <xliff:g id="APPLICATION">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားသည်။ ၎င်းသည် အီးမေးလ်များ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်သည်။"</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"စက်အသစ် တွဲချိတ်ရန်"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"တည်ဆောက်မှုနံပါတ်"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"တည်ဆောက်မှုနံပါတ်ကို ကလစ်ဘုတ်သို့ မိတ္တူကူးပြီးပါပြီ။"</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index b676e91..8becc3b 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Batteri – to stolper."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Batteri – tre stolper."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batteriet er fullt."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Ingen telefon."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefon – én stolpe."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefon – to stolper."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profilen kan overvåkes"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Nettverket kan være overvåket"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Nettverket kan bli overvåket"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Denne enheten administreres av forelderen din"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Organisasjonen din eier denne enheten og kan overvåke nettverkstrafikken"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> eier denne enheten og kan overvåke nettverkstrafikken"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Denne enheten tilhører organisasjonen din og er koblet til <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Deaktiver VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Koble fra VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Se retningslinjer"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Visningskontroller"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Denne enheten tilhører <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nIT-administratoren din kan overvåke og administrere innstillinger, bedriftstilgang, apper, data som er tilknyttet denne enheten, og enhetens posisjonsinformasjon.\n\nKontakt IT-administratoren for å få mer informasjon."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Denne enheten tilhører organisasjonen din.\n\nIT-administratoren din kan overvåke og administrere innstillinger, bedriftstilgang, apper, data som er tilknyttet denne enheten, og enhetens posisjonsinformasjon.\n\nKontakt IT-administratoren for å få mer informasjon."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Organisasjonen din installerte en sertifiseringsinstans på denne enheten. Den sikre nettverkstrafikken din kan overvåkes eller endres."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Administratoren din har slått på loggføring av nettverk, som overvåker trafikken på enheten din.\n\nKontakt administratoren for mer informasjon."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Du ga en app tillatelse til å konfigurere en VPN-tilkobling.\n\nDenne appen kan overvåke enheten og nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Jobbprofilen din administreres av <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratoren din kan overvåke nettverksaktiviteten din, inkludert e-post, apper og nettsteder.\n\nKontakt administratoren for mer informasjon.\n\nDu er også tilkoblet en VPN som kan overvåke nettverksaktiviteten din."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Denne enheten administreres av forelderen din. Forelderen din kan se og administrere informasjon, for eksempel appene du bruker, posisjonen din og skjermtiden din."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Enheten er koblet til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåke nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Enheten er koblet til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåke den personlige nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Koble til en ny enhet"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Delversjonsnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Delversjonsnummeret er kopiert til utklippstavlen."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index c3c8903..eac89c2 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"ब्याट्रिका दुईवटा पट्टिहरू"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"ब्याट्रिका तिनवटा पट्टिहरू"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"ब्याट्री पूर्ण छ।"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"फोन छैन्।"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"फोन एउटा पट्टि।"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"फोन दुई पट्टि।"</string>
@@ -520,6 +522,8 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"प्रोफाइल अनुगमन हुन सक्छ"</string>
<string name="vpn_footer" msgid="3457155078010607471">"सञ्जाल अनुगमित हुन सक्छ"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"नेटवर्कको अनुगमन गरिने सम्भावना छ"</string>
+ <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
+ <skip />
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"यो यन्त्र तपाईंको सङ्गठनको स्वामित्वमा छ र उक्त सङ्गठनले यसको नेटवर्क ट्राफिक अनुगमन गर्न सक्छ"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"यो यन्त्र <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> को स्वामित्वमा छ र उक्त सङ्गठनले यसको नेटवर्क ट्राफिक अनुगमन गर्न सक्छ"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"यो यन्त्र तपाईंको सङ्गठनको स्वामित्वमा छ र <xliff:g id="VPN_APP">%1$s</xliff:g> मा कनेक्ट गरिएको छ"</string>
@@ -544,6 +548,8 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN असक्षम गर्नुहोस्"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"विच्छेद VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"नीतिहरू हेर्नुहोस्"</string>
+ <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
+ <skip />
<string name="monitoring_description_named_management" msgid="505833016545056036">"यो यन्त्र <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> को स्वामित्वमा छ।\n\nतपाईंका IT एड्मिन सेटिङ, संस्थागत पहुँच, एप, तपाईंको यन्त्रसँग सम्बन्धित डेटा र तपाईंको यन्त्रको स्थानसम्बन्धी जानकारीको निगरानी र व्यवस्थापन गर्न सक्नुहुन्छ।\n\nथप जानकारीका लागि आफ्ना IT एड्मिनसँग सम्पर्क गर्नुहोस्।"</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"यो यन्त्र तपाईंको सङ्गठनको स्वामित्वमा छ।\n\nतपाईंका IT एड्मिन सेटिङ, संस्थागत पहुँच, एप, तपाईंको यन्त्रसँग सम्बन्धित डेटा र तपाईंको यन्त्रको स्थानसम्बन्धी जानकारीको निगरानी र व्यवस्थापन गर्न सक्नुहुन्छ।\n\nथप जानकारीका लागि आफ्ना IT एड्मिनसँग सम्पर्क गर्नुहोस्।"</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"तपाईंको संगठनले तपाईंको कार्य प्रोफाइलमा एउटा प्रमाणपत्र सम्बन्धी अख्तियार सुविधा स्थापित गऱ्यो। तपाईंको सुरक्षित नेटवर्क ट्राफिकको अनुगमन वा परिमार्जन हुनसक्छ।"</string>
@@ -567,6 +573,8 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"तपाईँको प्रशासकले तपाईँको यन्त्रमा ट्राफिकको अनुगमन गर्ने नेटवर्कको लगिङलाई सक्रिय पार्नुभएको छ।\n\nथप जानकारीका लागि आफ्नो प्रशासकलाई सम्पर्क गर्नुहोस्।"</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"तपाईँले VPN जडान गर्न एपलाई अनुमति दिनुभयो।\n\nयो एपले तपाईँका यन्त्र र नेटवर्क गतिविधि लगायत इमेल, एप र वेबसाइटहरू अनुगमन गर्न सक्छ।"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"तपाईंको कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> ले व्यवस्थापन गर्दछ।\n\nतपाईंको प्रशासकले तपाईंको इमेल, एप र वेबसाइट सहित नेटवर्कमा तपाईंको गतिविधिको अनुगमन गर्न सक्नुहुन्छ। \n\nथप जानकारीका लागि आफ्नो प्रशासकलाई सम्पर्क गर्नुहोस्।\n\n तपाईं एउटा VPN मा जडित हुनुहुन्छ। यस VPN ले नेटवर्कमा तपाईंको गतिविधिको अनुगमन गर्न सक्छ।"</string>
+ <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
+ <skip />
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"तपाईं आफ्ना इमेल, एप र वेवसाइटहरू लगायत तपाईंको नेटवर्कको गतिविधिको अनुगमन गर्नसक्ने <xliff:g id="APPLICATION">%1$s</xliff:g> मा जडान हुनुहुन्छ।"</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"तपाईं <xliff:g id="APPLICATION">%1$s</xliff:g> सँग जडित हुनुहुन्छ जसले इ-मेल, एपहरू र वेबसाइट लगायतका तपाईंको निजी नेटवर्क गतिविधिका अनुगमन गर्न सक्छ।"</string>
@@ -1089,4 +1097,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नयाँ यन्त्रको जोडा बनाउनुहोस्"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नम्बर"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नम्बर कपी गरी क्लिपबोर्डमा सारियो।"</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 691bfcb..d1134d3 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Batterij: twee streepjes."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Batterij: drie streepjes."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batterij is vol."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Geen telefoonsignaal."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefoon: één streepje."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefoon: twee streepjes."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profiel kan worden gecontroleerd"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Netwerk kan worden gecontroleerd"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Netwerk kan worden gecontroleerd"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Dit apparaat wordt beheerd door je ouder"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Je organisatie is eigenaar van dit apparaat en kan het netwerkverkeer bijhouden"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> is eigenaar van dit apparaat en kan het netwerkverkeer bijhouden"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Dit apparaat is eigendom van je organisatie en is verbonden met <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN uitschakelen"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Verbinding met VPN verbreken"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Beleid bekijken"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Beheeropties bekijken"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Dit apparaat is eigendom van <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nJe IT-beheerder kan instellingen, zakelijke toegang, apps, aan je apparaat gekoppelde gegevens en de locatiegegevens van je apparaat bekijken en beheren.\n\nNeem contact op met je IT-beheerder voor meer informatie."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Dit apparaat is eigendom van je organisatie.\n\nJe IT-beheerder kan instellingen, zakelijke toegang, apps, aan je apparaat gekoppelde gegevens en de locatiegegevens van je apparaat bekijken en beheren.\n\nNeem contact op met je IT-beheerder voor meer informatie."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Je organisatie heeft een certificeringsinstantie geïnstalleerd op dit apparaat. Je beveiligde netwerkverkeer kan worden bijgehouden of aangepast."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Je beheerder heeft netwerkregistratie ingeschakeld, waarmee verkeer op je apparaat wordt bijgehouden.\n\nNeem contact op met je beheerder voor meer informatie."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Je hebt een app rechten gegeven voor het instellen van een VPN-verbinding.\n\nMet deze app kan je apparaat- en netwerkactiviteit worden gecontroleerd, inclusief e-mails, apps en websites."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Je werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJe beheerder kan je netwerkactiviteit controleren, inclusief e-mails, apps en websites.\n\nNeem contact op met je beheerder voor meer informatie.\n\nJe bent ook verbonden met een VPN, waarmee je netwerkactiviteit kan worden gecontroleerd."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Dit apparaat wordt beheerd door je ouder. Je ouder kan informatie bekijken en beheren, zoals de apps die je gebruikt, je locatie en je schermtijd."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Je bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee je netwerkactiviteit (waaronder e-mails, apps en websites) kan worden bijgehouden."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"U bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee je persoonlijke netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Nieuw apparaat koppelen"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build-nummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build-nummer naar klembord gekopieerd."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index de48527..264076f 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"ବ୍ୟାଟେରୀର ଦୁଇଟି ବାର୍ ଅଛି।"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"ବ୍ୟାଟେରୀର ତିନୋଟି ବାର୍ ଅଛି।"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"ବ୍ୟାଟେରୀ ପୂର୍ଣ୍ଣ।"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"କୌଣସି ଫୋନ୍ ନାହିଁ।"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"ଫୋନର ଗୋଟିଏ ବାର ଅଛି।"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"ଫୋନର ଦୁଇଟି ବାର୍ ଅଛି।"</string>
@@ -520,6 +522,8 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"ପ୍ରୋଫାଇଲ୍ ନିରୀକ୍ଷଣ କରାଯାଇପାରେ।"</string>
<string name="vpn_footer" msgid="3457155078010607471">"ନେଟ୍ୱର୍କ ନୀରିକ୍ଷଣ କରାଯାଇପାରେ"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"ନେଟ୍ୱର୍କକୁ ନିରୀକ୍ଷଣ କରାଯାଇପାରେ"</string>
+ <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
+ <skip />
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"ଏହି ଡିଭାଇସର ମାଲିକାନା ଆପଣଙ୍କ ସଂସ୍ଥା ପାଖରେ ଅଛି ଏବଂ ଏହା ନେଟୱାର୍କ ଟ୍ରାଫିକର ନିରୀକ୍ଷଣ କରିପାରେ"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"ଏହି ଡିଭାଇସଟି <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>ର ଅଟେ ଏବଂ ଏହା ନେଟୱାର୍କ ଟ୍ରାଫିକକୁ ନିରୀକ୍ଷଣ କରିପାରେ"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"ଏହି ଡିଭାଇସଟି ଆପଣଙ୍କ ସଂସ୍ଥାର ଅଟେ ଏବଂ ଏହା <xliff:g id="VPN_APP">%1$s</xliff:g> ସହ ସଂଯୁକ୍ତ ଅଛି"</string>
@@ -544,6 +548,8 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN ଅକ୍ଷମ କରନ୍ତୁ"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN ବିଛିନ୍ନ କରନ୍ତୁ"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"ପଲିସୀ ଦେଖନ୍ତୁ"</string>
+ <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
+ <skip />
<string name="monitoring_description_named_management" msgid="505833016545056036">"ଏହି ଡିଭାଇସଟି <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>ର ଅଟେ।\n\nଆପଣଙ୍କ IT ଆଡମିନ୍ ସେଟିଂସ୍, କର୍ପୋରେଟ୍ ଆକ୍ସେସ୍, ଆପ୍ସ, ଆପଣଙ୍କ ଡିଭାଇସ୍ ସହ ସମ୍ବନ୍ଧିତ ଡାଟା ଏବଂ ଆପଣଙ୍କ ଡିଭାଇସର ଲୋକେସନ୍ ସୂଚନାକୁ ନିରୀକ୍ଷଣ ଏବଂ ପରିଚାଳନା କରିପାରିବେ।\n\nଅଧିକ ସୂଚନା ପାଇଁ, ଆପଣଙ୍କ IT ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"ଏହି ଡିଭାଇସଟି ଆପଣଙ୍କ ସଂସ୍ଥାର ଅଟେ।\n\nଆପଣଙ୍କ IT ଆଡମିନ୍ ସେଟିଂସ୍, କର୍ପୋରେଟ୍ ଆକ୍ସେସ୍, ଆପ୍ସ, ଆପଣଙ୍କ ଡିଭାଇସ୍ ସହ ସମ୍ବନ୍ଧିତ ଡାଟା ଏବଂ ଆପଣଙ୍କ ଡିଭାଇସର ଲୋକେସନ୍ ସୂଚନାକୁ ନିରୀକ୍ଷଣ ଏବଂ ପରିଚାଳନା କରିପାରିବେ।\n\nଅଧିକ ସୂଚନା ପାଇଁ, ଆପଣଙ୍କ IT ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"ଏହି ଡିଭାଇସରେ ଆପଣଙ୍କ ସଂସ୍ଥା ଏକ ସର୍ଟିଫିକେଟ୍ ଅଥରିଟି ଇନଷ୍ଟଲ୍ କରିଛନ୍ତି। ଆପଣଙ୍କ ସୁରକ୍ଷିତ ନେଟୱର୍କ ଟ୍ରାଫିକ୍ ନୀରିକ୍ଷଣ କିମ୍ବା ସଂଶୋଧନ କରାଯାଇ ପାରେ।"</string>
@@ -567,6 +573,8 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"ଆପଣଙ୍କ ଆଡମିନ୍ ନେଟ୍ୱର୍କ ଲଗଇନ୍ କରିବା ଅନ୍ କରିଛନ୍ତି, ଯାହା ଆପଣଙ୍କ ଡିଭାଇସରେ ଟ୍ରାଫିକ୍ ନିରୀକ୍ଷଣ କରେ।\n\nଅଧିକ ସୂଚନା ପାଇଁ, ନିଜ ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"ଏକ VPN ସଂଯୋଗ ସେଟ୍ ଅପ୍ କରିବା ପାଇଁ ଆପଣ ଗୋଟିଏ ଆପକୁ ଅନୁମତି ଦେଲେ।\n\nଏହି ଆପ୍ ଇମେଲ୍, ଆପ୍ ଓ ୱେବସାଇଟ୍ ସମେତ ଆପଣଙ୍କ ଡିଭାଇସ୍ ଓ ନେଟ୍ୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"ଆପଣଙ୍କ ୱର୍କ ପ୍ରୋଫାଇଲ୍ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ଦ୍ୱାରା ପରିଚାଳନା କରାଯାଉଛି।\n\nଆପଣଙ୍କ ଆଡମିନ୍ ଇମେଲ୍, ଆପ୍ ଓ ୱେବସାଇଟ୍ ସମେତ ଆପଣଙ୍କ ନେଟୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରିବେ।\n\nଅଧିକ ସୂଚନା ପାଇଁ, ନିଜ ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।.\n\nଆପଣ ଏକ VPNରେ ମଧ୍ୟ ସଂଯୁକ୍ତ, ଯାହା ଆପଣଙ୍କ ନେଟୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
+ <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
+ <skip />
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"ଆପଣ <xliff:g id="APPLICATION">%1$s</xliff:g>ରେ ସଂଯୁକ୍ତ, ଯାହା ଇମେଲ୍, ଆପ୍ ଓ ୱେବସାଇଟ୍ ସମେତ ଆପଣଙ୍କ ନେଟୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"ଆପଣ <xliff:g id="APPLICATION">%1$s</xliff:g>ରେ ସଂଯୁକ୍ତ, ଯାହା ଇମେଲ୍, ଆପ୍ ଓ ୱେବସାଇଟ୍ ସମେତ ଆପଣଙ୍କ ନେଟ୍ୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
@@ -1089,4 +1097,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ନୂଆ ଡିଭାଇସକୁ ପେୟାର୍ କରନ୍ତୁ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ବିଲ୍ଡ ନମ୍ୱର"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"କ୍ଲିପବୋର୍ଡକୁ କପି କରାଯାଇଥିବା ବିଲ୍ଡ ନମ୍ୱର।"</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 13f4506..d05f80d 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"ਬੈਟਰੀ ਦੋ ਬਾਰਸ।"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"ਬੈਟਰੀ ਤਿੰਨ ਬਾਰਸ।"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"ਬੈਟਰੀ ਪੂਰੀ।"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"ਕੋਈ ਫ਼ੋਨ ਨਹੀਂ।"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"ਫ਼ੋਨ ਇੱਕ ਬਾਰ।"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"ਫ਼ੋਨ ਦੋ ਬਾਰਸ।"</string>
@@ -520,6 +522,8 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"ਪ੍ਰੋਫਾਈਲ ਦਾ ਨਿਰੀਖਣ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ"</string>
<string name="vpn_footer" msgid="3457155078010607471">"ਨੈੱਟਵਰਕ ਦਾ ਨਿਰੀਖਣ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"ਹੋ ਸਕਦਾ ਹੈ ਨੈੱਟਵਰਕ ਦੀ ਨਿਗਰਾਨੀ ਹੋ ਰਹੀ ਹੋਵੇ"</string>
+ <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
+ <skip />
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"ਤੁਹਾਡੀ ਸੰਸਥਾ ਕੋਲ ਇਸ ਡੀਵਾਈਸ ਦੀ ਮਲਕੀਅਤ ਹੈ ਅਤੇ ਇਹ ਨੈੱਟਵਰਕ ਟਰੈਫ਼ਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ਕੋਲ ਇਸ ਡੀਵਾਈਸ ਦੀ ਮਲਕੀਅਤ ਹੈ ਅਤੇ ਇਹ ਨੈੱਟਵਰਕ ਟਰੈਫ਼ਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"ਇਹ ਡੀਵਾਈਸ ਤੁਹਾਡੀ ਸੰਸਥਾ ਨਾਲ ਸੰਬੰਧਿਤ ਹੈ ਅਤੇ <xliff:g id="VPN_APP">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੈ"</string>
@@ -544,6 +548,8 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN ਨੂੰ ਅਸਮਰੱਥ ਬਣਾਓ"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN ਨੂੰ ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"ਨੀਤੀਆਂ ਦੇਖੋ"</string>
+ <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
+ <skip />
<string name="monitoring_description_named_management" msgid="505833016545056036">"ਇਹ ਡੀਵਾਈਸ <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ਨਾਲ ਸੰਬੰਧਿਤ ਹੈ।\n\nਤੁਹਾਡਾ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਨਾਲ ਸੰਬੰਧਿਤ ਸੈਟਿੰਗਾਂ, ਕਾਰਪੋਰੇਟ ਪਹੁੰਚ, ਐਪਾਂ, ਡਾਟੇ ਅਤੇ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀ ਟਿਕਾਣਾ ਜਾਣਕਾਰੀ ਦੀ ਨਿਗਰਾਨੀ ਅਤੇ ਪ੍ਰਬੰਧਨ ਕਰ ਸਕਦਾ ਹੈ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"ਇਹ ਡੀਵਾਈਸ ਤੁਹਾਡੀ ਸੰਸਥਾ ਨਾਲ ਸੰਬੰਧਿਤ ਹੈ।\n\nਤੁਹਾਡਾ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਨਾਲ ਸੰਬੰਧਿਤ ਸੈਟਿੰਗਾਂ, ਕਾਰਪੋਰੇਟ ਪਹੁੰਚ, ਐਪਾਂ, ਡਾਟੇ ਅਤੇ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀ ਟਿਕਾਣਾ ਜਾਣਕਾਰੀ ਦੀ ਨਿਗਰਾਨੀ ਅਤੇ ਪ੍ਰਬੰਧਨ ਕਰ ਸਕਦਾ ਹੈ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਇੱਕ ਪ੍ਰਮਾਣ-ਪੱਤਰ ਅਥਾਰਟੀ ਸਥਾਪਤ ਕੀਤੀ ਗਈ ਹੈ। ਤੁਹਾਡੇ ਸੁਰੱਖਿਅਤ ਨੈੱਟਵਰਕ ਟਰੈਫਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ ਜਾਂ ਉਸਨੂੰ ਸੋਧਿਆ ਜਾ ਸਕਦਾ ਹੈ।"</string>
@@ -567,6 +573,8 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਨੈੱਟਵਰਕ ਲੌਗਿੰਗ ਨੂੰ ਚਾਲੂ ਕੀਤਾ ਹੋਇਆ ਹੈ, ਜੋ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਟਰੈਫਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕਰਦਾ ਹੈ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"ਤੁਸੀਂ ਕਿਸੇ ਐਪ ਨੂੰ ਇੱਕ VPN ਕਨੈਕਸ਼ਨ ਸੈੱਟ ਅੱਪ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿੱਤੀ ਹੈ।\n\nਇਹ ਐਪ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਅਤੇ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ, ਈਮੇਲਾਂ, ਐਪਾਂ ਅਤੇ ਸੁਰੱਖਿਅਤ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ।"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"ਤੁਹਾਡੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਦਾ ਪ੍ਰਬੰਧਨ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ਵੱਲੋਂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।\n\nਤੁਹਾਡਾ ਪ੍ਰਸ਼ਾਸਕ ਈਮੇਲ, ਐਪਾਂ, ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰਨ ਦੇ ਸਮਰੱਥ ਹੈ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ।\n\nਤੁਸੀਂ ਇੱਕ VPN ਨਾਲ ਵੀ ਕਨੈਕਟ ਹੋਂ, ਜੋ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦਾ ਹੈ।"</string>
+ <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
+ <skip />
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"ਤੁਸੀਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲਾਂ, ਐਪਾਂ ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ।"</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"ਤੁਸੀਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈਬਸਫ਼ਿਆਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ।"</string>
@@ -1089,4 +1097,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ਨਵਾਂ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ਬਿਲਡ ਨੰਬਰ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ਬਿਲਡ ਨੰਬਰ ਨੂੰ ਕਲਿੱਪਬੋਰਡ \'ਤੇ ਕਾਪੀ ਕੀਤਾ ਗਿਆ।"</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 6da167d..7343b26 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Bateria: dwa paski."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Bateria: trzy paski."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Bateria naładowana."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Brak sygnału telefonu."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefon: jeden pasek."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefon: dwa paski."</string>
@@ -526,6 +528,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profil może być monitorowany"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Sieć może być monitorowana"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Sieć może być monitorowana"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Tym urządzeniem zarządza Twój rodzic"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Twoja organizacja jest właścicielem tego urządzenia i może monitorować ruch w sieci"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"Organizacja <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> jest właścicielem tego urządzenia i może monitorować ruch w sieci"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"To urządzenie należy do Twojej organizacji i jest połączone z siecią <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -550,6 +553,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Wyłącz VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Rozłącz z VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Zobacz zasady"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Wyświetl elementy sterujące"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"To urządzenie należy do organizacji <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nAdministrator IT może monitorować ustawienia, firmowe uprawnienia dostępu, aplikacje, dane dotyczące urządzenia i lokalizacji oraz nimi zarządzać.\n\nAby dowiedzieć się więcej, skontaktuj się z administratorem IT."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"To urządzenie należy do Twojej organizacji.\n\nAdministrator IT może monitorować ustawienia, firmowe uprawnienia dostępu, aplikacje, dane dotyczące urządzenia i lokalizacji oraz nimi zarządzać.\n\nAby dowiedzieć się więcej, skontaktuj się z administratorem IT."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Twoja organizacja zainstalowała urząd certyfikacji na tym urządzeniu. Zabezpieczony ruch w sieci może być monitorowany i zmieniany."</string>
@@ -573,6 +577,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Administrator włączył rejestrowanie sieciowe, które pozwala monitorować ruch na Twoim urządzeniu.\n\nAby dowiedzieć się więcej, skontaktuj się z administratorem."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Aplikacja otrzymała od Ciebie uprawnienia do konfigurowania połączenia VPN.\n\nMoże ona monitorować Twoją aktywność na urządzeniu i w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Twoim profilem do pracy zarządza <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrator może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe.\n\nAby dowiedzieć się więcej, skontaktuj się z administratorem.\n\nŁączysz się też z siecią VPN, która może monitorować Twoją aktywność w sieci."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Tym urządzeniem zarządza Twój rodzic. Rodzic może zobaczyć różne informacje, np. o aplikacjach, których używasz, lokalizacji i czasie korzystania z urządzenia, a także zarządzać tymi danymi."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Łączysz się z aplikacją <xliff:g id="APPLICATION">%1$s</xliff:g>, która może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Masz połączenie z aplikacją <xliff:g id="APPLICATION">%1$s</xliff:g>, która może monitorować Twoją prywatną aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
@@ -1101,4 +1106,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sparuj nowe urządzenie"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numer kompilacji"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numer kompilacji został skopiowany do schowka."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 0db05d8..344671d 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Duas barras de bateria."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Três barras de bateria."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Bateria cheia."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Sem telefone."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Uma barra de sinal do telefone."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Duas barras de sinal do telefone."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"O perfil pode ser monitorado"</string>
<string name="vpn_footer" msgid="3457155078010607471">"A rede pode ser monitorada"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"A rede pode ser monitorada"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Este dispositivo é gerenciado pelo seu pai/mãe"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Sua organização é dona deste dispositivo e pode monitorar o tráfego de rede"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"A organização <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> é dona deste dispositivo e pode monitorar o tráfego de rede"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Este dispositivo pertence à sua organização e está conectado a <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Desativar VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Desconectar VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Ver políticas"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Controles de visualização"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Este dispositivo pertence à organização <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nO administrador de TI pode monitorar e gerenciar configurações, acesso corporativo, apps, dados associados ao dispositivo e informações de local do dispositivo.\n\nPara saber mais, entre em contato com seu administrador de TI."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Este dispositivo pertence à sua organização.\n\nO administrador de TI pode monitorar e gerenciar configurações, acesso corporativo, apps, dados associados ao dispositivo e informações de local do dispositivo.\n\nPara saber mais, entre em contato com seu administrador de TI."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Sua organização instalou uma autoridade de certificação neste dispositivo. É possível monitorar ou modificar seu tráfego de rede seguro."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Seu administrador ativou o registro de rede, que monitora o tráfego no seu dispositivo.\n\nPara ver mais informações, entre em contato com o administrador."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Você deu permissão para um app configurar uma conexão VPN.\n\nEsse app pode monitorar seu dispositivo e a atividade na rede, incluindo e-mails, apps e websites."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSeu administrador pode monitorar sua atividade de rede, incluindo e-mails, apps e websites.\n\nPara ver mais informações, entre em contato com o administrador.\n\nVocê também está conectado a uma VPN, que pode monitorar sua atividade de rede."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Este dispositivo é gerenciado pelo seu pai/mãe, que pode ver e gerenciar informações como os apps que você usa, sua localização e seu tempo de uso."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade de rede, incluindo e-mails, apps e websites."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parear novo dispositivo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 147ed1d..709f532 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Duas barras de bateria."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Três barras de bateria."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Bateria carregada."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Sem telefone."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Uma barra de telefone."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Duas barras de telefone."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"O perfil pode ser monitorizado"</string>
<string name="vpn_footer" msgid="3457155078010607471">"A rede pode ser monitorizada"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"A rede pode ser monitorizada"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Este dispositivo é gerido pelos teus pais"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"A sua entidade gere este dispositivo e pode monitorizar o tráfego de rede."</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"A entidade <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> é proprietária deste dispositivo e pode monitorizar o tráfego de rede."</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Este dispositivo pertence à sua entidade e está ligado a <xliff:g id="VPN_APP">%1$s</xliff:g>."</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Desativar a VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Desligar VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Ver Políticas"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Ver controlos"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Este dispositivo pertence à entidade <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nO administrador de TI pode monitorizar e gerir as definições, o acesso empresarial, as apps, os dados associados ao dispositivo e as informações de localização do mesmo.\n\nContacte o administrador de TI para obter mais informações."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Este dispositivo pertence à sua entidade.\n\nO administrador de TI pode monitorizar e gerir as definições, o acesso empresarial, as apps, os dados associados ao dispositivo e as informações de localização do mesmo.\n\nContacte o administrador de TI para obter mais informações."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"A sua entidade instalou uma autoridade de certificação neste dispositivo. O tráfego da sua rede segura pode ser monitorizado ou alterado."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"O seu gestor ativou os registos de rede, que monitorizam o tráfego no seu dispositivo.\n\nPara obter mais informações, contacte o gestor."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Concedeu autorização a uma app para configurar uma ligação VPN.\n\nEsta app pode monitorizar a atividade do dispositivo e da rede, incluindo emails, aplicações e Sites."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"O seu perfil de trabalho é gerido por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nO seu gestor tem a capacidade de monitorizar a sua atividade da rede, incluindo emails, aplicações e Sites.\n\nPara obter mais informações, contacte o gestor.\n\nAlém disso, está ligado a uma VPN, que pode monitorizar a sua atividade da rede."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Este dispositivo é gerido pelos teus pais. Estes podem ver e gerir informações como as apps que utilizas, a tua localização e o tempo de utilização."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Está associado à app <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorizar a sua atividade de rede, incluindo emails, aplicações e Sites."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Está ligado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorizar a atividade da rede pessoal, incluindo emails, aplicações e Sites."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sincronize o novo dispositivo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da compilação"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número da compilação copiado para a área de transferência."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 0db05d8..344671d 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Duas barras de bateria."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Três barras de bateria."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Bateria cheia."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Sem telefone."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Uma barra de sinal do telefone."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Duas barras de sinal do telefone."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"O perfil pode ser monitorado"</string>
<string name="vpn_footer" msgid="3457155078010607471">"A rede pode ser monitorada"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"A rede pode ser monitorada"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Este dispositivo é gerenciado pelo seu pai/mãe"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Sua organização é dona deste dispositivo e pode monitorar o tráfego de rede"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"A organização <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> é dona deste dispositivo e pode monitorar o tráfego de rede"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Este dispositivo pertence à sua organização e está conectado a <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Desativar VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Desconectar VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Ver políticas"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Controles de visualização"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Este dispositivo pertence à organização <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nO administrador de TI pode monitorar e gerenciar configurações, acesso corporativo, apps, dados associados ao dispositivo e informações de local do dispositivo.\n\nPara saber mais, entre em contato com seu administrador de TI."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Este dispositivo pertence à sua organização.\n\nO administrador de TI pode monitorar e gerenciar configurações, acesso corporativo, apps, dados associados ao dispositivo e informações de local do dispositivo.\n\nPara saber mais, entre em contato com seu administrador de TI."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Sua organização instalou uma autoridade de certificação neste dispositivo. É possível monitorar ou modificar seu tráfego de rede seguro."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Seu administrador ativou o registro de rede, que monitora o tráfego no seu dispositivo.\n\nPara ver mais informações, entre em contato com o administrador."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Você deu permissão para um app configurar uma conexão VPN.\n\nEsse app pode monitorar seu dispositivo e a atividade na rede, incluindo e-mails, apps e websites."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSeu administrador pode monitorar sua atividade de rede, incluindo e-mails, apps e websites.\n\nPara ver mais informações, entre em contato com o administrador.\n\nVocê também está conectado a uma VPN, que pode monitorar sua atividade de rede."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Este dispositivo é gerenciado pelo seu pai/mãe, que pode ver e gerenciar informações como os apps que você usa, sua localização e seu tempo de uso."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade de rede, incluindo e-mails, apps e websites."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parear novo dispositivo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 24e71fb..6c54460 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Baterie: două bare."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Baterie: trei bare."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Baterie: complet."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Nu există semnal pentru telefon."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Semnal pentru telefon: o bară."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Semnal pentru telefon: două bare."</string>
@@ -523,6 +525,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profilul poate fi monitorizat"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Rețeaua poate fi monitorizată"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Este posibil ca rețeaua să fie monitorizată"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Dispozitivul este gestionat de unul dintre părinți"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Organizația dvs. deține acest dispozitiv și poate monitoriza traficul de rețea"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> deține acest dispozitiv și poate monitoriza traficul din rețea"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Dispozitivul aparține organizației dvs. și este conectat la <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -547,6 +550,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Dezactivați conexiunea prin VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Deconectați rețeaua VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Afișați politicile"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Vedeți opțiunile"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Dispozitivul aparține organizației <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nAdministratorul dvs. IT poate să monitorizeze și să gestioneze setările, accesul la nivelul companiei, aplicațiile, datele asociate dispozitivului și informațiile despre locația dispozitivului.\n\nPentru mai multe informații, contactați administratorul IT."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Dispozitivul aparține organizației dvs.\n\nAdministratorul dvs. IT poate să monitorizeze și să gestioneze setările, accesul la nivelul companiei, aplicațiile, datele asociate dispozitivului și informațiile despre locația dispozitivului.\n\nPentru mai multe informații, contactați administratorul IT."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Organizația dvs. a instalat un certificat CA pe acest dispozitiv. Traficul dvs. sigur de rețea poate fi monitorizat sau modificat."</string>
@@ -570,6 +574,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Administratorul dvs. a activat înregistrarea în jurnal pentru rețea, funcție ce monitorizează traficul de pe dispozitivul dvs.\n\nPentru mai multe informații, contactați administratorul."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Ați acordat unei aplicații permisiunea de a configura o conexiune VPN.\n\nAceastă aplicație poate monitoriza activitatea de pe dispozitiv și în rețea, inclusiv e-mailurile, aplicațiile și site-urile."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Profilul dvs. de serviciu este gestionat de <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratorul dvs. vă poate monitoriza activitatea în rețea, inclusiv e-mailurile, aplicațiile și site-urile.\n\nPentru mai multe informații, contactați administratorul.\n\nDe asemenea, sunteți conectat(ă) la o rețea VPN care vă poate monitoriza activitatea în rețea."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Dispozitivul este gestionat de unul dintre părinți. Părintele poate să vadă și să gestioneze informații cum ar fi aplicațiile pe care le folosești, locația ta și durata de folosire a dispozitivului."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"V-ați conectat la <xliff:g id="APPLICATION">%1$s</xliff:g>, care vă poate monitoriza activitatea în rețea, inclusiv e-mailurile, aplicațiile și site-urile accesate."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Sunteți conectat(ă) la <xliff:g id="APPLICATION">%1$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua personală, inclusiv e-mailurile, aplicațiile și site-urile."</string>
@@ -1095,4 +1100,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Asociați un nou dispozitiv"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numărul versiunii"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numărul versiunii s-a copiat în clipboard."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 1ca1c80..53773cf 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Заряд батареи: два деления."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Заряд батареи: три деления."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Батарея полностью заряжена."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Сигнал телефонной сети отсутствует."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Сигнал телефонной сети: одно деление."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Сигнал телефонной сети: два деления."</string>
@@ -526,6 +528,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Действия в профиле могут отслеживаться"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Сеть может отслеживаться"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Сеть может отслеживаться"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Этим устройством управляет один из твоих родителей."</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Ваша организация управляет этим устройством и может отслеживать сетевой трафик"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"Организация \"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>\" управляет этим устройством и может отслеживать сетевой трафик"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Это устройство принадлежит вашей организации и подключено к приложению \"<xliff:g id="VPN_APP">%1$s</xliff:g>\""</string>
@@ -550,6 +553,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Отключить VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Отключить VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Просмотреть политику"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Показать элементы управления"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Это устройство принадлежит организации \"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>\".\n\nВаш системный администратор может управлять настройками, приложениями и параметрами доступа к корпоративным ресурсам на этом устройстве, а также связанными с ним данными (например, сведениями о местоположении).\n\nЗа подробной информацией обращайтесь к системному администратору."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Это устройство принадлежит вашей организации.\n\nСистемный администратор может управлять настройками, приложениями и параметрами доступа к корпоративным ресурсам на этом устройстве, а также связанными с ним данными (например, сведениями о местоположении).\n\nЗа подробной информацией обращайтесь к системному администратору."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Ваша организация установила сертификат ЦС на устройство. Она может отслеживать и изменять защищенный сетевой трафик."</string>
@@ -573,6 +577,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Администратор включил ведение сетевого журнала, чтобы отслеживать трафик на вашем устройстве.\n\nДля получения подробной информации обращайтесь к администратору."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Вы разрешили приложению подключаться к сети VPN.\n\nОно может отслеживать ваши действия на устройстве и в Интернете, включая работу с электронной почтой, приложениями и веб-сайтами."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Вашим рабочим профилем управляет <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nАдминистратор может отслеживать ваши действия в сети, в том числе работу с электронной почтой, приложениями и веб-сайтами.\n\nДля получения подробной информации обращайтесь к администратору.\n\nВы также подключены к сети VPN, в которой можно отслеживать ваши действия."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Этим устройством управляет один из твоих родителей. Он может видеть определенные сведения (например, какие приложения ты используешь и где находишься), а также устанавливать определенные настройки (например, ограничивать время использования устройства)."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"Сеть VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Запущено приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\", которое может отслеживать ваши действия в сети, включая работу с электронной почтой, приложениями и веб-сайтами."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Запущено приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\", которое может отслеживать ваши действия в Интернете (выполняемые в личном профиле), включая работу с электронной почтой, приложениями и веб-сайтами."</string>
@@ -1101,4 +1106,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Подключить новое устройство"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер сборки"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Номер сборки скопирован в буфер обмена."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index eb789c1..afd556a 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"බැටරිය තීරු දෙකයි."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"බැටරිය තීරු තුනයි."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"බැටරිය පිරී ඇත."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"දුරකථනයක් නැත."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"දුරකථනය තීරු එකයි."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"දුරකථනය තීරු දෙකයි."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"ඇතැම් විට පැතිකඩ නිරීක්ෂණය කරන ලදි"</string>
<string name="vpn_footer" msgid="3457155078010607471">"ඇතැම් විට ජාලය නිරීක්ෂණය විය හැක"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"ඇතැම් විට ජාලය නිරීක්ෂණය විය හැක"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"මෙම උපාංගය ඔබගේ මාපියන්ගෙන් අයකු විසින් කළමනාකරණය කෙරේ"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"ඔබේ සංවිධානයට මෙම උපාංගය අයිති අතර ජාල තදබදය නිරීක්ෂණය කළ හැකිය"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> සංවිධානයට මෙම උපාංගය අයිති අතර ජාල තදබදය නිරීක්ෂණය කළ හැකිය"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"මෙම උපාංගය ඔබේ සංවිධානයට අයිති අතර <xliff:g id="VPN_APP">%1$s</xliff:g> වෙත සම්බන්ධ කර ඇත"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN අබල කරන්න."</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN විසන්ධි කරන්න"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"ප්රතිපත්ති පෙන්වන්න"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"පාලන බලන්න"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"මෙම උපාංගය <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> සංවිධානයට අයිතිය.\n\nඔබේ IT පරිපාලකට ඔබේ උපාංගය හා සම්බන්ධිත සැකසීම්, ආයතනික ප්රවේශය, යෙදුම්, දත්ත සහ ඔබේ උපාංගයේ ස්ථාන තොරතුරු නිරීක්ෂණය කර කළමනාකරණය කිරීමට හැකිය.\n\nවැඩිදුර තොරතුරු සඳහා, ඔබේ IT අමතන්න."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"මෙම උපාංගය ඔබේ සංවිධානයට අයිතිය.\n\nඔබේ IT පරිපාලකට ඔබේ උපාංගය හා සම්බන්ධිත සැකසීම්, ආයතනික ප්රවේශය, යෙදුම්, දත්ත සහ ඔබේ උපාංගයේ ස්ථාන තොරතුරු නිරීක්ෂණය කර කළමනාකරණය කිරීමට හැකිය.\n\nවැඩිදුර තොරතුරු සඳහා, ඔබේ IT අමතන්න."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"ඔබගේ සංවිධානය ඔබගේ උපාංගය තුළ සහතික අධිකාරියක් ස්ථාපනය කර තිබේ. ඔබගේ ආරක්ෂක ජාල තදබදය නිරීක්ෂණය හෝ වෙනස් කිරීමට පුළුවනි."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"ඔබගේ පරිපාලක ඔබගේ උපාංගය මත තදබදය නිරීක්ෂණය කරන, ජාල ඇතුළු වීම ක්රියාත්මක කර ඇත.\n\nවැඩිදුර තොරතුරු සඳහා ඔබේ පරිපාලක අමතන්න."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"ඔබ VPN සම්බන්ධතාවක් පිහිටුවීමට යෙදුමකට අවසරයක් දී ඇත.\n\nමෙම යෙදුමට ඔබේ ඊ-තැපැල්, යෙදුම්, සහ වෙබ් අඩවි ඇතුළු, ඔබගේ උපාංග සහ ජාල ක්රියාකාරකම් නිරීක්ෂණය කිරීමට හැකිය."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"ඔබේ කාර්ය පැතිකඩ කළමනාකරණය කරන්නේ <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nඔබේ පරිපාලකට ඔබේ ඊ-තැපැල්, යෙදුම්, සහ වෙබ් අඩවි ඇතුළු, ඔබේ ජාල ක්රියාකාරකම් නිරීක්ෂණය කළ හැකිය.\n\nවැඩිදුර තොරතුරු සඳහා, ඔබගේ පරිපාලක අමතන්න.\n\nඔබේ ජාල ක්රියාකාරකම් නිරීක්ෂණය කළ හැකි, VPN එකකටද ඔබ සබැඳී ඇත"</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"මෙම උපාංගය ඔබගේ මාපියන් විසින් කළමනාකරණය කෙරේ. ඔබ භාවිත කරන යෙදුම්, ඔබගේ ස්ථානය සහ ඔබගේ තිර කාලය වැනි තොරතුරු ඔබගේ මාපියන්ට බැලීමට සහ කළමනාකරණය කිරීමට හැකිය."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ ජාල ක්රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION">%1$s</xliff:g> වෙත ඔබ සම්බන්ධ වී ඇත."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ පෞද්ගලික ජාල ක්රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION">%1$s</xliff:g> වෙත ඔබ සම්බන්ධ වී ඇත."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"නව උපාංගය යුගල කරන්න"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"නිමැවුම් අංකය"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"නිමැවුම් අංකය පසුරු පුවරුවට පිටපත් කරන ලදි."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 9ec0771..4c518dc 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Dve čiarky batérie."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Tri čiarky batérie."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batéria je nabitá."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Žiadna telefónna sieť."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Jeden stĺpec signálu telefónnej siete."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Dve čiarky signálu telefónnej siete."</string>
@@ -526,6 +528,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profil môže byť monitorovaný"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Sieť môže byť sledovaná"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Sieť môže byť monitorovaná"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Toto zariadenie spravuje tvoj rodič"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Vaša organizácia spravuje toto zariadenie a môže sledovať sieťovú premávku"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> vlastní toto zariadenie a môže sledovať sieťovú premávku"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Toto zariadenie patrí vašej organizácii a je pripojené k sieti <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -550,6 +553,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Deaktivovať VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Odpojiť sieť VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Zobraziť pravidlá"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Zobraziť ovládacie prvky"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Toto zariadenie patrí organizácii <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nVáš správca IT môže sledovať a spravovať nastavenia, podnikový prístup, aplikácie, údaje spojené s vaším zariadení a informácie o jeho polohe.\n\nViac sa dozviete od správcu IT."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Toto zariadenie patrí vašej organizácii.\n\nVáš správca IT môže sledovať a spravovať nastavenia, podnikový prístup, aplikácie, údaje spojené s vaším zariadením a informácie o jeho polohe.\n\n. Viac sa dozviete od správcu IT."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Organizácia nainštalovala pre toto zariadenie certifikačnú autoritu. Zabezpečená sieťová premávka môže byť sledovaná či upravená."</string>
@@ -573,6 +577,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Správca aktivoval zapisovanie do denníka siete, ktoré sleduje premávku na vašom zariadení.\n\nĎalšie informácie vám poskytne správca."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Určitej aplikácii ste udelili povolenie nastaviť pripojenie VPN.\n\nTáto aplikácia môže sledovať vaše zariadenie a aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Váš pracovný profil spravuje organizácia <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSprávca môže sledovať vašu aktivitu v sieti vrátane e-mailov, aplikácií a webov.\n\nĎalšie informácie vám poskytne správca.\n\nMáte tiež aktívne pripojenie k sieti VPN, ktorá môže sledovať vašu aktivitu v rámci siete."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Toto zariadenie spravuje tvoj rodič. Vidí a môže spravovať informácie, napríklad aplikácie, ktoré používaš, tvoju polohu a čas používania."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Pripojili ste sa k aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g>, ktorá môže sledovať vašu aktivitu v sieti vrátane správ, aplikácií a webových stránok."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Ste pripojený/-á k aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g>, ktorá môže sledovať vašu osobnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
@@ -1101,4 +1106,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Spárovať nové zariadenie"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Číslo zostavy"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Číslo zostavy bolo skopírované do schránky."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 14f6553..f459bc8 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Baterija z dvema črticama."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Baterija s tremi črticami."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Baterija je polna."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Ni telefona."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefon z eno črtico."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefon z dvema črticama."</string>
@@ -526,6 +528,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profil je morda nadziran"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Omrežje je lahko nadzorovano"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Omrežje je morda nadzorovano"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"To napravo upravlja tvoj starš"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Vaša organizacija je lastnica te naprave in lahko nadzira omrežni promet"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"Organizacija <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> je lastnica te naprave in lahko nadzira omrežni promet"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Ta naprava pripada vaši organizaciji in je povezana v aplikacijo <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -550,6 +553,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Onemogoči VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Prekini povezavo z VPN-jem"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Prikaži pravilnike"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Ogled kontrolnikov"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Ta naprava pripada organizaciji <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nSkrbnik za IT lahko nadzira in upravlja nastavitve, dostop za podjetje, aplikacije, z napravo povezane podatke in podatke o lokaciji naprave.\n\nZa več informacij se obrnite na skrbnika za IT."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Ta naprava pripada vaši organizaciji.\n\nSkrbnik za IT lahko nadzira in upravlja nastavitve, dostop za podjetje, aplikacije, z napravo povezane podatke in podatke o lokaciji naprave.\n\nZa več informacij se obrnite na skrbnika za IT."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Vaša organizacija je v to napravo namestila overitelja potrdil. Varni omrežni promet se lahko nadzira ali spreminja."</string>
@@ -573,6 +577,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Skrbnik je vklopil beleženje omrežnega prometa, ki nadzoruje promet v napravi.\n\nČe želite več informacij, se obrnite na skrbnika."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Aplikaciji ste dovolili vzpostavitev povezave VPN.\n\nTa aplikacija lahko nadzira napravo in omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Delovni profil upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSkrbnik lahko nadzira vašo omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti.\n\nČe želite več informacij, se obrnite na skrbnika.\n\nPovezani ste tudi z omrežjem VPN, ki lahko nadzira vašo omrežno dejavnost."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"To napravo upravlja tvoj starš. Tvoj starš si lahko ogleda in upravlja podatke, na primer katere aplikacije uporabljaš, tvojo lokacijo in koliko časa uporabljaš telefon."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Povezani ste z aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>, ki lahko nadzira omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Povezani ste z aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>, ki lahko nadzira vašo osebno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
@@ -1101,4 +1106,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Seznanitev nove naprave"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Delovna različica"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Delovna različica je bila kopirana v odložišče."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 87ca508..73408ce 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Bateria ka edhe dy vija."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Bateria ka edhe tre vija."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Bateria u mbush."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Nuk ka telefon."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefoni ka edhe një vijë."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefoni ka dy vija."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profili mund të monitorohet"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Rrjeti mund të jetë i monitoruar"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Rrjeti mund të jetë i monitoruar"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Kjo pajisje menaxhohet nga prindi yt."</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Organizata jote e zotëron këtë pajisje dhe mund të monitorojë trafikun e rrjetit"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> e zotëron këtë pajisje dhe mund të monitorojë trafikun e rrjetit"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Kjo pajisje i përket organizatës sate dhe është e lidhur me <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Çaktivizo VPN-në"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Shkëput VPN-në"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Shiko politikat"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Shiko kontrollet"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Kjo pajisje i përket <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nAdministratori i teknologjisë së informacionit mund të monitorojë dhe menaxhojë cilësimet, qasjen e korporatës, aplikacionet, të dhënat e lidhura me pajisjen tënde, si dhe informacionet e vendndodhjes së pajisjes tënde.\n\nPër më shumë informacione, kontakto me administratorin e teknologjisë së informacionit."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Kjo pajisje i përket organizatës sate.\n\nAdministratori i teknologjisë së informacionit mund të monitorojë dhe menaxhojë cilësimet, qasjen e korporatës, aplikacionet, të dhënat e lidhura me pajisjen tënde, si dhe informacionet e vendndodhjes së pajisjes tënde.\n\nPër më shumë informacione, kontakto me administratorin e teknologjisë së informacionit."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Organizata jote instaloi një autoritet certifikate në këtë pajisje. Trafiku i rrjetit tënd të sigurt mund të monitorohet ose modifikohet."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Administratori yt ka aktivizuar regjistrimin e rrjetit, i cili monitoron trafikun në pajisjen tënde.\n\nPër më shumë informacione, kontakto me administratorin."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"I dhe leje një aplikacioni që të konfigurojë një lidhje VPN.\n\nKy aplikacion mund të monitorojë pajisjen tënde dhe aktivitetin e rrjetit, përfshirë email-et, aplikacionet dhe sajtet e uebit."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Profili yt i punës menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratori yt mund të monitorojë aktivitetin tënd të rrjetit, duke përfshirë email-et, aplikacionet dhe sajtet e uebit.\n\nPër më shumë informacion, kontakto me administratorin tënd.\n\nJe i lidhur edhe me një VPN, që mund të monitorojë aktivitetin tënd të rrjetit."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Kjo pajisje menaxhohet nga prindi yt. Prindi yt mund të shohë e menaxhojë informacionin, si p.sh. aplikacionet që përdor, vendndodhjen tënde dhe kohën para ekranit."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g> i cili mund të monitorojë aktivitetin tënd në rrjet, duke përfshirë mail-et, aplikacionet dhe sajtet e uebit."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet, përfshirë email-et, aplikacionet dhe sajtet e uebit."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Çifto pajisjen e re"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numri i ndërtimit"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numri i ndërtimit u kopjua te kujtesa e fragmenteve"</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 1ad7a91..d173f00 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Батерија од две црте."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Батерија од три црте."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Батерија је пуна."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Нема телефона."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Сигнал телефона има једну црту."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Сигнал телефона од две црте."</string>
@@ -523,6 +525,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Профил се можда надгледа"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Мрежа се можда надгледа"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Мрежа се можда надгледа"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Овим уређајем управља родитељ"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Организација је власник уређаја и може да надгледа мрежни саобраћај"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> је власник овог уређаја и може да надгледа мрежни саобраћај"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Овај уређај припада организацији и повезан је са апликацијом <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -547,6 +550,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Онемогући VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Прекини везу са VPN-ом"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Прикажи смернице"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Прикажи контроле"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Овај уређај припада организацији <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nИТ администратор може да надгледа подешавања, корпоративни приступ, апликације, податке повезане са уређајем и информације о локацији уређаја, као и да управља њима.\n\nВише информација потражите од ИТ администратора."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Овај уређај припада организацији.\n\nИТ администратор може да надгледа подешавања, корпоративни приступ, апликације, податке повезане са уређајем и информације о локацији уређаја, као и да управља њима.\n\nВише информација потражите од ИТ администратора."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Организација је на овом уређају инсталирала ауторитет за издавање сертификата. Безбедни мрежни саобраћај може да се прати или мења."</string>
@@ -570,6 +574,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Администратор је укључио евидентирање мреже, које прати саобраћај на уређају.\n\nКонтактирајте администратора за више информација."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Дали сте дозволу апликацији да подешава VPN везу.\n\nТа апликација може да надгледа активности на уређају и мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> управља пословним профилом.\n\nАдминистратор може да прати активности на мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nКонтактирајте администратора за више информација.\n\nПовезани сте и са VPN-ом, који може да прати активности на мрежи."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Овим уређајем управља родитељ. Родитељ може да види информације, као што су апликације које користиш, твоју локацију и време испред екрана, и да управља њима."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Повезани сте са апликацијом <xliff:g id="APPLICATION">%1$s</xliff:g>, која може да надгледа активности на мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Повезани сте са апликацијом <xliff:g id="APPLICATION">%1$s</xliff:g>, која може да надгледа активности на личној мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
@@ -1095,4 +1100,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Упари нови уређај"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Број верзије"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Број верзије је копиран у привремену меморију."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index d34c814..b79fb40 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Batteri: två staplar."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Batteri: tre staplar."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batteriet är fulladdat."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Ingen telefon."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefon: en stapel."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefon: två staplar."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Det kan hända att profilen övervakas"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Nätverket kan vara övervakat"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Nätverket kan vara övervakat"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Den här enheten hanteras av din förälder"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Organisationen äger den här enheten och kan övervaka nätverkstrafiken"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> äger den här enheten och kan övervaka nätverkstrafiken"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Den här enheten tillhör organisationen och är ansluten till <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Inaktivera VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Koppla från VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Visa policyer"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Visa kontroller"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Den här enheten tillhör <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nIT-administratören kan övervaka och hantera inställningar, företagsåtkomst, appar, data med koppling till enheten och enhetens plats.\n\nKontakta IT-administratören om du vill veta mer."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Den här enheten tillhör organisationen.\n\nIT-administratören kan övervaka och hantera inställningar, företagsåtkomst, appar, data med koppling till enheten och enhetens plats.\n\nKontakta IT-administratören om du vill veta mer."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Organisationen har installerat en certifikatutfärdare på enheten. Din säkra nätverkstrafik kan övervakas och ändras."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Administratören har aktiverat nätverksloggning som övervakar trafik på enheten.\n\nKontakta administratören om du vill veta mer."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Du har gett en app behörighet att upprätta en VPN-anslutning.\n\nAppen kan bevaka aktivitet på enheten och nätverket, inklusive e-post, appar och webbplatser."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Jobbprofilen hanteras av <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratören kan övervaka nätverksaktivitet, till exempel e-postmeddelanden, appar och webbplatser.\n\nKontakta administratören om du vill veta mer.\n\nDu är även ansluten till ett VPN som kan övervaka nätverksaktivitet."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Den här enheten hanteras av din förälder. Föräldern kan se och hantera information som vilka appar du använder, din plats och din skärmtid."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Du är ansluten till <xliff:g id="APPLICATION">%1$s</xliff:g> som kan bevaka din nätverksaktivitet, exempelvis e-post, appar och webbplatser."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Du är ansluten till <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan bevaka din privata aktivitet på nätverket, inklusive e-post, appar och webbplatser."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parkoppla en ny enhet"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versionsnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versionsnumret har kopierats till urklipp."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index eab7f69..2e4c91d 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Pau mbili za betri"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Pau tatu za betri."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Betri imejaa."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Hakuna simu"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Mwambaa mmoja wa simu."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Miambaa miwili ya simu"</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Huenda wasifu ukafuatiliwa"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Huenda mtandao unafuatiliwa"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Huenda mtandao unafuatiliwa"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Kifaa hiki kinadhibitiwa na mzazi wako"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Shirika lako linamiliki kifaa hiki na huenda likafuatilia trafiki ya mtandao"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> inamiliki kifaa hiki na huenda ikafuatilia trafiki ya mtandao"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Kifaa hiki kinamilikiwa na shirika lako na kimeunganishwa kwenye <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Zima VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Ondoa VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Angalia Sera"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Angalia vidhibiti"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Kifaa hiki kinamilikiwa na <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nMsimamizi wako wa TEHAMA anaweza kufuatilia na kudhibiti mipangilio, ufikiaji wa maudhui ya shirika, programu, data inayohusiana na kifaa chako na maelezo kuhusu mahali kifaa chako kilipo.\n\nKwa maelezo zaidi, wasiliana na msimamizi wako wa TEHAMA."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Kifaa hiki kinamilikiwa na shirika lako.\n\nMsimamizi wako wa TEHAMA anaweza kufuatilia na kudhibiti mipangilio, ufikiaji wa maudhui ya shirika, programu, data inayohusiana na kifaa chako na maelezo kuhusu mahali kifaa chako kilipo.\n\nKwa maelezo zaidi, wasiliana na msimamizi wako wa TEHAMA."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Shirika lako limesakinisha mamlaka ya cheti kwenye kifaa hiki. Huenda shughuli kwenye mtandao wako salama zikafuatiliwa au kubadilishwa."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Msimamizi wako amewasha kumbukumbu ya kuingia mtandaoni ambayo hufuatilia shughuli kwenye kifaa chako.\n\nKwa maelezo zaidi, wasiliana na msimamizi wako."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Uliruhusu programu iweke muunganisho wa VPN.\n\nProgramu hii inaweza kufuatilia shughuli za kifaa na mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Wasifu wako wa kazini unadhibitiwa na <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nMsimamizi wako anaweza kufuatilia shughuli za mtandaoni, ikiwa ni pamoja na barua pepe, programu na tovuti.\n\nKwa maelezo zaidi, wasiliana na msimamizi wako.\n\nUmeunganishwa pia kwenye VPN, ambayo inaweza kufuatilia shughuli zako mtandaoni."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Kifaa hiki kinadhibitiwa na mzazi wako. Mzazi wako anaweza kuona na kudhibiti maelezo kama vile programu unazotumia, mahali ulipo na muda unaotumia kifaa."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Umeunganishwa kwenye <xliff:g id="APPLICATION">%1$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Umeunganishwa kwenye <xliff:g id="APPLICATION">%1$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Oanisha kifaa kipya"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nambari ya muundo"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nambari ya muundo imewekwa kwenye ubao wa kunakili."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index a72ebef..97240d9 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"பேட்டரி சக்தி இரண்டு பார் அளவில் உள்ளது."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"பேட்டரி சக்தி மூன்று பார் அளவில் உள்ளது."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"பேட்டரி முழுமையாக உள்ளது."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"சிக்னல் இல்லை."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"சிக்னல் ஒரு கோட்டில் உள்ளது."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"சிக்னல் இரண்டு கோட்டில் உள்ளது."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"சுயவிவரம் கண்காணிக்கப்படலாம்"</string>
<string name="vpn_footer" msgid="3457155078010607471">"நெட்வொர்க் கண்காணிக்கப்படலாம்"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"நெட்வொர்க் கண்காணிக்கப்படலாம்"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"இந்தச் சாதனம் உங்கள் பெற்றோரால் நிர்வகிக்கப்படுகிறது"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"இந்த சாதனம் உங்கள் நிறுவனத்துக்கு உரியது, நெட்வொர்க் ட்ராஃபிக்கையும் நிறுவனமே கண்காணிக்கக்கூடும்"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"இந்த சாதனம் <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> நிறுவனத்துக்கு உரியது, நெட்வொர்க் ட்ராஃபிக்கையும் நிறுவனமே கண்காணிக்கக்கூடும்"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"இந்த சாதனம் உங்கள் நிறுவனத்துக்கு சொந்தமானது, அது <xliff:g id="VPN_APP">%1$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளது"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPNஐ முடக்கு"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPNஐத் துண்டி"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"கொள்கைகளைக் காட்டு"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"கட்டுப்பாடுகளைக் காட்டு"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"இந்த சாதனம் <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> நிறுவனத்துக்கு சொந்தமானது.\n\nஉங்கள் IT நிர்வாகியால் அமைப்புகள், நிறுவன அணுகல், ஆப்ஸ், உங்கள் சாதனத்துடன் தொடர்புடைய தரவு, சாதனத்தின் இருப்பிடத் தகவல்கள் ஆகியவற்றைக் கண்காணிக்கவும் நிர்வகிக்கவும் முடியும்.\n\nமேலும் தகவல்களுக்கு IT நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"இந்த சாதனம் உங்கள் நிறுவனத்துக்கு சொந்தமானது.\n\nஉங்கள் IT நிர்வாகியால் அமைப்புகள், நிறுவன அணுகல், ஆப்ஸ், உங்கள் சாதனத்துடன் தொடர்புடைய தரவு, சாதனத்தின் இருப்பிடத் தகவல்கள் ஆகியவற்றைக் கண்காணிக்கவும் நிர்வகிக்கவும் முடியும்.\n\nமேலும் தகவல்களுக்கு IT நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"உங்கள் நிறுவனம் இந்தச் சாதனத்தில் சான்றிதழ் அங்கீகாரத்தை நிறுவியுள்ளது. உங்களின் பாதுகாப்பான நெட்வொர்க் ட்ராஃபிக் கண்காணிக்கப்படலாம் அல்லது மாற்றப்படலாம்."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"உங்கள் நிர்வாகி நெட்வொர்க் பதிவெடுத்தலை இயக்கியுள்ளார், இது சாதனத்தில் ட்ராஃபிக்கைக் கண்காணிக்கும்.\n\nமேலும் தகவலுக்கு, உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"VPN இணைப்பை அமைக்க, பயன்பாட்டிற்கு அனுமதி வழங்கியுள்ளீர்கள்.\n\nஇந்த ஆப்ஸால் மின்னஞ்சல்கள், ஆப்ஸ் மற்றும் இணையதளங்கள் உட்பட, உங்கள் சாதனத்தையும் நெட்வொர்க் செயல்பாட்டையும் கண்காணிக்க முடியும்."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"உங்கள் பணிக் கணக்கை <xliff:g id="ORGANIZATION">%1$s</xliff:g> நிர்வகிக்கிறது.\n\nஉங்கள் நிர்வாகியால் ஆப்ஸ், இணையதளங்கள் உட்பட உங்கள் நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்க முடியும்.\n\nமேலும் தகவலுக்கு, உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்.\n\nஉங்கள் நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்கக்கூடிய VPN உடனும் இணைக்கப்பட்டுள்ளீர்கள்."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"இந்தச் சாதனம் உங்கள் பெற்றோரால் நிர்வகிக்கப்படுகிறது. நீங்கள் பயன்படுத்தும் ஆப்ஸ், இருப்பிடம், பயன்படுத்திய நேரம் ஆகியவற்றைப் பார்க்கவும் நிர்வகிக்கவும் உங்கள் பெற்றோரால் முடியும்."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"மின்னஞ்சல்கள், ஆப்ஸ், இணையதளங்கள் உட்பட உங்கள் நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்கக்கூடிய <xliff:g id="APPLICATION">%1$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளீர்கள்."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"<xliff:g id="APPLICATION">%1$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளீர்கள். இந்த ஆப்ஸால், மின்னஞ்சல்கள், ஆப்ஸ் மற்றும் இணையதளங்கள் உட்பட உங்கள் தனிப்பட்ட நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்க முடியும்."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"புதிய சாதனத்தை இணைத்தல்"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"பதிப்பு எண்"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"பதிப்பு எண் கிளிப்போர்டுக்கு நகலெடுக்கப்பட்டது."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 0d23f25..7100c33 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"బ్యాటరీ రెండు బార్లు."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"బ్యాటరీ మూడు బార్లు."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"బ్యాటరీ నిండింది."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"ఫోన్ లేదు."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"ఫోన్ ఒక బారు."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"ఫోన్ రెండు బార్లు."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"ప్రొఫైల్ని పర్యవేక్షించవచ్చు"</string>
<string name="vpn_footer" msgid="3457155078010607471">"నెట్వర్క్ పర్యవేక్షించబడవచ్చు"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"నెట్వర్క్ పర్యవేక్షించబడవచ్చు"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ఈ పరికరాన్ని మీ తల్లి/తండ్రి మేనేజ్ చేస్తున్నారు"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"ఈ పరికరం మీ సంస్థకు చెందినది, కాబట్టి అది నెట్వర్క్ ట్రాఫిక్ను పర్యవేక్షించవచ్చు"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"మీ పరికరం <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>కు చెందినది, కాబట్టి అది నెట్వర్క్ ట్రాఫిక్ను పర్యవేక్షించవచ్చు"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"ఈ పరికరం మీ సంస్థకు చెందినది, ఇది <xliff:g id="VPN_APP">%1$s</xliff:g>కు కనెక్ట్ అయి ఉంది"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPNని నిలిపివేయి"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPNను డిస్కనెక్ట్ చేయి"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"విధానాలను వీక్షించండి"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"నియంత్రణలను చూడండి"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"ఈ పరికరం <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>కు చెందినది.\n\nసెట్టింగ్లను, కార్పొరేట్ యాక్సెస్ను, యాప్లను, మీ పరికరానికి సంబంధించిన డేటాను, అలాగే మీ పరికరం యొక్క లొకేషన్ సమాచారాన్ని మీ IT అడ్మిన్ పర్యవేక్షించగలరు, మేనేజ్ చేయగలరు.\n\nమరింత సమాచారం కోసం, మీ IT అడ్మిన్ను సంప్రదించండి."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"ఈ పరికరం మీ సంస్థకు చెందినది.\n\nసెట్టింగ్లను, కార్పొరేట్ యాక్సెస్ను, యాప్లను, మీ పరికరానికి సంబంధించిన డేటాను, అలాగే మీ పరికరం యొక్క లొకేషన్ సమాచారాన్ని మీ IT అడ్మిన్ పర్యవేక్షించగలరు, మేనేజ్ చేయగలరు.\n\nమరింత సమాచారం కోసం, మీ IT అడ్మిన్ను సంప్రదించండి."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"ఈ పరికరంలో మీ సంస్థ ఒక ప్రమాణపత్ర అధికారాన్ని ఇన్స్టాల్ చేసింది. మీ సురక్షిత నెట్వర్క్ ట్రాఫిక్ పర్యవేక్షించబడవచ్చు లేదా సవరించబడవచ్చు."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"మీ నిర్వాహకులు మీ పరికరంలోని ట్రాఫిక్ని పర్యవేక్షించగల నెట్వర్క్ లాగింగ్ని ఆన్ చేసారు.\n\nమరింత సమాచారం కావాలంటే, మీ నిర్వాహకులను సంప్రదించండి."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"మీరు VPN కనెక్షన్ సెటప్ చేయడానికి ఒక యాప్నకు అనుమతి ఇచ్చారు.\n\nఈ యాప్ ఇమెయిల్లు,యాప్లు మరియు వెబ్సైట్లతో సహా మీ డివైజ్ మరియు నెట్వర్క్ కార్యకలాపాన్ని పర్యవేక్షించగలదు."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> ద్వారా మీ కార్యాలయ ప్రొఫైల్ నిర్వహించబడుతోంది.\n\nఇమెయిల్లు, అనువర్తనాలు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల సామర్థ్యం మీ నిర్వాహకులకు ఉంది.\n\nమరింత సమాచారం కావాలంటే, మీ నిర్వాహకులను సంప్రదించండి.\n\nమీరు VPNకి కూడా కనెక్ట్ అయ్యారు, ఇది మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ఈ పరికరాన్ని మీ తల్లి/తండ్రి మేనేజ్ చేస్తున్నారు. మీ తల్లి/తండ్రి, మీరు ఉపయోగించే యాప్లు, మీ లొకేషన్, అలాగే మీ పరికర వినియోగ వ్యవధి వంటి సమాచారాన్ని చూడగలరు, మేనేజ్ చేయగలరు."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"మీరు ఇమెయిల్లు, అనువర్తనాలు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్లు, అనువర్తనాలు మరియు వెబ్సైట్లతో సహా మీ వ్యక్తిగత నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"కొత్త పరికరాన్ని పెయిర్ చేయండి"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"బిల్డ్ నంబర్"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"బిల్డ్ నంబర్, క్లిప్బోర్డ్కు కాపీ చేయబడింది."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 094cb76..8db84b8 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"แบตเตอรี่สองขีด"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"แบตเตอรี่สามขีด"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"แบตเตอรี่เต็ม"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"ไม่มีสัญญาณโทรศัพท์"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"สัญญาณโทรศัพท์หนึ่งขีด"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"สัญญาณโทรศัพท์สองขีด"</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"อาจมีการตรวจสอบโปรไฟล์"</string>
<string name="vpn_footer" msgid="3457155078010607471">"เครือข่ายอาจได้รับการตรวจสอบ"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"เครือข่ายอาจถูกตรวจสอบ"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"อุปกรณ์นี้จัดการโดยผู้ปกครอง"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"องค์กรของคุณเป็นเจ้าของอุปกรณ์นี้และอาจตรวจสอบการจราจรของข้อมูลในเครือข่าย"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> เป็นเจ้าของอุปกรณ์นี้และอาจตรวจสอบการจราจรของข้อมูลในเครือข่าย"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"องค์กรของคุณเป็นเจ้าของอุปกรณ์นี้ และอุปกรณ์เชื่อมต่ออยู่กับ <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"ปิดใช้ VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"ยกเลิกการเชื่อมต่อ VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"ดูนโยบาย"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"ดูการควบคุม"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> เป็นเจ้าของอุปกรณ์นี้\n\nผู้ดูแลระบบไอทีจะตรวจสอบและจัดการการตั้งค่า การเข้าถึงของบริษัท แอป ข้อมูลที่เชื่อมโยงกับอุปกรณ์ และข้อมูลตำแหน่งของอุปกรณ์ได้\n\nติดต่อผู้ดูแลระบบไอทีหากต้องการข้อมูลเพิ่มเติม"</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"องค์กรของคุณเป็นเจ้าของอุปกรณ์นี้\n\nผู้ดูแลระบบไอทีจะตรวจสอบและจัดการการตั้งค่า การเข้าถึงของบริษัท แอป ข้อมูลที่เชื่อมโยงกับอุปกรณ์ และข้อมูลตำแหน่งของอุปกรณ์ได้\n\nติดต่อผู้ดูแลระบบไอทีหากต้องการข้อมูลเพิ่มเติม"</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"องค์กรของคุณติดตั้งผู้ออกใบรับรองในอุปกรณ์นี้ อาจมีการตรวจสอบหรือแก้ไขการจราจรของข้อมูลในเครือข่ายที่ปลอดภัยของคุณ"</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"ผู้ดูแลระบบได้เปิดการทำบันทึกเครือข่าย ซึ่งจะติดตามดูการรับส่งข้อมูลบนอุปกรณ์ของคุณ\n\nโปรดติดต่อผู้ดูแลระบบสำหรับข้อมูลเพิ่มเติม"</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"คุณได้ให้สิทธิ์แอปในการตั้งค่าการเชื่อมต่อ VPN\n\nแอปนี้จะสามารถตรวจสอบอุปกรณ์และกิจกรรมในเครือข่าย รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"โปรไฟล์งานของคุณได้รับการจัดการโดย <xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nผู้ดูแลระบบสามารถตรวจสอบกิจกรรมในเครือข่ายของคุณ ซึ่งรวมถึงอีเมล แอป และเว็บไซต์ต่างๆ\n\nโปรดติดต่อผู้ดูแลระบบสำหรับข้อมูลเพิ่มเติม\n\nนอกจากนี้คุณยังเชื่อมต่อกับ VPN ซึ่งตรวจสอบกิจกรรมในเครือข่ายของคุณได้"</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"อุปกรณ์นี้จัดการโดยผู้ปกครอง ผู้ปกครองจะดูและจัดการข้อมูลต่างๆ ได้ เช่น แอปที่คุณใช้ ตำแหน่งของคุณ และเวลาอยู่หน้าจอ"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"คุณเชื่อมต่ออยู่กับ <xliff:g id="APPLICATION">%1$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายของคุณ รวมถึงอีเมล แอป และเว็บไซต์"</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"คุณเชื่อมต่อกับ <xliff:g id="APPLICATION">%1$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายส่วนตัวของคุณ รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"จับคู่อุปกรณ์ใหม่"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"หมายเลขบิวด์"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"คัดลอกหมายเลขบิวด์ไปยังคลิปบอร์ดแล้ว"</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 8ef1869..09f8a71 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Baterya na dalawang bar."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Baterya na tatlong bar."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Puno na ang baterya."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Walang telepono."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telepono na isang bar."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telepono na dalawang bar."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Maaaring subaybayan ang profile"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Maaaring sinusubaybayan ang network"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Maaaring sinusubaybayan ang network"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Pinapamahalaan ng iyong magulang ang device na ito"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Pagmamay-ari ng organisasyon mo ang device na ito at puwede nitong subaybayan ang trapiko sa network"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"Pagmamay-ari ng <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ang device na ito at puwede nitong subaybayan ang trapiko sa network"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Pagmamay-ari ng iyong organisasyon ang device na ito at nakakonekta ito sa <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"I-disable ang VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Idiskonekta ang VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Tingnan ang Mga Patakaran"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Tingnan ang mga kontrol"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Pagmamay-ari ng <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ang device na ito.\n\nMagagawa ng iyong IT admin na subaybayan at pamahalaan ang mga setting, pangkorporasyong access, mga app, data na nauugnay sa device mo, at ang impormasyon ng lokasyon ng iyong device.\n\nPara sa higit pang impormasyon, makipag-ugnayan sa iyong IT admin."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Pagmamay-ari ng iyong organisasyon ang device na ito.\n\nMagagawa ng iyong IT admin na subaybayan at pamahalaan ang mga setting, pangkorporasyong access, mga app, data na nauugnay sa device mo, at ang impormasyon ng lokasyon ng iyong device.\n\nPara sa higit pang impormasyon, makipag-ugnayan sa iyong IT admin."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Nag-install ang iyong organisasyon ng awtoridad sa certificate sa device na ito. Maaaring subaybayan o baguhin ang iyong ligtas na trapiko sa network."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Na-on ng iyong admin ang pag-log sa network, na sumusubaybay sa trapiko ng device mo.\n\nPara sa higit pang impormasyon, makipag-ugnayan sa iyong admin."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Nagbigay ka ng pahintulot sa app upang mag-set up ng VPN na koneksyon.\n\nMaaaring subaybayan ng app na ito ang iyong aktibidad sa device at network, kabilang ang mga email, app at website."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Pinamamahalaan ng <xliff:g id="ORGANIZATION">%1$s</xliff:g> ang iyong profile sa trabaho.\n\nMay kakayahan ang admin mo na subaybayan ang iyong aktibidad sa network, kasama ang mga email, app at website.\n\nPara sa higit pang impormasyon, makipag-ugnayan sa admin mo.\n\nNakakonekta ka rin sa isang VPN, na may kakayahang subaybayan ang iyong aktibidad sa network."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Pinapamahalaan ng iyong magulang ang device na ito. Makikita at mapapamahalaan ng iyong magulang ang impormasyon tulad ng mga app na ginagamit mo, iyong lokasyon, at tagal ng paggamit mo sa device."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Nakakonekta ka sa <xliff:g id="APPLICATION">%1$s</xliff:g>, na maaaring sumubaybay sa iyong aktibidad sa network, kasama ang mga email, app, at website."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Nakakonekta ka sa <xliff:g id="APPLICATION">%1$s</xliff:g>, na maaaring sumubaybay sa iyong personal na aktibidad sa network, kabilang ang mga email, app at website."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Magpares ng bagong device"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numero ng build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nakopya sa clipboard ang numero ng build."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index c17c8f7..89d7374 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Pil gücü iki çubuk."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Pil gücü üç çubuk."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Pil tam dolu."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Telefon sinyali yok."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefon sinyali bir çubuk."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefon sinyali iki çubuk."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profil izlenebilir"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Ağ etkinliği izlenebilir"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Ağ etkinliği izlenebilir"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Bu cihaz ebeveyniniz tarafından yönetiliyor"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Bu cihaz, kuruluşunuza ait olup ağ trafiği kuruluşunuz tarafından izlenebilir"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"Bu cihaz, <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> adlı kuruluşa ait olup ağ trafiği bu kuruluş tarafından izlenebilir"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Bu cihaz, kuruluşunuza ait olup <xliff:g id="VPN_APP">%1$s</xliff:g> uygulamasına bağlı"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN\'yi devre dışı bırak"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN bağlantısını kes"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Politikaları Göster"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Kontrolleri göster"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Bu cihaz <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> adlı kuruluşa ait.\n\nBT yöneticiniz cihazınızın ayarlarını, şirket erişimini, uygulamaları, cihazınızla ilişkilendirilen verileri, cihazınızın konum bilgilerini izleyip yönetebilir.\n\nDaha fazla bilgi için BT yöneticinize başvurun."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Bu cihaz kuruluşunuza ait.\n\nBT yöneticiniz cihazın ayarlarını, şirket erişimini, uygulamaları, cihazınızla ilişkilendirilen verileri, cihazınızın konum bilgilerini izleyip yönetebilir.\n\nDaha fazla bilgi için BT yöneticinize başvurun."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Kuruluşunuz bu cihaza bir sertifika yetkilisi yükledi. Güvenli ağ trafiğiniz izlenebilir veya değiştirilebilir."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Yöneticiniz,cihazınızdaki trafiği izleyen ağ günlük kaydını açtı.\n\nDaha fazla bilgi için yöneticinizle iletişim kurun."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"VPN bağlantısı kurması için bir uygulamaya izin verdiniz.\n\nBu uygulama, cihazınızın yanı sıra e-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilir."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tarafından yönetiliyor.\n\nYöneticiniz e-postalar, uygulamalar ve web siteleri de dahil olmak üzere ağ etkinliğinizi izleyebilir.\n\nDaha fazla bilgi için yöneticinizle iletişim kurun.\n\nAyrıca, ağ etkinliğinizi izleyebilen bir VPN\'ye de bağlısınız."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Bu cihaz ebeveyniniz tarafından yönetiliyor. Kullandığınız uygulamalar, konumunuz ve ekran başında kalma süreniz gibi bilgiler ebeveyniniz tarafından görülüp yönetebilir."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasına bağlısınız."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere kişisel ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasına bağlısınız."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yeni cihaz eşle"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Derleme numarası"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Derleme numarası panoya kopyalandı."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 7dcfc3b..f196293 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Заряд акумулятора: дві смужки."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Заряд акумулятора: три смужки."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Акумулятор заряджений."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Немає сигналу телефону."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Одна смужка сигналу телефону."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Дві смужки сигналу телефону."</string>
@@ -526,6 +528,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Профіль може відстежуватись"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Дії в мережі можуть відстежуватися"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Мережа може відстежуватися"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Цим пристроєм керує батько або мати"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Цей пристрій належить вашій організації. Її адміністратор може відстежувати мережевий трафік"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"Цей пристрій належить організації \"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>\". Її адміністратор може відстежувати мережевий трафік"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Цей пристрій належить вашій організації. Його підключено до додатка <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -550,6 +553,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Вимкнути VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Від’єднатися від мережі VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Переглянути правила"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Переглянути засоби контролю"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Цей пристрій належить організації \"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>\".\n\nIT-адміністратор може відстежувати й контролювати налаштування, корпоративний доступ, додатки, дані пристрою та інформацію про його місцезнаходження.\n\nЩоб дізнатися більше, зв\'яжіться з IT-адміністратором."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Цей пристрій належить вашій організації.\n\nІТ-адміністратор може відстежувати й контролювати налаштування, корпоративний доступ, додатки, дані пристрою та інформацію про його місцезнаходження.\n\nЩоб дізнатися більше, зв\'яжіться з ІТ-адміністратором."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Адміністратор організації встановив центр сертифікації на цьому пристрої. Захищений мережевий трафік може відстежуватися або змінюватися."</string>
@@ -573,6 +577,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Ваш адміністратор увімкнув реєстрацію в мережі, під час якої на вашому пристрої відстежується трафік.\n\nЩоб дізнатися більше, зв’яжіться з адміністратором."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Ви дозволили додатку під’єднуватися до мережі VPN.\n\nЦей додаток може відстежувати вашу активність на пристрої та в мережі, зокрема в електронній пошті, додатках і на веб-сайтах."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Вашим робочим профілем керує адміністратор організації <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nВін може відстежувати ваші дії в мережі, зокрема електронні листи, додатки та веб-сайти.\n\nЩоб дізнатися більше, зв’яжіться з адміністратором.\n\nВаш пристрій також під’єднано до мережі VPN, у якій можна відстежувати ваші дії в мережі."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Цим пристроєм керує батько або мати. Вони можуть бачити та контролювати, якими додатками ви користуєтесь, де перебуваєте й скільки часу проводите за пристроєм."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Ваш профіль під’єднано до додатка <xliff:g id="APPLICATION">%1$s</xliff:g>, який може відстежувати вашу активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Ваш профіль під’єднано до додатка <xliff:g id="APPLICATION">%1$s</xliff:g>, який може відстежувати вашу особисту активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах."</string>
@@ -1101,4 +1106,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Підключити новий пристрій"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер складання"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Номер складання скопійовано в буфер обміну."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 4c0ebaa..6973c5e 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"بیٹری کے دو بارز۔"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"بیٹری کے تین بارز۔"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"بیٹری بھری ہے۔"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"کوئی فون نہیں ہے۔"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"فون کا ایک بار۔"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"فون کے دو بارز۔"</string>
@@ -520,6 +522,8 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"پروفائل کو مانیٹر کیا جا سکتا ہے"</string>
<string name="vpn_footer" msgid="3457155078010607471">"نیٹ ورک کو مانیٹر کیا جا سکتا ہے"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"نیٹ ورک کو شاید مانیٹر کیا جائے"</string>
+ <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
+ <skip />
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"آپ کی تنظیم اس آلے کی مالک ہے اور نیٹ ورک ٹریفک کی نگرانی کر سکتی ہے"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> اس آلے کی مالک ہے اور نیٹ ورک ٹریفک کی نگرانی کر سکتی ہے"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"یہ آلہ آپ کی تنظیم کا ہے اور <xliff:g id="VPN_APP">%1$s</xliff:g> سے منسلک ہے"</string>
@@ -544,6 +548,8 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN کو غیر فعال کریں"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN کو غیر منسلک کریں"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"پالیسیاں دیکھیں"</string>
+ <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
+ <skip />
<string name="monitoring_description_named_management" msgid="505833016545056036">"یہ آلہ <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> کا ہے۔\n\nآپ کا IT منتظم ترتیبات، کارپوریٹ رسائی، ایپس، آپ کے آلہ سے وابستہ ڈیٹا اور آپ کے آلہ کے مقام کی معلومات کی نگرانی اور ان کا نظم کر سکتا ہے۔\n\nمزید معلومات کے لیے اپنے IT منتظم سے رابطہ کریں۔"</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"یہ آلہ آپ کی تنظیم کا ہے۔\n\nآپ کا IT منتظم ترتیبات، کارپوریٹ رسائی، ایپس، آپ کے آلہ سے وابستہ ڈیٹا اور آپ کے آلہ کے مقام کی معلومات کی نگرانی اور ان کا نظم کر سکتا ہے۔\n\nمزید معلومات کے لیے اپنے IT منتظم سے رابطہ کریں۔"</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"آپ کی تنظیم نے اس آلے پر ایک سرٹیفکیٹ کی اتھارٹی کو انسٹال کیا ہے۔ آپ کا محفوظ نیٹ ورک ٹریفک مانیٹر ہو سکتا ہے یا اس میں ترمیم کی جا سکتی ہے۔"</string>
@@ -567,6 +573,8 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"آپ کے ایڈمن نے نیٹ ورک لاگنگ آن کر دی ہے، جو آپ کے آلہ پر ٹریفک کو مانیٹر کرتی ہے۔\n\nمزید معلومات کیلئے اپنے ایڈمن سے رابطہ کریں۔"</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"آپ نے ایک ایپ کو VPN کنکشن ترتیب دینے کی اجازت دی ہے۔\n\nیہ ایپ ای میلز، ایپس اور ویب سائٹس سمیت آپ کے آلہ اور نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"آپ کی دفتری پروفائل <xliff:g id="ORGANIZATION">%1$s</xliff:g> کے زیر نظم ہے۔\n\nآپ کا ایڈمن بشمول ای میلز، ایپس، اور ویب سائٹس، آپ کے نیٹ ورک کی سرگرمی کو مانیٹر کرنے کا اہل ہے۔\n\nمزید معلومات کے لیے اپنے ایڈمن سے رابطہ کریں۔\n\nآپ ایک VPN سے بھی منسلک ہیں، جو آپ کے نیٹ ورک کی سرگرمی کو مانیٹر کر سکتا ہے۔"</string>
+ <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
+ <skip />
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"آپ <xliff:g id="APPLICATION">%1$s</xliff:g> سے منسلک ہیں، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"آپ <xliff:g id="APPLICATION">%1$s</xliff:g> سے منسلک ہیں، جو آپ کے نجی نیٹ ورک کی سرگرمی سمیت ای میلز، ایپس اور ویب سائٹس مانیٹر کر سکتی ہے۔"</string>
@@ -1089,4 +1097,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"نئے آلہ کا جوڑا بنائیں"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"بلڈ نمبر"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"بلڈ نمبر کلپ بورڈ میں کاپی ہو گیا۔"</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 33d4f4c..a97f1e4 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Batareya ikkta panelda."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Batareya uchta panelda."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batareya to‘la."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Signal yo‘q."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefon bitta panelda."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefon ikkita panelda."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profil kuzatilishi mumkin"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Tarmoqni kuzatish mumkin"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Tarmoq kuzatilishi mumkin"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Bu – ota-onangiz tomonidan boshqariladigan qurilma."</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Bu qurilma tashkilotingizga tegishli va tarmoq trafigi tashkilotingiz tomonidan kuzatilishi mumkin"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"Bu qurilma <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> tashkilotiga tegishli va tarmoq trafigi tashkilot tomonidan kuzatilishi mumkin"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Bu qurilma tashkilotingizga tegishli va <xliff:g id="VPN_APP">%1$s</xliff:g> tarmogʻiga ulangan"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN tarmog‘ini o‘chirish"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN ulanishini uzish"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Siyosatlarni ko‘rish"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Boshqaruvni chiqarish"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Bu qurilma <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> tashkilotiga tegishli.\n\nAT administratori sozlamalar, korporativ ruxsat, ilovalar, qurilmaning geolokatsiyasi va unga aloqador axborotlarni kuzatishi va boshqarishi mumkin.\n\nBatafsil axborot uchun AT administratoriga murojaat qiling."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Bu qurilma tashkilotingizga tegishli.\n\nAT administratori sozlamalar, korporativ ruxsat, ilovalar, qurilmaning geolokatsiyasi va unga aloqador axborotlarni kuzatishi va boshqarishi mumkin.\n\nBatafsil axborot uchun AT administratoriga murojaat qiling."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Tashkilotingiz bu qurilmada CA sertifikatini o‘rnatdi. U himoyalangan tarmoq trafigini nazorat qilishi va o‘zgartirishi mumkin."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Administrator qurilmangizdagi trafikni nazorat qiluvchi tarmoq jurnalini yoqdi.\n\nBatafsil axborot olish uchun administratoringizga murojaat qiling."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Siz ilovaga VPN tarmog‘iga ulanishga ruxsat bergansiz.\n\nUshbu ilova qurilmangiz va internetdagi harakatlaringizni, jumladan, e-pochta, ilovalar va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Sizning ishchi profilingiz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tomonidan boshqariladi.\n\nAdministrator internetdagi harakatlaringizni, jumladan, e-pochta, ilova va xavfsiz veb-saytlar bilan ishlashingizni kuzatishi mumkin.\n\nBatafsil axborot olish uchun administrator bilan bog‘laning.\n\nShuningdek, siz VPN tarmog‘iga ham ulangansiz. U internetdagi harakatlaringizni kuzatishi mumkin."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Bu – ota-onangiz tomonidan boshqariladigan qurilma. Ota-onangiz siz foydalangan ilovalar, joylashuvingiz va qurilmadan foydalanish vaqti kabi axborotlarni koʻrishi va boshqarishi mumkin."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasi ishga tushirilgan. U tarmoqdagi, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yangi qurilmani ulash"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nashr raqami"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nashr raqami vaqtinchalik xotiraga nusxalandi."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 179f7c2..4a69cc7 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Mức pin hai vạch."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Mức pin ba vạch."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Mức pin đầy."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Không có điện thoại nào."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Tín hiệu điện thoại một vạch."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Tín hiệu điện thoại hai vạch."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Hồ sơ có thể được giám sát"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Mạng có thể được giám sát"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Mạng có thể được giám sát"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Thiết bị này do cha mẹ của bạn quản lý"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Tổ chức của bạn sở hữu thiết bị này và có thể giám sát lưu lượng truy cập mạng"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> sở hữu thiết bị này và có thể giám sát lưu lượng truy cập mạng"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Thiết bị này thuộc về tổ chức của bạn và đã kết nối với <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Tắt VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Ngắt kết nối VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Xem chính sách"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Xem các quyền kiểm soát"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Thiết bị này thuộc về <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nQuản trị viên CNTT có thể giám sát và quản lý các tùy chọn cài đặt, quyền truy cập vào dữ liệu công ty, ứng dụng, dữ liệu liên kết với thiết bị và thông tin vị trí thiết bị của bạn.\n\nĐể biết thêm thông tin, hãy liên hệ với quản trị viên CNTT của bạn."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Thiết bị này thuộc về tổ chức của bạn.\n\nQuản trị viên CNTT có thể giám sát và quản lý các tùy chọn cài đặt, quyền truy cập vào dữ liệu công ty, ứng dụng, dữ liệu liên kết với thiết bị và thông tin vị trí thiết bị của bạn.\n\nĐể biết thêm thông tin, hãy liên hệ với quản trị viên CNTT của bạn."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Tổ chức của bạn đã cài đặt một tổ chức phát hành chứng chỉ trên thiết bị này. Lưu lượng truy cập mạng bảo mật của bạn có thể được giám sát hoặc sửa đổi."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Quản trị viên đã bật tính năng ghi nhật ký mạng. Tính năng này giám sát lưu lượng truy cập trên thiết bị của bạn.\n\nĐể biết thêm thông tin, hãy liên hệ với quản trị viên của bạn."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Bạn đã cấp cho ứng dụng quyền thiết lập kết nối VPN.\n\nỨng dụng này có thể giám sát hoạt động mạng và thiết bị của bạn, bao gồm email, ứng dụng và trang web."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Hồ sơ công việc của bạn do <xliff:g id="ORGANIZATION">%1$s</xliff:g> quản lý.\n\nQuản trị viên có thể giám sát hoạt động mạng của bạn bao gồm email, ứng dụng và trang web.\n\nĐể biết thêm thông tin, hãy liên hệ với quản trị viên của bạn.\n\nBạn cũng được kết nối với VPN. Dịch vụ này có thể giám sát hoạt động mạng của bạn."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Thiết bị này do cha mẹ bạn quản lý. Cha mẹ có thể có thể xem và quản lý những thông tin như ứng dụng bạn dùng, vị trí của bạn và thời gian bạn sử dụng thiết bị."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Bạn đang kết nối với <xliff:g id="APPLICATION">%1$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng của bạn bao gồm email, ứng dụng và trang web."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Bạn đang kết nối với <xliff:g id="APPLICATION">%1$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng cá nhân của bạn bao gồm email, ứng dụng và trang web."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Ghép nối thiết bị mới"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Số bản dựng"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Đã sao chép số bản dựng vào khay nhớ tạm."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index e1f483c..9c34b31 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"电池电量为两格。"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"电池电量为三格。"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"电池电量满格。"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"没有手机信号。"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"手机信号强度为一格。"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"手机信号强度为两格。"</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"资料可能会受到监控"</string>
<string name="vpn_footer" msgid="3457155078010607471">"网络可能会受到监控"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"网络可能会受到监控"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"此设备由您的家长管理"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"贵单位拥有此设备,且可能会监控网络流量"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>拥有此设备,且可能会监控网络流量"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"此设备归贵单位所有,且已连接到“<xliff:g id="VPN_APP">%1$s</xliff:g>”"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"关闭VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"断开VPN连接"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"查看政策"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"查看家长控制功能相关信息"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"此设备归<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>所有。\n\n您的 IT 管理员能够监控和管理与您的设备相关的设置、企业权限、应用、数据,以及您设备的位置信息。\n\n如需了解详情,请与您的 IT 管理员联系。"</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"此设备归贵单位所有。\n\n您的 IT 管理员能够监控和管理与您的设备相关的设置、企业权限、应用、数据,以及您设备的位置信息。\n\n如需了解详情,请与您的 IT 管理员联系。"</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"您所在的单位已在此设备上安装证书授权中心。您的安全网络流量可能会受到监控或修改。"</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"您的管理员已开启网络日志功能,该功能会监控您设备上的流量。\n\n如需更多信息,请与您的管理员联系。"</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"您已授权应用设置 VPN 连接。\n\n该应用可以监控您的设备和网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"您的工作资料由“<xliff:g id="ORGANIZATION">%1$s</xliff:g>”管理。\n\n您的管理员能够监控您的网络活动,其中包括收发电子邮件、使用应用和访问网站。\n\n如需更多信息,请与您的管理员联系。\n\n此外,您还连接到了 VPN,它同样可以监控您的网络活动。"</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"此设备由您的家长管理。您的家长可以查看和管理相关信息,例如您使用的应用、您的位置信息和设备使用时间。"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"您已连接到“<xliff:g id="APPLICATION">%1$s</xliff:g>”(该应用能够监控您的网络活动,其中包括收发电子邮件、使用应用和浏览网站)。"</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"您已连接到<xliff:g id="APPLICATION">%1$s</xliff:g>,该应用可以监控您的个人网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"与新设备配对"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本号"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"已将版本号复制到剪贴板。"</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index f986ef33..2e22b07 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"電池電量為兩格。"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"電池電量為三格。"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"電池已滿。"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"沒有電話訊號。"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"電話訊號強度為一格。"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"電話訊號強度為兩格。"</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"個人檔案可能受到監控"</string>
<string name="vpn_footer" msgid="3457155078010607471">"網絡可能會受到監控"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"網絡可能會受到監控"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"此裝置由您的家長管理"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"您的機構擁有此裝置,並可能會監察網絡流量"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"「<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>」擁有此裝置,並可能會監察網絡流量"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"此裝置屬於您的機構,並已連結至「<xliff:g id="VPN_APP">%1$s</xliff:g>」"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"停用 VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"中斷 VPN 連線"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"查看政策"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"查看控制項"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"此裝置屬於 <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>。\n\n您的 IT 管理員可監察及管理與裝置相關聯的設定、公司存取權、應用程式和資料,以及裝置的位置資料。\n\n如要瞭解詳情,請與您的 IT 管理員聯絡。"</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"此裝置屬於您的機構。\n\n您的 IT 管理員可監察及管理與裝置相關聯的設定、公司存取權、應用程式和資料,以及裝置的位置資料。\n\n如要瞭解詳情,請與您的 IT 管理員聯絡。"</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"您的機構已在此裝置中安裝憑證授權單位。您的安全網絡流量可能會受監控或修改。"</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"您的管理員已開啟網絡記錄功能,以監控您裝置上的流量。\n\n如需瞭解詳情,請聯絡您的管理員。"</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"您已授權應用程式設定 VPN 連線。\n\n這個應用程式能夠監控您的裝置和網絡活動,包括電郵、應用程式和網站。"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"您的工作設定檔由<xliff:g id="ORGANIZATION">%1$s</xliff:g>管理。\n\n您的管理員可以監控您的網絡活動,包括收發電郵、使用應用程式和瀏覽網站。\n\n如需瞭解詳情,請聯絡您的管理員。\n\n此外,由於您已連接至 VPN,因此 VPN 可監控您的網絡活動。"</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"此裝置由您的家長管理。家長可以查看及管理裝置上的資料,例如您使用的應用程式、位置和裝置使用時間。"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"您已連結至「<xliff:g id="APPLICATION">%1$s</xliff:g>」,此應用程式可以監控您的網絡活動,包括電郵、應用程式和網站。"</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"您已連結至<xliff:g id="APPLICATION">%1$s</xliff:g>,它能夠監控您的個人網絡活動,包括電郵、應用程式和網站。"</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"配對新裝置"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本號碼"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"版本號碼已複製到剪貼簿。"</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index b442b79..0cc17ef 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"電池電量兩格。"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"電池電量三格。"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"電池電量已滿。"</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"沒有電話訊號。"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"電話訊號強度一格。"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"電話訊號強度兩格。"</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"設定檔可能會受到監控"</string>
<string name="vpn_footer" msgid="3457155078010607471">"網路可能會受到監控"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"網路可能會受到監控"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"這個裝置是由你的家長管理"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"貴機構擁有這部裝置,而且可能會監控網路流量"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"這部裝置的擁有者為「<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>」,而且該機構可能會監控網路流量"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"這部裝置的擁有者為貴機構,並且已連線到「<xliff:g id="VPN_APP">%1$s</xliff:g>」"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"停用 VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"中斷 VPN 連線"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"查看政策"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"查看監護功能相關資訊"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"這部裝置的擁有者為「<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>」。\n\n你的 IT 管理員可以監控及管理與裝置相關聯的設定、公司系統權限、應用程式和資料,以及裝置的位置資訊。\n\n如要瞭解詳情,請與你的 IT 管理員聯絡。"</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"這部裝置的擁有者為貴機構。\n\n你的 IT 管理員可以監控及管理與裝置相關聯的設定、公司系統權限、應用程式和資料,以及裝置的位置資訊。\n\n如要瞭解詳情,請與你的 IT 管理員聯絡。"</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"貴機構已為這個裝置安裝憑證授權單位憑證。你的安全網路流量可能會受到監控或修改。"</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"你的管理員已啟用網路記錄功能,可監控你裝置的流量。\n\n如需詳細資訊,請與你的管理員聯絡。"</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"你已授權一個應用程式設定 VPN 連線。\n\n這個應用程式可以監控你的裝置和網路活動,包括收發電子郵件、使用應用程式和瀏覽網站。"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"你的工作資料夾是由下列機構管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。\n\n你的管理員可以監控你的網路活動,包括收發電子郵件、使用應用程式及瀏覽網站。\n\n如需詳細資訊,請與你的管理員聯絡。\n\n此外,由於你已連線至 VPN,因此你的網路活動也會受到 VPN 監控。"</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"這個裝置是由你的家長管理。家長可以查看及管理裝置上的資訊,例如你使用的應用程式、所在位置和裝置使用時間。"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"由於你已連結至「<xliff:g id="APPLICATION">%1$s</xliff:g>」,因此你的網路活動 (包括收發電子郵件、使用應用程式和瀏覽網站) 可能會受到這個應用程式監控。"</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"由於你已連線至 <xliff:g id="APPLICATION">%1$s</xliff:g>,你的個人網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。"</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"配對新裝置"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本號碼"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"已將版本號碼複製到剪貼簿。"</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 764f0b7..9e85eed 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -182,6 +182,8 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Amabha amabili ebhethri"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Amabha amathathu ebhethri"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Ibhethri igcwele."</string>
+ <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
+ <skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Ayikho ifoni."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Ibha eyodwa yefoni"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Amabha amabilil efoni."</string>
@@ -520,6 +522,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Iphrofayela ingaqashwa"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Inethiwekhi kungenzeka iqashiwe"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Inethiwekhi kungenzeka iqashiwe"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Le divayisi iphethwe ngumzali wakho"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Inhlangano yakho ingumnikazi wale divayisi futhi ingaqapha ithrafikhi yenethiwekhi"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"I-<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ingumnikazi wale divayisi futhi ingaqapha ithrafikhi yenethiwekhi"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Le divayisi ngeyenhlangano yakho futhi ixhunywe ku-<xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -544,6 +547,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Khubaza i-VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Nqamula i-VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Buka izinqubomgomo"</string>
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Buka izilawuli"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Le divayisi ngeye-<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nUmphathi wakho we-IT angakwazi ukugada nokulawula amasethingi, ukufinyelela kwenhlangano, izinhlelo zokusebenza, idatha ehlobene nedivayisi yakho, nolwazi lwendawo yedivayisi yakho.\n\nUkuze uthole ulwazi olwengeziwe, xhumana nomphathi wakho we-IT."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Le divayisi ngeyenhlangano.\n\nUmphathi wakho we-IT angakwazi ukugada nokulawula amasethingi, ukufinyelela kwenhlangano, izinhlelo zokusebenza, idatha ehlobene nedivayisi yakho, nolwazi lwendawo yedivayisi yakho.\n\nUkuze uthole ulwazi olwengeziwe, xhumana nomphathi wakho we-IT."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Inhlangano yakho ifake ukugunyazwa kwesitifiketi kule divayisi. Ithrafikhi yenethiwekhi yakho evikelekile kungenzeka iqashelwe noma ilungiswe."</string>
@@ -567,6 +571,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Umlawuli wakho uvule ukungena kwenethiwekhi, okuhlola ithrafikhi kudivayisi yakho.\n\nNgolwazi olubanzi xhumana nomlawuli wakho."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Unikeze uhlelo lokusebenza imvume yokusetha ukuxhumana kwe-VPN.\n\nLolu hlelo lokusebenza lungahlola idivayisi yakho nomsebenzi wenethiwekhi, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Iphrofayela yakho yomsebenzi iphethwe ngu-<xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nUmlawuli wakho uyakwazi ukwengamela umsebenzi wakho wenethiwekhi kufaka phakathi ama-imeyili, izinhlelo zokusebenza, namawebhusayithi.\n\nNgolwazi olubanzi, xhumana nomlawuli wakho.\n\nFuthi uxhumekile ku-VPN, engangamela umsebenzi wakho wenethiwekhi."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Le divayisi iphethwe ngumzali wakho. Umzali wakho angabona futhi aphathe ulwazi olunjengezinhlelo zokusebenza ozisebenzisayo, indawo yakho, kanye nesikhathi sesikrini."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"I-VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Uxhumeke ku-<xliff:g id="APPLICATION">%1$s</xliff:g>, engaqapha umsebenzi wakho wenethiwekhi, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Uxhumeke ku-<xliff:g id="APPLICATION">%1$s</xliff:g>, engahlola umsebenzi wenethiwekhi yakho yomuntu siqu, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
@@ -1089,4 +1094,8 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Bhanqa idivayisi entsha"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Yakha inombolo"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Yakha inombolo ekopishelwe kubhodi yokunamathisela."</string>
+ <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
+ <skip />
+ <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 6df8b4e..be36316 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -204,10 +204,6 @@
<color name="global_screenshot_dismiss_foreground">@color/GM2_grey_500</color>
<color name="global_screenshot_background_protection_start">#40000000</color> <!-- 25% black -->
- <!-- Bubbles -->
- <color name="bubbles_light">#FFFFFF</color>
- <color name="bubbles_dark">@color/GM2_grey_800</color>
-
<!-- GM2 colors -->
<color name="GM2_grey_50">#F8F9FA</color>
<color name="GM2_grey_100">#F1F3F4</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 17dc400..a2e9f39 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1159,90 +1159,6 @@
<!-- Radius of Ongoing App Ops chip corners -->
<dimen name="ongoing_appops_chip_bg_corner_radius">16dp</dimen>
-
- <!-- How much each bubble is elevated. -->
- <dimen name="bubble_elevation">1dp</dimen>
- <!-- How much the bubble flyout text container is elevated. -->
- <dimen name="bubble_flyout_elevation">4dp</dimen>
- <!-- How much padding is around the left and right sides of the flyout text. -->
- <dimen name="bubble_flyout_padding_x">12dp</dimen>
- <!-- How much padding is around the top and bottom of the flyout text. -->
- <dimen name="bubble_flyout_padding_y">10dp</dimen>
- <!-- Size of the triangle that points from the flyout to the bubble stack. -->
- <dimen name="bubble_flyout_pointer_size">6dp</dimen>
- <!-- How much space to leave between the flyout (tip of the arrow) and the bubble stack. -->
- <dimen name="bubble_flyout_space_from_bubble">8dp</dimen>
- <!-- How much space to leave between the flyout text and the avatar displayed in the flyout. -->
- <dimen name="bubble_flyout_avatar_message_space">6dp</dimen>
- <!-- Padding between status bar and bubbles when displayed in expanded state -->
- <dimen name="bubble_padding_top">16dp</dimen>
- <!-- Size of individual bubbles. -->
- <dimen name="individual_bubble_size">60dp</dimen>
- <!-- Size of bubble bitmap. -->
- <dimen name="bubble_bitmap_size">52dp</dimen>
- <!-- Size of bubble icon bitmap. -->
- <dimen name="bubble_overflow_icon_bitmap_size">24dp</dimen>
- <!-- Extra padding added to the touchable rect for bubbles so they are easier to grab. -->
- <dimen name="bubble_touch_padding">12dp</dimen>
- <!-- Size of the circle around the bubbles when they're in the dismiss target. -->
- <dimen name="bubble_dismiss_encircle_size">52dp</dimen>
- <!-- Padding around the view displayed when the bubble is expanded -->
- <dimen name="bubble_expanded_view_padding">4dp</dimen>
- <!-- This should be at least the size of bubble_expanded_view_padding; it is used to include
- a slight touch slop around the expanded view. -->
- <dimen name="bubble_expanded_view_slop">8dp</dimen>
- <!-- Default (and minimum) height of the expanded view shown when the bubble is expanded -->
- <dimen name="bubble_expanded_default_height">180dp</dimen>
- <!-- Default height of bubble overflow -->
- <dimen name="bubble_overflow_height">480dp</dimen>
- <!-- Bubble overflow padding when there are no bubbles -->
- <dimen name="bubble_overflow_empty_state_padding">16dp</dimen>
- <!-- Padding of container for overflow bubbles -->
- <dimen name="bubble_overflow_padding">15dp</dimen>
- <!-- Padding of label for bubble overflow view -->
- <dimen name="bubble_overflow_text_padding">7dp</dimen>
- <!-- Height of bubble overflow empty state illustration -->
- <dimen name="bubble_empty_overflow_image_height">200dp</dimen>
- <!-- Padding of bubble overflow empty state subtitle -->
- <dimen name="bubble_empty_overflow_subtitle_padding">50dp</dimen>
- <!-- Height of the triangle that points to the expanded bubble -->
- <dimen name="bubble_pointer_height">8dp</dimen>
- <!-- Width of the triangle that points to the expanded bubble -->
- <dimen name="bubble_pointer_width">12dp</dimen>
- <!-- Extra padding around the dismiss target for bubbles -->
- <dimen name="bubble_dismiss_slop">16dp</dimen>
- <!-- Height of button allowing users to adjust settings for bubbles. -->
- <dimen name="bubble_manage_button_height">48dp</dimen>
- <!-- Max width of the message bubble-->
- <dimen name="bubble_message_max_width">144dp</dimen>
- <!-- Min width of the message bubble -->
- <dimen name="bubble_message_min_width">32dp</dimen>
- <!-- Interior padding of the message bubble -->
- <dimen name="bubble_message_padding">4dp</dimen>
- <!-- Offset between bubbles in their stacked position. -->
- <dimen name="bubble_stack_offset">10dp</dimen>
- <!-- Offset between stack y and animation y for bubble swap. -->
- <dimen name="bubble_swap_animation_offset">15dp</dimen>
- <!-- How far offscreen the bubble stack rests. Cuts off padding and part of icon bitmap. -->
- <dimen name="bubble_stack_offscreen">9dp</dimen>
- <!-- How far down the screen the stack starts. -->
- <dimen name="bubble_stack_starting_offset_y">120dp</dimen>
- <!-- Space between the pointer triangle and the bubble expanded view -->
- <dimen name="bubble_pointer_margin">8dp</dimen>
- <!-- Padding applied to the bubble dismiss target. Touches in this padding cause the bubbles to
- snap to the dismiss target. -->
- <dimen name="bubble_dismiss_target_padding_x">40dp</dimen>
- <dimen name="bubble_dismiss_target_padding_y">20dp</dimen>
- <dimen name="bubble_manage_menu_elevation">4dp</dimen>
-
- <!-- Bubbles user education views -->
- <dimen name="bubbles_manage_education_width">160dp</dimen>
- <!-- The inset from the top bound of the manage button to place the user education. -->
- <dimen name="bubbles_manage_education_top_inset">65dp</dimen>
- <!-- Size of padding for the user education cling, this should at minimum be larger than
- individual_bubble_size + some padding. -->
- <dimen name="bubble_stack_user_education_side_inset">72dp</dimen>
-
<!-- Size of the RAT type for CellularTile -->
<dimen name="celltile_rat_type_size">10sp</dimen>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 7d3135a..5f68bdb4 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -130,12 +130,6 @@
<item type="id" name="action_snooze_assistant_suggestion_1"/>
<item type="id" name="action_snooze"/>
- <!-- Accessibility actions for bubbles. -->
- <item type="id" name="action_move_top_left"/>
- <item type="id" name="action_move_top_right"/>
- <item type="id" name="action_move_bottom_left"/>
- <item type="id" name="action_move_bottom_right"/>
-
<!-- For StatusIconContainer to tag its icon views -->
<item type="id" name="status_bar_view_state_tag" />
@@ -146,17 +140,6 @@
<!-- Optional cancel button on Keyguard -->
<item type="id" name="cancel_button"/>
- <!-- For saving PhysicsAnimationLayout animations/animators as view tags. -->
- <item type="id" name="translation_x_dynamicanimation_tag"/>
- <item type="id" name="translation_y_dynamicanimation_tag"/>
- <item type="id" name="translation_z_dynamicanimation_tag"/>
- <item type="id" name="alpha_dynamicanimation_tag"/>
- <item type="id" name="scale_x_dynamicanimation_tag"/>
- <item type="id" name="scale_y_dynamicanimation_tag"/>
- <item type="id" name="physics_animator_tag"/>
- <item type="id" name="target_animator_tag" />
- <item type="id" name="reorder_animator_tag"/>
-
<!-- Global Actions Menu -->
<item type="id" name="global_actions_view" />
diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml
index b1e91c8..b50b5c1 100644
--- a/packages/SystemUI/res/values/integers.xml
+++ b/packages/SystemUI/res/values/integers.xml
@@ -22,17 +22,6 @@
<integer name="qs_footer_actions_width">0</integer>
<integer name="qs_footer_actions_weight">1</integer>
- <!-- Maximum number of bubbles to render and animate at one time. While the animations used are
- lightweight translation animations, this number can be reduced on lower end devices if any
- performance issues arise. -->
- <integer name="bubbles_max_rendered">5</integer>
-
- <!-- Number of columns in bubble overflow. -->
- <integer name="bubbles_overflow_columns">4</integer>
-
- <!-- Maximum number of bubbles we allow in overflow before we dismiss the oldest one. -->
- <integer name="bubbles_max_overflow">16</integer>
-
<integer name="magnification_default_scale">2</integer>
<!-- The position of the volume dialog on the screen.
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d5c9823..773ef7d 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -233,10 +233,16 @@
<!-- Notification text displayed when we fail to take a screenshot. [CHAR LIMIT=100] -->
<string name="screenshot_failed_to_capture_text">Taking screenshots isn\'t allowed by the app or
your organization</string>
+ <!-- Label for UI element which allows editing the screenshot [CHAR LIMIT=30] -->
+ <string name="screenshot_edit_label">Edit</string>
<!-- Content description indicating that tapping the element will allow editing the screenshot [CHAR LIMIT=NONE] -->
- <string name="screenshot_edit">Edit screenshot</string>
+ <string name="screenshot_edit_description">Edit screenshot</string>
+ <!-- Label for UI element which allows scrolling and extending the screenshot to be taller [CHAR LIMIT=30] -->
+ <string name="screenshot_scroll_label">Scroll</string>
+ <!-- Content description UI element which allows scrolling and extending the screenshot to be taller [CHAR LIMIT=NONE] -->
+ <string name="screenshot_scroll_description">Scroll screenshot</string>
<!-- Content description indicating that tapping a button will dismiss the screenshots UI [CHAR LIMIT=NONE] -->
- <string name="screenshot_dismiss_ui_description">Dismiss screenshot</string>
+ <string name="screenshot_dismiss_description">Dismiss screenshot</string>
<!-- Content description indicating that the view is a preview of the screenshot that was just taken [CHAR LIMIT=NONE] -->
<string name="screenshot_preview_description">Screenshot preview</string>
@@ -646,9 +652,6 @@
<!-- Content description to tell the user a notification has been removed from the notification shade -->
<string name="accessibility_notification_dismissed">Notification dismissed.</string>
- <!-- Content description to tell the user a bubble has been dismissed. -->
- <string name="accessibility_bubble_dismissed">Bubble dismissed.</string>
-
<!-- Content description for the notification shade panel (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_desc_notification_shade">Notification shade.</string>
<!-- Content description for the quick settings panel (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -1846,9 +1849,6 @@
<string name="notification_alert_title">Default</string>
<!-- [CHAR LIMIT=100] Notification Importance title -->
- <string name="notification_bubble_title">Bubble</string>
-
- <!-- [CHAR LIMIT=100] Notification Importance title -->
<string name="notification_automatic_title">Automatic</string>
<!-- [CHAR LIMIT=150] Notification Importance title: low importance level summary -->
@@ -1881,12 +1881,6 @@
<!-- Text shown in notification guts for conversation notifications that don't implement the full feature -->
<string name="no_shortcut"><xliff:g id="app_name" example="YouTube">%1$s</xliff:g> doesn\u2019t support conversation features</string>
- <!-- [CHAR LIMIT=NONE] Empty overflow title -->
- <string name="bubble_overflow_empty_title">No recent bubbles</string>
-
- <!-- [CHAR LIMIT=NONE] Empty overflow subtitle -->
- <string name="bubble_overflow_empty_subtitle">Recent bubbles and dismissed bubbles will appear here</string>
-
<!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. -->
<string name="notification_unblockable_desc">These notifications can\'t be modified.</string>
@@ -2607,45 +2601,8 @@
<!-- Description of the restart button in the hint of size compatibility mode. [CHAR LIMIT=NONE] -->
<string name="restart_button_description">Tap to restart this app and go full screen.</string>
- <!-- Text used for content description of settings button in the header of expanded bubble
- view. [CHAR_LIMIT=NONE] -->
- <string name="bubbles_settings_button_description">Settings for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g> bubbles</string>
- <!-- Content description for button that shows bubble overflow on click [CHAR LIMIT=NONE] -->
- <string name="bubble_overflow_button_content_description">Overflow</string>
- <!-- Action to add overflow bubble back to stack. [CHAR LIMIT=NONE] -->
- <string name="bubble_accessibility_action_add_back">Add back to stack</string>
- <!-- The text for the manage bubbles link. [CHAR LIMIT=NONE] -->
- <string name="manage_bubbles_text">Manage</string>
- <!-- Content description when a bubble is focused. [CHAR LIMIT=NONE] -->
- <string name="bubble_content_description_single"><xliff:g id="notification_title" example="some title">%1$s</xliff:g> from <xliff:g id="app_name" example="YouTube">%2$s</xliff:g></string>
- <!-- Content description when the stack of bubbles is focused. [CHAR LIMIT=NONE] -->
- <string name="bubble_content_description_stack"><xliff:g id="notification_title" example="some title">%1$s</xliff:g> from <xliff:g id="app_name" example="YouTube">%2$s</xliff:g> and <xliff:g id="bubble_count" example="4">%3$d</xliff:g> more</string>
<!-- Action in accessibility menu to move the stack of bubbles [CHAR LIMIT=20] -->
<string name="bubble_accessibility_action_move">Move</string>
- <!-- Action in accessibility menu to move the stack of bubbles to the top left of the screen. [CHAR LIMIT=30] -->
- <string name="bubble_accessibility_action_move_top_left">Move top left</string>
- <!-- Action in accessibility menu to move the stack of bubbles to the top right of the screen. [CHAR LIMIT=30] -->
- <string name="bubble_accessibility_action_move_top_right">Move top right</string>
- <!-- Action in accessibility menu to move the stack of bubbles to the bottom left of the screen. [CHAR LIMIT=30]-->
- <string name="bubble_accessibility_action_move_bottom_left">Move bottom left</string>
- <!-- Action in accessibility menu to move the stack of bubbles to the bottom right of the screen. [CHAR LIMIT=30]-->
- <string name="bubble_accessibility_action_move_bottom_right">Move bottom right</string>
- <!-- Text used for the bubble dismiss area. Bubbles dragged to, or flung towards, this area will go away. [CHAR LIMIT=30] -->
- <string name="bubble_dismiss_text">Dismiss bubble</string>
- <!-- Button text to stop a conversation from bubbling [CHAR LIMIT=60]-->
- <string name="bubbles_dont_bubble_conversation">Don\u2019t bubble conversation</string>
- <!-- Title text for the bubbles feature education cling shown when a bubble is on screen for the first time. [CHAR LIMIT=60]-->
- <string name="bubbles_user_education_title">Chat using bubbles</string>
- <!-- Descriptive text for the bubble feature education cling shown when a bubble is on screen for the first time. [CHAR LIMIT=NONE] -->
- <string name="bubbles_user_education_description">New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it.</string>
- <!-- Title text for the bubble "manage" button tool tip highlighting where users can go to control bubble settings. [CHAR LIMIT=60]-->
- <string name="bubbles_user_education_manage_title">Control bubbles anytime</string>
- <!-- Descriptive text for the bubble "manage" button tool tip highlighting where users can go to control bubble settings. [CHAR LIMIT=80]-->
- <string name="bubbles_user_education_manage">Tap Manage to turn off bubbles from this app</string>
- <!-- Button text for dismissing the bubble "manage" button tool tip [CHAR LIMIT=20]-->
- <string name="bubbles_user_education_got_it">Got it</string>
- <!-- Label for the button that takes the user to the notification settings for the given app. -->
- <string name="bubbles_app_settings"><xliff:g id="notification_title" example="Android Messages">%1$s</xliff:g> settings</string>
<!-- Notification content text when the system navigation mode changes as a result of changing the default launcher [CHAR LIMIT=NONE] -->
<string name="notification_content_system_nav_changed">System navigation updated. To make changes, go to Settings.</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 628193d..5b89f7f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -22,6 +22,7 @@
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.FrameLayout;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.keyguard.clock.ClockManager;
@@ -30,6 +31,9 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.AnimatableProperty;
+import com.android.systemui.statusbar.notification.PropertyAnimator;
+import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
import com.android.systemui.util.ViewController;
@@ -51,6 +55,7 @@
private final ClockManager mClockManager;
private final KeyguardSliceViewController mKeyguardSliceViewController;
private final NotificationIconAreaController mNotificationIconAreaController;
+ private FrameLayout mNewLockscreenClockFrame;
private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
@@ -114,6 +119,7 @@
mColorExtractor.addOnColorsChangedListener(mColorsListener);
mView.updateColors(getGradientColors());
updateAodIcons();
+ mNewLockscreenClockFrame = mView.findViewById(R.id.new_lockscreen_clock_view);
}
@Override
@@ -180,6 +186,21 @@
}
/**
+ * Update position of the view, with optional animation. Move the slice view and the clock
+ * slightly towards the center in order to prevent burn-in. Y positioning occurs at the
+ * view parent level.
+ */
+ void updatePosition(int x, AnimationProperties props, boolean animate) {
+ x = Math.abs(x);
+ if (mNewLockscreenClockFrame != null) {
+ PropertyAnimator.setProperty(mNewLockscreenClockFrame, AnimatableProperty.TRANSLATION_X,
+ -x, props, animate);
+ }
+ mKeyguardSliceViewController.updatePosition(x, props, animate);
+ mNotificationIconAreaController.updatePosition(x, props, animate);
+ }
+
+ /**
* Update lockscreen mode that may change clock display.
*/
void updateLockScreenMode(int mode) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
index 8b55b06..02b18b2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
@@ -42,6 +42,9 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardSliceProvider;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.notification.AnimatableProperty;
+import com.android.systemui.statusbar.notification.PropertyAnimator;
+import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.ViewController;
@@ -199,6 +202,13 @@
Trace.endSection();
}
+ /**
+ * Update position of the view, with optional animation
+ */
+ void updatePosition(int x, AnimationProperties props, boolean animate) {
+ PropertyAnimator.setProperty(mView, AnimatableProperty.TRANSLATION_X, x, props, animate);
+ }
+
void showSlice(Slice slice) {
Trace.beginSection("KeyguardSliceViewController#showSlice");
if (slice == null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index cc0d1b6..cc7b832 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -186,12 +186,23 @@
/**
* Update position of the view with an optional animation
*/
- public void updatePosition(int clockTranslationX, int clockTranslationY,
- boolean animateClock) {
- PropertyAnimator.setProperty(mView, AnimatableProperty.X,
- clockTranslationX, CLOCK_ANIMATION_PROPERTIES, animateClock);
- PropertyAnimator.setProperty(mView, AnimatableProperty.Y,
- clockTranslationY, CLOCK_ANIMATION_PROPERTIES, animateClock);
+ public void updatePosition(int x, int y, boolean animate) {
+ PropertyAnimator.setProperty(mView, AnimatableProperty.Y, y, CLOCK_ANIMATION_PROPERTIES,
+ animate);
+
+ if (mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
+ // reset any prior movement
+ PropertyAnimator.setProperty(mView, AnimatableProperty.X, 0,
+ CLOCK_ANIMATION_PROPERTIES, animate);
+
+ mKeyguardClockSwitchController.updatePosition(x, CLOCK_ANIMATION_PROPERTIES, animate);
+ } else {
+ // reset any prior movement
+ mKeyguardClockSwitchController.updatePosition(0, CLOCK_ANIMATION_PROPERTIES, animate);
+
+ PropertyAnimator.setProperty(mView, AnimatableProperty.X, x,
+ CLOCK_ANIMATION_PROPERTIES, animate);
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 0e6bc24..31b0701 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -289,6 +289,8 @@
private final DevicePolicyManager mDevicePolicyManager;
private final BroadcastDispatcher mBroadcastDispatcher;
private boolean mLogoutEnabled;
+ // cached value to avoid IPCs
+ private boolean mIsUdfpsEnrolled;
// If the user long pressed the lock icon, disabling face auth for the current session.
private boolean mLockIconPressed;
private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -1857,7 +1859,15 @@
private void updateLockScreenMode() {
mLockScreenMode = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.SHOW_NEW_LOCKSCREEN, mAuthController.isUdfpsEnrolled() ? 1 : 0);
+ Settings.Global.SHOW_NEW_LOCKSCREEN,
+ isUdfpsEnrolled() ? 1 : 0);
+ }
+
+ private void updateUdfpsEnrolled(int userId) {
+ mIsUdfpsEnrolled = mAuthController.isUdfpsEnrolled(userId);
+ }
+ public boolean isUdfpsEnrolled() {
+ return mIsUdfpsEnrolled;
}
private final UserSwitchObserver mUserSwitchObserver = new UserSwitchObserver() {
@@ -2098,6 +2108,7 @@
}
if (DEBUG) Log.v(TAG, "startListeningForFingerprint()");
int userId = getCurrentUser();
+ updateUdfpsEnrolled(userId);
if (isUnlockWithFingerprintPossible(userId)) {
if (mFingerprintCancelSignal != null) {
mFingerprintCancelSignal.cancel();
@@ -3069,6 +3080,7 @@
+ " expected=" + (shouldListenForFingerprint() ? 1 : 0));
pw.println(" strongAuthFlags=" + Integer.toHexString(strongAuthFlags));
pw.println(" trustManaged=" + getUserTrustIsManaged(userId));
+ pw.println(" udfpsEnrolled=" + isUdfpsEnrolled());
}
if (mFaceManager != null && mFaceManager.isHardwareDetected()) {
final int userId = ActivityManager.getCurrentUser();
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 8147f66..d3ac9ac 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -89,6 +89,7 @@
import com.android.systemui.settings.UserTracker;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
+import com.android.systemui.util.settings.SecureSettings;
import java.util.ArrayList;
import java.util.List;
@@ -120,6 +121,7 @@
private final BroadcastDispatcher mBroadcastDispatcher;
private final Handler mMainHandler;
private final TunerService mTunerService;
+ private final SecureSettings mSecureSettings;
private DisplayManager.DisplayListener mDisplayListener;
private CameraAvailabilityListener mCameraListener;
private final UserTracker mUserTracker;
@@ -199,11 +201,13 @@
@Inject
public ScreenDecorations(Context context,
@Main Handler handler,
+ SecureSettings secureSettings,
BroadcastDispatcher broadcastDispatcher,
TunerService tunerService,
UserTracker userTracker) {
super(context);
mMainHandler = handler;
+ mSecureSettings = secureSettings;
mBroadcastDispatcher = broadcastDispatcher;
mTunerService = tunerService;
mUserTracker = userTracker;
@@ -309,7 +313,7 @@
// Watch color inversion and invert the overlay as needed.
if (mColorInversionSetting == null) {
- mColorInversionSetting = new SecureSetting(mContext, mHandler,
+ mColorInversionSetting = new SecureSetting(mSecureSettings, mHandler,
Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
mUserTracker.getUserId()) {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index b30103e..17bb40e 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -108,12 +108,14 @@
.setPip(mWMComponent.getPip())
.setSplitScreen(mWMComponent.getSplitScreen())
.setOneHanded(mWMComponent.getOneHanded())
+ .setBubbles(mWMComponent.getBubbles())
.setShellDump(mWMComponent.getShellDump());
} else {
// TODO: Call on prepareSysUIComponentBuilder but not with real components.
builder = builder.setPip(Optional.ofNullable(null))
.setSplitScreen(Optional.ofNullable(null))
.setOneHanded(Optional.ofNullable(null))
+ .setBubbles(Optional.ofNullable(null))
.setShellDump(Optional.ofNullable(null));
}
mSysUIComponent = builder
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index 98424be..724d197 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -146,6 +146,13 @@
}
@Override
+ public void onPerformScaleAction(int displayId, float scale) {
+ if (mWindowMagnificationConnectionImpl != null) {
+ mWindowMagnificationConnectionImpl.onPerformScaleAction(displayId, scale);
+ }
+ }
+
+ @Override
public void requestWindowMagnificationConnection(boolean connect) {
if (connect) {
setWindowMagnificationConnection();
@@ -247,5 +254,15 @@
}
}
}
+
+ void onPerformScaleAction(int displayId, float scale) {
+ if (mConnectionCallback != null) {
+ try {
+ mConnectionCallback.onPerformScaleAction(displayId, scale);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to inform performing scale action", e);
+ }
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index fd89baa..87dc6a5 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -719,12 +719,14 @@
private boolean performA11yAction(int action) {
if (action == R.id.accessibility_action_zoom_in) {
final float scale = mScale + A11Y_CHANGE_SCALE_DIFFERENCE;
- setScale(A11Y_ACTION_SCALE_RANGE.clamp(scale));
+ mWindowMagnifierCallback.onPerformScaleAction(mDisplayId,
+ A11Y_ACTION_SCALE_RANGE.clamp(scale));
return true;
}
if (action == R.id.accessibility_action_zoom_out) {
final float scale = mScale - A11Y_CHANGE_SCALE_DIFFERENCE;
- setScale(A11Y_ACTION_SCALE_RANGE.clamp(scale));
+ mWindowMagnifierCallback.onPerformScaleAction(mDisplayId,
+ A11Y_ACTION_SCALE_RANGE.clamp(scale));
return true;
}
if (action == R.id.accessibility_action_move_up) {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java
index e405a89..fb1d1b6 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java
@@ -37,4 +37,13 @@
* @param sourceBounds The magnified bounds in screen coordinates.
*/
void onSourceBoundsChanged(int displayId, Rect sourceBounds);
+
+ /**
+ * Called when the accessibility action of scale requests to be performed.
+ * It is invoked from System UI. And the action is provided by the mirror window.
+ *
+ * @param displayId The logical display id.
+ * @param scale the target scale, or {@link Float#NaN} to leave unchanged
+ */
+ void onPerformScaleAction(int displayId, float scale);
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index c72bc25..a6b1b90 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -56,6 +56,7 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
+import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
@@ -81,6 +82,7 @@
@Nullable private final List<FingerprintSensorPropertiesInternal> mFpProps;
@Nullable private final List<FaceSensorPropertiesInternal> mFaceProps;
+ @Nullable private final List<FingerprintSensorPropertiesInternal> mUdfpsProps;
// TODO: These should just be saved from onSaveState
private SomeArgs mCurrentDialogArgs;
@@ -314,6 +316,16 @@
: null;
mFaceProps = mFaceManager != null ? mFaceManager.getSensorPropertiesInternal() : null;
+ List<FingerprintSensorPropertiesInternal> udfpsProps = new ArrayList<>();
+ if (mFpProps != null) {
+ for (FingerprintSensorPropertiesInternal props : mFpProps) {
+ if (props.isAnyUdfpsType()) {
+ udfpsProps.add(props);
+ }
+ }
+ }
+ mUdfpsProps = !udfpsProps.isEmpty() ? udfpsProps : null;
+
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
@@ -326,15 +338,9 @@
mCommandQueue.addCallback(this);
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
- if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) {
- final List<FingerprintSensorPropertiesInternal> fingerprintSensorProperties =
- mFingerprintManager.getSensorPropertiesInternal();
- for (FingerprintSensorPropertiesInternal props : fingerprintSensorProperties) {
- if (props.isAnyUdfpsType()) {
- mUdfpsController = mUdfpsControllerFactory.get();
- break;
- }
- }
+ if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()
+ && mUdfpsProps != null) {
+ mUdfpsController = mUdfpsControllerFactory.get();
}
try {
@@ -484,12 +490,14 @@
}
/**
- * Whether the current user has a UDFP enrolled.
+ * Whether the passed userId has enrolled UDFPS.
*/
- public boolean isUdfpsEnrolled() {
- // TODO: (b/171392825) right now only checks whether the UDFPS sensor exists on this device
- // but not whether user has enrolled or not
- return mUdfpsController != null;
+ public boolean isUdfpsEnrolled(int userId) {
+ if (mUdfpsController == null) {
+ return false;
+ }
+
+ return mFingerprintManager.hasEnrolledTemplatesForAnySensor(userId, mUdfpsProps);
}
private void showDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
deleted file mode 100644
index ffb650d6..0000000
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.bubbles;
-
-import static android.app.Notification.EXTRA_MESSAGES;
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC;
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_MANIFEST;
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED;
-
-import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_EXPERIMENTS;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.Person;
-import android.content.Context;
-import android.content.pm.LauncherApps;
-import android.content.pm.ShortcutInfo;
-import android.graphics.Color;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.Log;
-
-import com.android.internal.graphics.ColorUtils;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.ContrastColorUtil;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.people.PeopleHubNotificationListenerKt;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Common class for experiments controlled via secure settings.
- */
-public class BubbleExperimentConfig {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleController" : TAG_BUBBLES;
-
- private static final int BUBBLE_HEIGHT = 10000;
-
- private static final String ALLOW_ANY_NOTIF_TO_BUBBLE = "allow_any_notif_to_bubble";
- private static final boolean ALLOW_ANY_NOTIF_TO_BUBBLE_DEFAULT = false;
-
- private static final String ALLOW_MESSAGE_NOTIFS_TO_BUBBLE = "allow_message_notifs_to_bubble";
- private static final boolean ALLOW_MESSAGE_NOTIFS_TO_BUBBLE_DEFAULT = false;
-
- private static final String ALLOW_SHORTCUTS_TO_BUBBLE = "allow_shortcuts_to_bubble";
- private static final boolean ALLOW_SHORTCUT_TO_BUBBLE_DEFAULT = false;
-
- private static final String WHITELISTED_AUTO_BUBBLE_APPS = "whitelisted_auto_bubble_apps";
-
- /**
- * When true, if a notification has the information necessary to bubble (i.e. valid
- * contentIntent and an icon or image), then a {@link android.app.Notification.BubbleMetadata}
- * object will be created by the system and added to the notification.
- * <p>
- * This does not produce a bubble, only adds the metadata based on the notification info.
- */
- static boolean allowAnyNotifToBubble(Context context) {
- return Settings.Secure.getInt(context.getContentResolver(),
- ALLOW_ANY_NOTIF_TO_BUBBLE,
- ALLOW_ANY_NOTIF_TO_BUBBLE_DEFAULT ? 1 : 0) != 0;
- }
-
- /**
- * Same as {@link #allowAnyNotifToBubble(Context)} except it filters for notifications that
- * are using {@link Notification.MessagingStyle} and have remote input.
- */
- static boolean allowMessageNotifsToBubble(Context context) {
- return Settings.Secure.getInt(context.getContentResolver(),
- ALLOW_MESSAGE_NOTIFS_TO_BUBBLE,
- ALLOW_MESSAGE_NOTIFS_TO_BUBBLE_DEFAULT ? 1 : 0) != 0;
- }
-
- /**
- * When true, if the notification is able to bubble via {@link #allowAnyNotifToBubble(Context)}
- * or {@link #allowMessageNotifsToBubble(Context)} or via normal BubbleMetadata, then a new
- * BubbleMetadata object is constructed based on the shortcut info.
- * <p>
- * This does not produce a bubble, only adds the metadata based on shortcut info.
- */
- static boolean useShortcutInfoToBubble(Context context) {
- return Settings.Secure.getInt(context.getContentResolver(),
- ALLOW_SHORTCUTS_TO_BUBBLE,
- ALLOW_SHORTCUT_TO_BUBBLE_DEFAULT ? 1 : 0) != 0;
- }
-
- /**
- * Returns whether the provided package is whitelisted to bubble.
- */
- static boolean isPackageWhitelistedToAutoBubble(Context context, String packageName) {
- String unsplitList = Settings.Secure.getString(context.getContentResolver(),
- WHITELISTED_AUTO_BUBBLE_APPS);
- if (unsplitList != null) {
- // We expect the list to be separated by commas and no white space (but we trim in case)
- String[] packageList = unsplitList.split(",");
- for (int i = 0; i < packageList.length; i++) {
- if (packageList[i].trim().equals(packageName)) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * If {@link #allowAnyNotifToBubble(Context)} is true, this method creates and adds
- * {@link android.app.Notification.BubbleMetadata} to the notification entry as long as
- * the notification has necessary info for BubbleMetadata.
- *
- * @return whether an adjustment was made.
- */
- static boolean adjustForExperiments(Context context, NotificationEntry entry,
- boolean previouslyUserCreated, boolean userBlocked) {
- Notification.BubbleMetadata metadata = null;
- boolean addedMetadata = false;
- boolean whiteListedToAutoBubble =
- isPackageWhitelistedToAutoBubble(context, entry.getSbn().getPackageName());
-
- Notification notification = entry.getSbn().getNotification();
- boolean isMessage = Notification.MessagingStyle.class.equals(
- notification.getNotificationStyle());
- boolean bubbleNotifForExperiment = (isMessage && allowMessageNotifsToBubble(context))
- || allowAnyNotifToBubble(context);
-
- boolean useShortcutInfo = useShortcutInfoToBubble(context);
- String shortcutId = entry.getSbn().getNotification().getShortcutId();
-
- boolean hasMetadata = entry.getBubbleMetadata() != null;
- if ((!hasMetadata && (previouslyUserCreated || bubbleNotifForExperiment))
- || useShortcutInfo) {
- if (DEBUG_EXPERIMENTS) {
- Log.d(TAG, "Adjusting " + entry.getKey() + " for bubble experiment."
- + " allowMessages=" + allowMessageNotifsToBubble(context)
- + " isMessage=" + isMessage
- + " allowNotifs=" + allowAnyNotifToBubble(context)
- + " useShortcutInfo=" + useShortcutInfo
- + " previouslyUserCreated=" + previouslyUserCreated);
- }
- }
-
- if (useShortcutInfo && shortcutId != null) {
- // We don't actually get anything useful from ShortcutInfo so just check existence
- ShortcutInfo info = getShortcutInfo(context, entry.getSbn().getPackageName(),
- entry.getSbn().getUser(), shortcutId);
- if (info != null) {
- metadata = createForShortcut(shortcutId);
- }
-
- // Replace existing metadata with shortcut, or we're bubbling for experiment
- boolean shouldBubble = entry.getBubbleMetadata() != null
- || bubbleNotifForExperiment
- || previouslyUserCreated;
- if (shouldBubble && metadata != null) {
- if (DEBUG_EXPERIMENTS) {
- Log.d(TAG, "Adding experimental shortcut bubble for: " + entry.getKey());
- }
- entry.setBubbleMetadata(metadata);
- addedMetadata = true;
- }
- }
-
- // Didn't get metadata from a shortcut & we're bubbling for experiment
- if (entry.getBubbleMetadata() == null
- && (bubbleNotifForExperiment || previouslyUserCreated)) {
- metadata = createFromNotif(context, entry);
- if (metadata != null) {
- if (DEBUG_EXPERIMENTS) {
- Log.d(TAG, "Adding experimental notification bubble for: " + entry.getKey());
- }
- entry.setBubbleMetadata(metadata);
- addedMetadata = true;
- }
- }
-
- boolean bubbleForWhitelist = !userBlocked
- && whiteListedToAutoBubble
- && (addedMetadata || hasMetadata);
- if ((previouslyUserCreated && addedMetadata) || bubbleForWhitelist) {
- // Update to a previous bubble (or new autobubble), set its flag now.
- if (DEBUG_EXPERIMENTS) {
- Log.d(TAG, "Setting FLAG_BUBBLE for: " + entry.getKey());
- }
- entry.setFlagBubble(true);
- return true;
- }
- return addedMetadata;
- }
-
- static Notification.BubbleMetadata createFromNotif(Context context, NotificationEntry entry) {
- Notification notification = entry.getSbn().getNotification();
- final PendingIntent intent = notification.contentIntent;
- Icon icon = null;
- // Use the icon of the person if available
- List<Person> personList = getPeopleFromNotification(entry);
- if (personList.size() > 0) {
- final Person person = personList.get(0);
- if (person != null) {
- icon = person.getIcon();
- if (icon == null) {
- // Lets try and grab the icon constructed by the layout
- Drawable d = PeopleHubNotificationListenerKt.extractAvatarFromRow(entry);
- if (d instanceof BitmapDrawable) {
- icon = Icon.createWithBitmap(((BitmapDrawable) d).getBitmap());
- }
- }
- }
- }
- if (icon == null) {
- boolean shouldTint = notification.getLargeIcon() == null;
- icon = shouldTint
- ? notification.getSmallIcon()
- : notification.getLargeIcon();
- if (shouldTint) {
- int notifColor = entry.getSbn().getNotification().color;
- notifColor = ColorUtils.setAlphaComponent(notifColor, 255);
- notifColor = ContrastColorUtil.findContrastColor(notifColor, Color.WHITE,
- true /* findFg */, 3f);
- icon.setTint(notifColor);
- }
- }
- if (intent != null) {
- return new Notification.BubbleMetadata.Builder(intent, icon)
- .setDesiredHeight(BUBBLE_HEIGHT)
- .build();
- }
- return null;
- }
-
- static Notification.BubbleMetadata createForShortcut(String shortcutId) {
- return new Notification.BubbleMetadata.Builder(shortcutId)
- .setDesiredHeight(BUBBLE_HEIGHT)
- .build();
- }
-
- static ShortcutInfo getShortcutInfo(Context context, String packageName, UserHandle user,
- String shortcutId) {
- LauncherApps launcherAppService =
- (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
- LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery();
- if (packageName != null) {
- query.setPackage(packageName);
- }
- if (shortcutId != null) {
- query.setShortcutIds(Arrays.asList(shortcutId));
- }
- query.setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST);
- List<ShortcutInfo> shortcuts = launcherAppService.getShortcuts(query, user);
- return shortcuts != null && shortcuts.size() > 0
- ? shortcuts.get(0)
- : null;
- }
-
- static List<Person> getPeopleFromNotification(NotificationEntry entry) {
- Bundle extras = entry.getSbn().getNotification().extras;
- ArrayList<Person> personList = new ArrayList<>();
- if (extras == null) {
- return personList;
- }
-
- List<Person> p = extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST);
-
- if (p != null) {
- personList.addAll(p);
- }
-
- if (Notification.MessagingStyle.class.equals(
- entry.getSbn().getNotification().getNotificationStyle())) {
- final Parcelable[] messages = extras.getParcelableArray(EXTRA_MESSAGES);
- if (!ArrayUtils.isEmpty(messages)) {
- for (Notification.MessagingStyle.Message message :
- Notification.MessagingStyle.Message
- .getMessagesFromBundleArray(messages)) {
- personList.add(message.getSenderPerson());
- }
- }
- }
- return personList;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
deleted file mode 100644
index 5a7e033..0000000
--- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.bubbles.dagger;
-
-import android.app.INotificationManager;
-import android.content.Context;
-import android.content.pm.LauncherApps;
-import android.os.Handler;
-import android.view.WindowManager;
-
-import androidx.annotation.Nullable;
-
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.bubbles.BubbleController;
-import com.android.systemui.bubbles.Bubbles;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.model.SysUiState;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.FeatureFlags;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
-import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.wmshell.BubblesManager;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.WindowManagerShellWrapper;
-import com.android.wm.shell.common.FloatingContentCoordinator;
-
-import java.util.Optional;
-
-import dagger.Module;
-import dagger.Provides;
-
-/** */
-@Module
-public interface BubbleModule {
-
- /**
- */
- @SysUISingleton
- @Provides
- static Bubbles newBubbleController(Context context,
- FloatingContentCoordinator floatingContentCoordinator,
- IStatusBarService statusBarService,
- WindowManager windowManager,
- WindowManagerShellWrapper windowManagerShellWrapper,
- LauncherApps launcherApps,
- UiEventLogger uiEventLogger,
- @Main Handler mainHandler,
- ShellTaskOrganizer organizer) {
- return BubbleController.create(context, null /* synchronizer */, floatingContentCoordinator,
- statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
- uiEventLogger, mainHandler, organizer);
- }
-
- /** Provides Optional of BubbleManager */
- @SysUISingleton
- @Provides
- static Optional<BubblesManager> provideBubblesManager(Context context,
- Optional<Bubbles> bubblesOptional,
- NotificationShadeWindowController notificationShadeWindowController,
- StatusBarStateController statusBarStateController, ShadeController shadeController,
- ConfigurationController configurationController,
- @Nullable IStatusBarService statusBarService, INotificationManager notificationManager,
- NotificationInterruptStateProvider interruptionStateProvider,
- ZenModeController zenModeController, NotificationLockscreenUserManager notifUserManager,
- NotificationGroupManagerLegacy groupManager, NotificationEntryManager entryManager,
- NotifPipeline notifPipeline, SysUiState sysUiState, FeatureFlags featureFlags,
- DumpManager dumpManager) {
- return Optional.ofNullable(BubblesManager.create(context, bubblesOptional,
- notificationShadeWindowController, statusBarStateController, shadeController,
- configurationController, statusBarService, notificationManager,
- interruptionStateProvider, zenModeController, notifUserManager,
- groupManager, entryManager, notifPipeline, sysUiState, featureFlags, dumpManager));
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
index 554d9cb..53383d6 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
@@ -22,9 +22,7 @@
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
import com.android.systemui.util.concurrency.GlobalConcurrencyModule;
-import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.animation.FlingAnimationUtils;
-import com.android.wm.shell.common.FloatingContentCoordinator;
import javax.inject.Singleton;
@@ -51,22 +49,6 @@
GlobalConcurrencyModule.class})
public class GlobalModule {
- // TODO(b/161980186): Currently only used by Bubbles, can move back to WMShellBaseModule once
- // Bubbles has migrated over
- @Singleton
- @Provides
- static FloatingContentCoordinator provideFloatingContentCoordinator() {
- return new FloatingContentCoordinator();
- }
-
- // TODO(b/161980186): Currently only used by Bubbles, can move back to WMShellBaseModule once
- // Bubbles has migrated over
- @Singleton
- @Provides
- static WindowManagerShellWrapper provideWindowManagerShellWrapper() {
- return new WindowManagerShellWrapper();
- }
-
// TODO(b/162923491): This should not be a singleton at all, the display metrics can change and
// callers should be creating a new builder on demand
@Singleton
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index d73633e..b94a68b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -27,6 +27,7 @@
import com.android.systemui.util.InjectionInflationController;
import com.android.wm.shell.ShellDump;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
@@ -64,6 +65,9 @@
Builder setOneHanded(Optional<OneHanded> o);
@BindsInstance
+ Builder setBubbles(Optional<Bubbles> b);
+
+ @BindsInstance
Builder setInputConsumerController(InputConsumerController i);
@BindsInstance
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index 1f6288a..c0013d8 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -24,7 +24,6 @@
import com.android.systemui.accessibility.SystemActions;
import com.android.systemui.accessibility.WindowMagnification;
import com.android.systemui.biometrics.AuthController;
-import com.android.systemui.bubbles.dagger.BubbleModule;
import com.android.systemui.globalactions.GlobalActionsComponent;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.dagger.KeyguardModule;
@@ -51,8 +50,7 @@
/**
* SystemUI objects that are injectable should go here.
*/
-@Module(includes = {RecentsModule.class, StatusBarModule.class, BubbleModule.class,
- KeyguardModule.class})
+@Module(includes = {RecentsModule.class, StatusBarModule.class, KeyguardModule.class})
public abstract class SystemUIBinder {
/** Inject into AuthController. */
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index a982ec5..780bb5b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -16,32 +16,49 @@
package com.android.systemui.dagger;
+import android.app.INotificationManager;
+import android.content.Context;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.statusbar.IStatusBarService;
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.BootCompleteCache;
import com.android.systemui.BootCompleteCacheImpl;
import com.android.systemui.appops.dagger.AppOpsModule;
import com.android.systemui.assist.AssistModule;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.controls.dagger.ControlsModule;
import com.android.systemui.demomode.dagger.DemoModeModule;
import com.android.systemui.doze.dagger.DozeComponent;
+import com.android.systemui.dump.DumpManager;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.log.dagger.LogModule;
import com.android.systemui.model.SysUiState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.power.dagger.PowerModule;
import com.android.systemui.recents.Recents;
import com.android.systemui.screenshot.dagger.ScreenshotModule;
import com.android.systemui.settings.dagger.SettingsModule;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.people.PeopleHubModule;
import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
+import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.policy.dagger.SmartRepliesInflationModule;
import com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule;
import com.android.systemui.tuner.dagger.TunerModule;
@@ -53,6 +70,10 @@
import com.android.systemui.util.time.SystemClock;
import com.android.systemui.util.time.SystemClockImpl;
import com.android.systemui.volume.dagger.VolumeModule;
+import com.android.systemui.wmshell.BubblesManager;
+import com.android.wm.shell.bubbles.Bubbles;
+
+import java.util.Optional;
import dagger.Binds;
import dagger.BindsOptionalOf;
@@ -126,10 +147,28 @@
@BindsOptionalOf
abstract StatusBar optionalStatusBar();
- @BindsOptionalOf
- abstract Bubbles optionalBubbles();
-
@SysUISingleton
@Binds
abstract SystemClock bindSystemClock(SystemClockImpl systemClock);
+
+ /** Provides Optional of BubbleManager */
+ @SysUISingleton
+ @Provides
+ static Optional<BubblesManager> provideBubblesManager(Context context,
+ Optional<Bubbles> bubblesOptional,
+ NotificationShadeWindowController notificationShadeWindowController,
+ StatusBarStateController statusBarStateController, ShadeController shadeController,
+ ConfigurationController configurationController,
+ @Nullable IStatusBarService statusBarService, INotificationManager notificationManager,
+ NotificationInterruptStateProvider interruptionStateProvider,
+ ZenModeController zenModeController, NotificationLockscreenUserManager notifUserManager,
+ NotificationGroupManagerLegacy groupManager, NotificationEntryManager entryManager,
+ NotifPipeline notifPipeline, SysUiState sysUiState, FeatureFlags featureFlags,
+ DumpManager dumpManager) {
+ return Optional.ofNullable(BubblesManager.create(context, bubblesOptional,
+ notificationShadeWindowController, statusBarStateController, shadeController,
+ configurationController, statusBarService, notificationManager,
+ interruptionStateProvider, zenModeController, notifUserManager,
+ groupManager, entryManager, notifPipeline, sysUiState, featureFlags, dumpManager));
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index 6635286..8f3d8ea 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -21,6 +21,7 @@
import com.android.wm.shell.ShellDump;
import com.android.wm.shell.ShellInit;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
@@ -64,13 +65,11 @@
InputConsumerController getInputConsumerController();
// TODO(b/162923491): To be removed once Bubbles migrates over to the Shell
-
@WMSingleton
ShellTaskOrganizer getShellTaskOrganizer();
// TODO(b/162923491): We currently pass the instances through to SysUI, but that may change
// depending on the threading mechanism we go with
-
@WMSingleton
Optional<OneHanded> getOneHanded();
@@ -79,4 +78,7 @@
@WMSingleton
Optional<SplitScreen> getSplitScreen();
+
+ @WMSingleton
+ Optional<Bubbles> getBubbles();
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index f07e5af..ebfce66 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -44,6 +44,7 @@
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
import com.android.internal.logging.nano.MetricsProto;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.plugins.SensorManagerPlugin;
import com.android.systemui.statusbar.phone.DozeParameters;
@@ -156,7 +157,7 @@
findSensorWithType(config.udfpsLongPressSensorType()),
"doze_pulse_on_auth",
true /* settingDef */,
- authController.isUdfpsEnrolled() /* configured */,
+ authController.isUdfpsEnrolled(KeyguardUpdateMonitor.getCurrentUser()),
DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS,
true /* reports touch coordinates */,
true /* touchscreen */,
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index d26f7ab..0d5faff 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -22,6 +22,7 @@
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.text.SpannableString;
+import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.View;
@@ -45,6 +46,7 @@
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private ViewGroup mConnectedItem;
+ private boolean mInclueDynamicGroup;
public MediaOutputAdapter(MediaOutputController controller) {
super(controller);
@@ -61,9 +63,21 @@
@Override
public void onBindViewHolder(@NonNull MediaDeviceBaseViewHolder viewHolder, int position) {
final int size = mController.getMediaDevices().size();
- if (mController.isZeroMode() && position == size) {
+ if (position == size && mController.isZeroMode()) {
viewHolder.onBind(CUSTOMIZED_ITEM_PAIR_NEW, false /* topMargin */,
true /* bottomMargin */);
+ } else if (mInclueDynamicGroup) {
+ if (position == 0) {
+ viewHolder.onBind(CUSTOMIZED_ITEM_DYNAMIC_GROUP, true /* topMargin */,
+ false /* bottomMargin */);
+ } else {
+ // When group item is added at the first(position == 0), devices will be added from
+ // the second item(position == 1). It means that the index of device list starts
+ // from "position - 1".
+ viewHolder.onBind(((List<MediaDevice>) (mController.getMediaDevices()))
+ .get(position - 1),
+ false /* topMargin */, position == size /* bottomMargin */);
+ }
} else if (position < size) {
viewHolder.onBind(((List<MediaDevice>) (mController.getMediaDevices())).get(position),
position == 0 /* topMargin */, position == (size - 1) /* bottomMargin */);
@@ -74,8 +88,9 @@
@Override
public int getItemCount() {
- if (mController.isZeroMode()) {
- // Add extra one for "pair new"
+ mInclueDynamicGroup = mController.getSelectedMediaDevice().size() > 1;
+ if (mController.isZeroMode() || mInclueDynamicGroup) {
+ // Add extra one for "pair new" or dynamic group
return mController.getMediaDevices().size() + 1;
}
return mController.getMediaDevices().size();
@@ -107,7 +122,7 @@
@Override
void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin) {
super.onBind(device, topMargin, bottomMargin);
- final boolean currentlyConnected = isCurrentlyConnected(device);
+ final boolean currentlyConnected = !mInclueDynamicGroup && isCurrentlyConnected(device);
if (currentlyConnected) {
mConnectedItem = mContainerLayout;
}
@@ -167,6 +182,22 @@
Utils.getColorAccentDefaultColor(mContext), PorterDuff.Mode.SRC_IN));
mTitleIcon.setImageDrawable(d);
mContainerLayout.setOnClickListener(v -> onItemClick(CUSTOMIZED_ITEM_PAIR_NEW));
+ } else if (customizedItem == CUSTOMIZED_ITEM_DYNAMIC_GROUP) {
+ mConnectedItem = mContainerLayout;
+ mBottomDivider.setVisibility(View.GONE);
+ mCheckBox.setVisibility(View.GONE);
+ mDivider.setVisibility(View.VISIBLE);
+ mDivider.setTransitionAlpha(1);
+ mAddIcon.setVisibility(View.VISIBLE);
+ mAddIcon.setTransitionAlpha(1);
+ mAddIcon.setOnClickListener(v -> onEndItemClick());
+ mTitleIcon.setImageDrawable(getSpeakerDrawable());
+ final CharSequence sessionName = mController.getSessionName();
+ final CharSequence title = TextUtils.isEmpty(sessionName)
+ ? mContext.getString(R.string.media_output_dialog_group) : sessionName;
+ setTwoLineLayout(title, true /* bFocused */, true /* showSeekBar */,
+ false /* showProgressBar */, false /* showSubtitle */);
+ initSessionSeekbar();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index 536b759..f1d4804 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -19,7 +19,11 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
@@ -35,6 +39,7 @@
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
+import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.media.MediaDevice;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -47,6 +52,7 @@
static final int CUSTOMIZED_ITEM_PAIR_NEW = 1;
static final int CUSTOMIZED_ITEM_GROUP = 2;
+ static final int CUSTOMIZED_ITEM_DYNAMIC_GROUP = 3;
final MediaOutputController mController;
@@ -223,6 +229,34 @@
});
}
+ void initSessionSeekbar() {
+ mSeekBar.setMax(mController.getSessionVolumeMax());
+ mSeekBar.setMin(0);
+ final int currentVolume = mController.getSessionVolume();
+ if (mSeekBar.getProgress() != currentVolume) {
+ mSeekBar.setProgress(currentVolume);
+ }
+ mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ if (!fromUser) {
+ return;
+ }
+ mController.adjustSessionVolume(progress);
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ mIsDragging = true;
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ mIsDragging = false;
+ }
+ });
+ }
+
void playSwitchingAnim(@NonNull View from, @NonNull View to) {
final float delta = (float) (mContext.getResources().getDimensionPixelSize(
R.dimen.media_output_dialog_title_anim_y_delta));
@@ -274,5 +308,15 @@
}
});
}
+
+ Drawable getSpeakerDrawable() {
+ final Drawable drawable = mContext.getDrawable(R.drawable.ic_speaker_group_black_24dp)
+ .mutate();
+ final ColorStateList list = mContext.getResources().getColorStateList(
+ R.color.advanced_icon_color, mContext.getTheme());
+ drawable.setColorFilter(new PorterDuffColorFilter(list.getDefaultColor(),
+ PorterDuff.Mode.SRC_IN));
+ return BluetoothUtils.buildAdvancedDrawable(mContext, drawable);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
index ceb4495..24e076b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
@@ -16,22 +16,17 @@
package com.android.systemui.media.dialog;
-import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.SeekBar;
import androidx.annotation.NonNull;
-import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.media.MediaDevice;
import com.android.systemui.R;
@@ -155,34 +150,6 @@
}
}
- private void initSessionSeekbar() {
- mSeekBar.setMax(mController.getSessionVolumeMax());
- mSeekBar.setMin(0);
- final int currentVolume = mController.getSessionVolume();
- if (mSeekBar.getProgress() != currentVolume) {
- mSeekBar.setProgress(currentVolume);
- }
- mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- if (!fromUser) {
- return;
- }
- mController.adjustSessionVolume(progress);
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- mIsDragging = true;
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- mIsDragging = false;
- }
- });
- }
-
private Drawable getDisabledCheckboxDrawable() {
final Drawable drawable = mContext.getDrawable(R.drawable.ic_check_box_blue_24dp)
.mutate();
@@ -198,16 +165,6 @@
return drawable;
}
- private Drawable getSpeakerDrawable() {
- final Drawable drawable = mContext.getDrawable(R.drawable.ic_speaker_group_black_24dp)
- .mutate();
- final ColorStateList list = mContext.getResources().getColorStateList(
- R.color.advanced_icon_color, mContext.getTheme());
- drawable.setColorFilter(new PorterDuffColorFilter(list.getDefaultColor(),
- PorterDuff.Mode.SRC_IN));
- return BluetoothUtils.buildAdvancedDrawable(mContext, drawable);
- }
-
private boolean isDeviceIncluded(List<MediaDevice> deviceList, MediaDevice targetDevice) {
for (MediaDevice device : deviceList) {
if (TextUtils.equals(device.getId(), targetDevice.getId())) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index cfcceb2..619729e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -57,7 +57,7 @@
protected TextView mDetailDoneButton;
private QSDetailClipper mClipper;
private DetailAdapter mDetailAdapter;
- private QSPanel mQsPanel;
+ private QSPanelController mQsPanelController;
protected View mQsDetailHeader;
protected TextView mQsDetailHeaderTitle;
@@ -114,19 +114,20 @@
public void onClick(View v) {
announceForAccessibility(
mContext.getString(R.string.accessibility_desc_quick_settings));
- mQsPanel.closeDetail();
+ mQsPanelController.closeDetail();
}
};
mDetailDoneButton.setOnClickListener(doneListener);
}
/** */
- public void setQsPanel(QSPanel panel, QuickStatusBarHeader header, QSFooter footer) {
- mQsPanel = panel;
+ public void setQsPanel(QSPanelController panelController, QuickStatusBarHeader header,
+ QSFooter footer) {
+ mQsPanelController = panelController;
mHeader = header;
mFooter = footer;
mHeader.setCallback(mQsPanelCallback);
- mQsPanel.setCallback(mQsPanelCallback);
+ mQsPanelController.setCallback(mQsPanelCallback);
}
public void setHost(QSTileHost host) {
@@ -221,7 +222,7 @@
listener = mTeardownDetailWhenDone;
mHeader.setVisibility(View.VISIBLE);
mFooter.setVisibility(View.VISIBLE);
- mQsPanel.setGridContentVisibility(true);
+ mQsPanelController.setGridContentVisibility(true);
mQsPanelCallback.onScanStateChanged(false);
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
@@ -362,7 +363,7 @@
public void onAnimationEnd(Animator animation) {
// Only hide content if still in detail state.
if (mDetailAdapter != null) {
- mQsPanel.setGridContentVisibility(false);
+ mQsPanelController.setGridContentVisibility(false);
mHeader.setVisibility(View.INVISIBLE);
mFooter.setVisibility(View.INVISIBLE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 1a7d366..e1bca4a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -38,7 +38,7 @@
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.customize.QSCustomizer;
+import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.dagger.QSFragmentComponent;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.StatusBarState;
@@ -69,7 +69,6 @@
private QSAnimator mQSAnimator;
private HeightListener mPanelView;
protected QuickStatusBarHeader mHeader;
- private QSCustomizer mQSCustomizer;
protected NonInterceptingScrollView mQSPanelScrollView;
private QSDetail mQSDetail;
private boolean mListening;
@@ -97,6 +96,7 @@
private float mLastHeaderTranslation;
private QSPanelController mQSPanelController;
private QuickQSPanelController mQuickQSPanelController;
+ private QSCustomizerController mQSCustomizerController;
@Inject
public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
@@ -148,16 +148,17 @@
mQSContainerImplController.init();
mContainer = mQSContainerImplController.getView();
- mQSDetail.setQsPanel(mQSPanelController.getView(), mHeader, mFooter);
+ mQSDetail.setQsPanel(mQSPanelController, mHeader, mFooter);
mQSAnimator = qsFragmentComponent.getQSAnimator();
- mQSCustomizer = view.findViewById(R.id.qs_customize);
- mQSCustomizer.setQs(this);
+ mQSCustomizerController = qsFragmentComponent.getQSCustomizerController();
+ mQSCustomizerController.init();
+ mQSCustomizerController.setQs(this);
if (savedInstanceState != null) {
setExpanded(savedInstanceState.getBoolean(EXTRA_EXPANDED));
setListening(savedInstanceState.getBoolean(EXTRA_LISTENING));
setEditLocation(view);
- mQSCustomizer.restoreInstanceState(savedInstanceState);
+ mQSCustomizerController.restoreInstanceState(savedInstanceState);
if (mQsExpanded) {
mQSPanelController.getTileLayout().restoreInstanceState(savedInstanceState);
}
@@ -181,7 +182,7 @@
if (mListening) {
setListening(false);
}
- mQSCustomizer.setQs(null);
+ mQSCustomizerController.setQs(null);
}
@Override
@@ -189,7 +190,7 @@
super.onSaveInstanceState(outState);
outState.putBoolean(EXTRA_EXPANDED, mQsExpanded);
outState.putBoolean(EXTRA_LISTENING, mListening);
- mQSCustomizer.saveInstanceState(outState);
+ mQSCustomizerController.saveInstanceState(outState);
if (mQsExpanded) {
mQSPanelController.getTileLayout().saveInstanceState(outState);
}
@@ -236,23 +237,22 @@
int[] loc = edit.getLocationOnScreen();
int x = loc[0] + edit.getWidth() / 2;
int y = loc[1] + edit.getHeight() / 2;
- mQSCustomizer.setEditLocation(x, y);
+ mQSCustomizerController.setEditLocation(x, y);
}
@Override
public void setContainer(ViewGroup container) {
if (container instanceof NotificationsQuickSettingsContainer) {
- mQSCustomizer.setContainer((NotificationsQuickSettingsContainer) container);
+ mQSCustomizerController.setContainer((NotificationsQuickSettingsContainer) container);
}
}
@Override
public boolean isCustomizing() {
- return mQSCustomizer.isCustomizing();
+ return mQSCustomizerController.isCustomizing();
}
public void setHost(QSTileHost qsh) {
- mQSPanelController.setCustomizer(mQSCustomizer);
mHeader.setQSPanel(mQSPanelController.getView());
mFooter.setQSPanel(mQSPanelController.getView());
mQSDetail.setHost(qsh);
@@ -325,13 +325,9 @@
return mQSPanelController.getView();
}
- public QSCustomizer getCustomizer() {
- return mQSCustomizer;
- }
-
@Override
public boolean isShowingDetail() {
- return mQSPanelController.isShowingCustomize() || mQSDetail.isShowingDetail();
+ return mQSCustomizerController.isCustomizing() || mQSDetail.isShowingDetail();
}
@Override
@@ -553,9 +549,10 @@
public void notifyCustomizeChanged() {
// The customize state changed, so our height changed.
mContainer.updateExpansion();
- mQSPanelScrollView.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE
+ mQSPanelScrollView.setVisibility(!mQSCustomizerController.isCustomizing() ? View.VISIBLE
: View.INVISIBLE);
- mFooter.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
+ mFooter.setVisibility(
+ !mQSCustomizerController.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
// Let the panel know the position changed and it needs to update where notifications
// and whatnot are.
mPanelView.onQsHeightChanged();
@@ -567,7 +564,7 @@
*/
@Override
public int getDesiredHeight() {
- if (mQSCustomizer.isCustomizing()) {
+ if (mQSCustomizerController.isCustomizing()) {
return getView().getHeight();
}
if (mQSDetail.isClosingDetail()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 76f2446..758e0c5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -46,7 +46,6 @@
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSTile;
-import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.settings.ToggleSliderView;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
@@ -56,7 +55,6 @@
import com.android.systemui.util.animation.DisappearParameters;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
@@ -84,7 +82,6 @@
private final H mHandler = new H();
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
- private QSTileRevealController mQsTileRevealController;
/** Whether or not the QS media player feature is enabled. */
protected boolean mUsingMediaPlayer;
private int mVisualMarginStart;
@@ -117,7 +114,6 @@
private int mVisualTilePadding;
private boolean mUsingHorizontalLayout;
- private QSCustomizer mCustomizePanel;
private Record mDetailRecord;
private BrightnessMirrorController mBrightnessMirrorController;
@@ -186,10 +182,6 @@
initMediaHostState();
}
- if (mRegularTileLayout instanceof PagedTileLayout) {
- mQsTileRevealController = new QSTileRevealController(mContext, this,
- (PagedTileLayout) mRegularTileLayout);
- }
mQSLogger.logAllTilesChangeListening(mListening, getDumpableTag(), "");
}
@@ -297,14 +289,6 @@
setMeasuredDimension(getMeasuredWidth(), height);
}
- public QSTileRevealController getQsTileRevealController() {
- return mQsTileRevealController;
- }
-
- public boolean isShowingCustomize() {
- return mCustomizePanel != null && mCustomizePanel.isCustomizing();
- }
-
@Override
protected void onDetachedFromWindow() {
if (mTileLayout != null) {
@@ -362,10 +346,6 @@
mCallback = callback;
}
- void setCustomizer(QSCustomizer customizer) {
- mCustomizePanel = customizer;
- }
-
/**
* Links the footer's page indicator, which is used in landscape orientation to save space.
*
@@ -608,12 +588,6 @@
}
}
- public void onCollapse() {
- if (mCustomizePanel != null && mCustomizePanel.isShown()) {
- mCustomizePanel.hide();
- }
- }
-
public void setExpanded(boolean expanded) {
if (mExpanded == expanded) return;
mQSLogger.logPanelExpanded(expanded, getDumpableTag());
@@ -684,10 +658,6 @@
return mExpanded;
}
- void updateRevealedTiles(Collection<QSTile> tiles) {
- mQsTileRevealController.updateRevealedTiles(tiles);
- }
-
void addTile(QSPanelControllerBase.TileRecord tileRecord) {
final QSTile.Callback callback = new QSTile.Callback() {
@Override
@@ -742,29 +712,7 @@
mTileLayout.removeTile(tileRecord);
}
- public void showEdit(final View v) {
- v.post(new Runnable() {
- @Override
- public void run() {
- if (mCustomizePanel != null) {
- if (!mCustomizePanel.isCustomizing()) {
- int[] loc = v.getLocationOnScreen();
- int x = loc[0] + v.getWidth() / 2;
- int y = loc[1] + v.getHeight() / 2;
- mCustomizePanel.show(x, y);
- }
- }
-
- }
- });
- }
-
- public void closeDetail() {
- if (mCustomizePanel != null && mCustomizePanel.isShown()) {
- // Treat this as a detail panel for now, to make things easy.
- mCustomizePanel.hide();
- return;
- }
+ void closeDetail() {
showDetail(false, mDetailRecord);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index f222b0d..e9670a9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -29,7 +29,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QSTile;
-import com.android.systemui.qs.customize.QSCustomizer;
+import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.settings.BrightnessController;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
@@ -44,6 +44,7 @@
public class QSPanelController extends QSPanelControllerBase<QSPanel> {
private final QSSecurityFooter mQsSecurityFooter;
private final TunerService mTunerService;
+ private final QSCustomizerController mQsCustomizerController;
private final BrightnessController mBrightnessController;
private final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener =
@@ -61,18 +62,26 @@
@Inject
QSPanelController(QSPanel view, QSSecurityFooter qsSecurityFooter, TunerService tunerService,
- QSTileHost qstileHost, DumpManager dumpManager,
- MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
+ QSTileHost qstileHost, QSCustomizerController qsCustomizerController,
+ QSTileRevealController.Factory qsTileRevealControllerFactory,
+ DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
BrightnessController.Factory brightnessControllerFactory) {
- super(view, qstileHost, metricsLogger, uiEventLogger, dumpManager);
+ super(view, qstileHost, qsCustomizerController, qsTileRevealControllerFactory,
+ metricsLogger, uiEventLogger, dumpManager);
mQsSecurityFooter = qsSecurityFooter;
mTunerService = tunerService;
+ mQsCustomizerController = qsCustomizerController;
mQsSecurityFooter.setHostEnvironment(qstileHost);
mBrightnessController = brightnessControllerFactory.create(
mView.findViewById(R.id.brightness_slider));
}
@Override
+ public void onInit() {
+ mQsCustomizerController.init();
+ }
+
+ @Override
protected void onViewAttached() {
super.onViewAttached();
mTunerService.addTunable(mView, QS_SHOW_BRIGHTNESS);
@@ -115,16 +124,6 @@
}
/** */
- public void setCustomizer(QSCustomizer customizer) {
- mView.setCustomizer(customizer);
- }
-
- /** */
- public boolean isShowingCustomize() {
- return mView.isShowingCustomize();
- }
-
- /** */
public void setVisibility(int visibility) {
mView.setVisibility(visibility);
}
@@ -148,11 +147,6 @@
}
/** */
- public QSTileRevealController getQsTileRevealController() {
- return mView.getQsTileRevealController();
- }
-
- /** */
public MediaHost getMediaHost() {
return mView.getMediaHost();
}
@@ -196,6 +190,23 @@
/** Start customizing the Quick Settings. */
public void showEdit(View view) {
- mView.showEdit(view);
+ view.post(() -> {
+ if (!mQsCustomizerController.isCustomizing()) {
+ int[] loc = view.getLocationOnScreen();
+ int x = loc[0] + view.getWidth() / 2;
+ int y = loc[1] + view.getHeight() / 2;
+ mQsCustomizerController.show(x, y, false);
+ }
+ });
+ }
+
+ /** */
+ public void setCallback(QSDetail.Callback qsPanelCallback) {
+ mView.setCallback(qsPanelCallback);
+ }
+
+ /** */
+ public void setGridContentVisibility(boolean visible) {
+ mView.setGridContentVisibility(visible);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 68a6cdc..0a4151b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -29,6 +29,7 @@
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTileView;
+import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.util.ViewController;
@@ -46,6 +47,8 @@
public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewController<T>
implements Dumpable{
protected final QSTileHost mHost;
+ private final QSCustomizerController mQsCustomizerController;
+ private final QSTileRevealController.Factory mQsTileRevealControllerFactory;
private final MediaHost mMediaHost;
private final MetricsLogger mMetricsLogger;
private final UiEventLogger mUiEventLogger;
@@ -53,6 +56,7 @@
protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
private int mLastOrientation;
+ private QSTileRevealController mQsTileRevealController;
private final QSHost.Callback mQSHostCallback = this::setTiles;
@@ -69,9 +73,13 @@
private String mCachedSpecs = "";
protected QSPanelControllerBase(T view, QSTileHost host,
+ QSCustomizerController qsCustomizerController,
+ QSTileRevealController.Factory qsTileRevealControllerFactory,
MetricsLogger metricsLogger, UiEventLogger uiEventLogger, DumpManager dumpManager) {
super(view);
mHost = host;
+ mQsCustomizerController = qsCustomizerController;
+ mQsTileRevealControllerFactory = qsTileRevealControllerFactory;
mMediaHost = mView.getMediaHost();
mMetricsLogger = metricsLogger;
mUiEventLogger = uiEventLogger;
@@ -80,6 +88,12 @@
@Override
protected void onViewAttached() {
+ QSPanel.QSTileLayout regularTileLayout = mView.createRegularTileLayout();
+ if (regularTileLayout instanceof PagedTileLayout) {
+ mQsTileRevealController = mQsTileRevealControllerFactory.create(
+ (PagedTileLayout) regularTileLayout);
+ }
+
mView.addOnConfigurationChangedListener(mOnConfigurationChangedListener);
mHost.addCallback(mQSHostCallback);
mMediaHost.addVisibilityChangeListener(aBoolean -> {
@@ -111,7 +125,7 @@
/** */
public void setTiles(Collection<QSTile> tiles, boolean collapsedView) {
if (!collapsedView) {
- mView.updateRevealedTiles(tiles);
+ mQsTileRevealController.updateRevealedTiles(tiles);
}
for (QSPanelControllerBase.TileRecord record : mRecords) {
mView.removeTile(record);
@@ -192,6 +206,10 @@
/** */
public void closeDetail() {
+ if (mQsCustomizerController.isShown()) {
+ mQsCustomizerController.hide();
+ return;
+ }
mView.closeDetail();
}
@@ -228,6 +246,10 @@
}
}
+ /** */
+ public QSTileRevealController getQsTileRevealController() {
+ return mQsTileRevealController;
+ }
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java
index 3d4a417..9414d0e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java
@@ -8,6 +8,7 @@
import com.android.systemui.Prefs;
import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.dagger.QSScope;
import java.util.Collection;
@@ -17,13 +18,13 @@
import javax.inject.Inject;
/** */
-@QSScope
public class QSTileRevealController {
private static final long QS_REVEAL_TILES_DELAY = 500L;
private final Context mContext;
private final QSPanel mQSPanel;
private final PagedTileLayout mPagedTileLayout;
+ private final QSCustomizerController mQsCustomizerController;
private final ArraySet<String> mTilesToReveal = new ArraySet<>();
private final Handler mHandler = new Handler();
@@ -38,12 +39,12 @@
});
}
};
-
- @Inject
- QSTileRevealController(Context context, QSPanel qsPanel, PagedTileLayout pagedTileLayout) {
+ QSTileRevealController(Context context, QSPanel qsPanel, PagedTileLayout pagedTileLayout,
+ QSCustomizerController qsCustomizerController) {
mContext = context;
mQSPanel = qsPanel;
mPagedTileLayout = pagedTileLayout;
+ mQsCustomizerController = qsCustomizerController;
}
public void setExpansion(float expansion) {
@@ -62,7 +63,7 @@
final Set<String> revealedTiles = Prefs.getStringSet(
mContext, QS_TILE_SPECS_REVEALED, Collections.EMPTY_SET);
- if (revealedTiles.isEmpty() || mQSPanel.isShowingCustomize()) {
+ if (revealedTiles.isEmpty() || mQsCustomizerController.isCustomizing()) {
// Do not reveal QS tiles the user has upon first load or those that they directly
// added through customization.
addTileSpecsToRevealed(tileSpecs);
@@ -79,4 +80,24 @@
revealedTiles.addAll(specs);
Prefs.putStringSet(mContext, QS_TILE_SPECS_REVEALED, revealedTiles);
}
+
+ /** TODO(b/168904199): Remove this once QSPanel has its rejection removed. */
+ @QSScope
+ static class Factory {
+ private final Context mContext;
+ private final QSPanel mQsPanel;
+ private final QSCustomizerController mQsCustomizerController;
+
+ @Inject
+ Factory(Context context, QSPanel qsPanel, QSCustomizerController qsCustomizerController) {
+ mContext = context;
+ mQsPanel = qsPanel;
+ mQsCustomizerController = qsCustomizerController;
+ }
+
+ QSTileRevealController create(PagedTileLayout pagedTileLayout) {
+ return new QSTileRevealController(mContext, mQsPanel, pagedTileLayout,
+ mQsCustomizerController);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index 97b6e99..a718271 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -23,6 +23,7 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -41,9 +42,12 @@
@Inject
QuickQSPanelController(QuickQSPanel view, TunerService tunerService, QSTileHost qsTileHost,
+ QSCustomizerController qsCustomizerController,
+ QSTileRevealController.Factory qsTileRevealControllerFactory,
MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
DumpManager dumpManager) {
- super(view, qsTileHost, metricsLogger, uiEventLogger, dumpManager);
+ super(view, qsTileHost, qsCustomizerController, qsTileRevealControllerFactory,
+ metricsLogger, uiEventLogger, dumpManager);
mTunerService = tunerService;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java b/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
index 3ee3e11..994da9a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
@@ -16,18 +16,17 @@
package com.android.systemui.qs;
-import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
-import android.provider.Settings.Secure;
import com.android.systemui.statusbar.policy.Listenable;
+import com.android.systemui.util.settings.SecureSettings;
/** Helper for managing a secure setting. **/
public abstract class SecureSetting extends ContentObserver implements Listenable {
private static final int DEFAULT = 0;
- private final Context mContext;
+ private SecureSettings mSecureSettings;
private final String mSettingName;
private boolean mListening;
@@ -36,19 +35,20 @@
protected abstract void handleValueChanged(int value, boolean observedChange);
- public SecureSetting(Context context, Handler handler, String settingName, int userId) {
+ public SecureSetting(SecureSettings secureSettings, Handler handler, String settingName,
+ int userId) {
super(handler);
- mContext = context;
+ mSecureSettings = secureSettings;
mSettingName = settingName;
mUserId = userId;
}
public int getValue() {
- return Secure.getIntForUser(mContext.getContentResolver(), mSettingName, DEFAULT, mUserId);
+ return mSecureSettings.getIntForUser(mSettingName, DEFAULT, mUserId);
}
public void setValue(int value) {
- Secure.putIntForUser(mContext.getContentResolver(), mSettingName, value, mUserId);
+ mSecureSettings.putIntForUser(mSettingName, value, mUserId);
}
@Override
@@ -57,10 +57,10 @@
mListening = listening;
if (listening) {
mObservedValue = getValue();
- mContext.getContentResolver().registerContentObserver(
- Secure.getUriFor(mSettingName), false, this, mUserId);
+ mSecureSettings.registerContentObserverForUser(
+ mSecureSettings.getUriFor(mSettingName), false, this, mUserId);
} else {
- mContext.getContentResolver().unregisterContentObserver(this);
+ mSecureSettings.unregisterContentObserver(this);
mObservedValue = DEFAULT;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 8097958..3291aa0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -20,41 +20,23 @@
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.res.Configuration;
-import android.os.Bundle;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.Menu;
-import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.Toolbar;
-import android.widget.Toolbar.OnMenuItemClickListener;
-import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.recyclerview.widget.DefaultItemAnimator;
-import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.UiEventLoggerImpl;
import com.android.systemui.R;
-import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.plugins.qs.QS;
-import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSDetailClipper;
-import com.android.systemui.qs.QSEditEvent;
-import com.android.systemui.qs.QSTileHost;
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.statusbar.policy.KeyguardStateController.Callback;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.inject.Inject;
/**
* Allows full-screen customization of QS, through show() and hide().
@@ -62,24 +44,16 @@
* This adds itself to the status bar window, so it can appear on top of quick settings and
* *someday* do fancy animations to get into/out of it.
*/
-public class QSCustomizer extends LinearLayout implements OnMenuItemClickListener {
+public class QSCustomizer extends LinearLayout {
- private static final int MENU_RESET = Menu.FIRST;
- private static final String EXTRA_QS_CUSTOMIZING = "qs_customizing";
- private static final String TAG = "QSCustomizer";
+ static final int MENU_RESET = Menu.FIRST;
+ static final String EXTRA_QS_CUSTOMIZING = "qs_customizing";
private final QSDetailClipper mClipper;
- private final LightBarController mLightBarController;
- private KeyguardStateController mKeyguardStateController;
- private final ScreenLifecycle mScreenLifecycle;
- private final TileQueryHelper mTileQueryHelper;
private final View mTransparentView;
- private final QSTileHost mHost;
private boolean isShown;
- private RecyclerView mRecyclerView;
- private TileAdapter mTileAdapter;
- private Toolbar mToolbar;
+ private final RecyclerView mRecyclerView;
private boolean mCustomizing;
private NotificationsQuickSettingsContainer mNotifQsContainer;
private QS mQs;
@@ -87,90 +61,47 @@
private int mY;
private boolean mOpening;
private boolean mIsShowingNavBackdrop;
- private UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
- @Inject
- public QSCustomizer(Context context, AttributeSet attrs,
- LightBarController lightBarController,
- KeyguardStateController keyguardStateController,
- ScreenLifecycle screenLifecycle,
- TileQueryHelper tileQueryHelper,
- QSTileHost qsTileHost,
- UiEventLogger uiEventLogger) {
+ public QSCustomizer(Context context, AttributeSet attrs) {
super(new ContextThemeWrapper(context, R.style.edit_theme), attrs);
LayoutInflater.from(getContext()).inflate(R.layout.qs_customize_panel_content, this);
mClipper = new QSDetailClipper(findViewById(R.id.customize_container));
- mToolbar = findViewById(com.android.internal.R.id.action_bar);
+ Toolbar toolbar = findViewById(com.android.internal.R.id.action_bar);
TypedValue value = new TypedValue();
mContext.getTheme().resolveAttribute(android.R.attr.homeAsUpIndicator, value, true);
- mToolbar.setNavigationIcon(
+ toolbar.setNavigationIcon(
getResources().getDrawable(value.resourceId, mContext.getTheme()));
- mToolbar.setNavigationOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- hide();
- }
- });
- mToolbar.setOnMenuItemClickListener(this);
- mToolbar.getMenu().add(Menu.NONE, MENU_RESET, 0,
+
+ toolbar.getMenu().add(Menu.NONE, MENU_RESET, 0,
mContext.getString(com.android.internal.R.string.reset));
- mToolbar.setTitle(R.string.qs_edit);
+ toolbar.setTitle(R.string.qs_edit);
mRecyclerView = findViewById(android.R.id.list);
mTransparentView = findViewById(R.id.customizer_transparent_view);
- mTileAdapter = new TileAdapter(getContext(), uiEventLogger);
- mTileQueryHelper = tileQueryHelper;
- mTileQueryHelper.setListener(mTileAdapter);
- mRecyclerView.setAdapter(mTileAdapter);
- mTileAdapter.getItemTouchHelper().attachToRecyclerView(mRecyclerView);
- GridLayoutManager layout = new GridLayoutManager(getContext(), 3) {
- @Override
- public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler,
- RecyclerView.State state, View host, AccessibilityNodeInfoCompat info) {
- // Do not read row and column every time it changes.
- }
- };
- layout.setSpanSizeLookup(mTileAdapter.getSizeLookup());
- mRecyclerView.setLayoutManager(layout);
- mRecyclerView.addItemDecoration(mTileAdapter.getItemDecoration());
- mRecyclerView.addItemDecoration(mTileAdapter.getMarginItemDecoration());
DefaultItemAnimator animator = new DefaultItemAnimator();
animator.setMoveDuration(TileAdapter.MOVE_DURATION);
mRecyclerView.setItemAnimator(animator);
- mLightBarController = lightBarController;
- mKeyguardStateController = keyguardStateController;
- mScreenLifecycle = screenLifecycle;
- mHost = qsTileHost;
- mTileAdapter.setHost(mHost);
- updateNavBackDrop(getResources().getConfiguration());
}
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- updateNavBackDrop(newConfig);
- updateResources();
- }
-
- private void updateResources() {
+ void updateResources() {
LayoutParams lp = (LayoutParams) mTransparentView.getLayoutParams();
lp.height = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.quick_qs_offset_height);
mTransparentView.setLayoutParams(lp);
}
- private void updateNavBackDrop(Configuration newConfig) {
+ void updateNavBackDrop(Configuration newConfig, LightBarController lightBarController) {
View navBackdrop = findViewById(R.id.nav_bar_background);
mIsShowingNavBackdrop = newConfig.smallestScreenWidthDp >= 600
|| newConfig.orientation != Configuration.ORIENTATION_LANDSCAPE;
if (navBackdrop != null) {
navBackdrop.setVisibility(mIsShowingNavBackdrop ? View.VISIBLE : View.GONE);
}
- updateNavColors();
+ updateNavColors(lightBarController);
}
- private void updateNavColors() {
- mLightBarController.setQsCustomizing(mIsShowingNavBackdrop && isShown);
+ void updateNavColors(LightBarController lightBarController) {
+ lightBarController.setQsCustomizing(mIsShowingNavBackdrop && isShown);
}
public void setContainer(NotificationsQuickSettingsContainer notificationsQsContainer) {
@@ -184,39 +115,30 @@
/** Animate and show QSCustomizer panel.
* @param x,y Location on screen of {@code edit} button to determine center of animation.
*/
- public void show(int x, int y) {
+ void show(int x, int y, TileAdapter tileAdapter) {
if (!isShown) {
- int containerLocation[] = findViewById(R.id.customize_container).getLocationOnScreen();
+ int[] containerLocation = findViewById(R.id.customize_container).getLocationOnScreen();
mX = x - containerLocation[0];
mY = y - containerLocation[1];
- mUiEventLogger.log(QSEditEvent.QS_EDIT_OPEN);
isShown = true;
mOpening = true;
- setTileSpecs();
setVisibility(View.VISIBLE);
- mClipper.animateCircularClip(mX, mY, true, mExpandAnimationListener);
- queryTiles();
+ mClipper.animateCircularClip(mX, mY, true, new ExpandAnimatorListener(tileAdapter));
mNotifQsContainer.setCustomizerAnimating(true);
mNotifQsContainer.setCustomizerShowing(true);
- mKeyguardStateController.addCallback(mKeyguardCallback);
- updateNavColors();
}
}
- public void showImmediately() {
+ void showImmediately() {
if (!isShown) {
setVisibility(VISIBLE);
mClipper.cancelAnimator();
mClipper.showBackground();
isShown = true;
- setTileSpecs();
setCustomizing(true);
- queryTiles();
mNotifQsContainer.setCustomizerAnimating(false);
mNotifQsContainer.setCustomizerShowing(true);
- mKeyguardStateController.addCallback(mKeyguardCallback);
- updateNavColors();
}
}
@@ -225,9 +147,6 @@
* {@link TileAdapter}.
*/
public void setContentPaddings(int paddingStart, int paddingEnd) {
- int halfMargin = mContext.getResources()
- .getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal) / 2;
- mTileAdapter.changeHalfMargin(halfMargin);
mRecyclerView.setPaddingRelative(
paddingStart,
mRecyclerView.getPaddingTop(),
@@ -236,22 +155,14 @@
);
}
- private void queryTiles() {
- mTileQueryHelper.queryTiles(mHost);
- }
-
- public void hide() {
- final boolean animate = mScreenLifecycle.getScreenState() != ScreenLifecycle.SCREEN_OFF;
+ /** Hide the customizer. */
+ public void hide(boolean animate) {
if (isShown) {
- mUiEventLogger.log(QSEditEvent.QS_EDIT_CLOSED);
isShown = false;
- mToolbar.dismissPopupMenus();
mClipper.cancelAnimator();
// Make sure we're not opening (because we're closing). Nobody can think we are
// customizing after the next two lines.
mOpening = false;
- setCustomizing(false);
- save();
if (animate) {
mClipper.animateCircularClip(mX, mY, false, mCollapseAnimationListener);
} else {
@@ -259,8 +170,6 @@
}
mNotifQsContainer.setCustomizerAnimating(animate);
mNotifQsContainer.setCustomizerShowing(false);
- mKeyguardStateController.removeCallback(mKeyguardCallback);
- updateNavColors();
}
}
@@ -268,7 +177,7 @@
return isShown;
}
- private void setCustomizing(boolean customizing) {
+ void setCustomizing(boolean customizing) {
mCustomizing = customizing;
mQs.notifyCustomizeChanged();
}
@@ -277,78 +186,21 @@
return mCustomizing || mOpening;
}
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- switch (item.getItemId()) {
- case MENU_RESET:
- mUiEventLogger.log(QSEditEvent.QS_EDIT_RESET);
- reset();
- break;
- }
- return false;
- }
-
- private void reset() {
- mTileAdapter.resetTileSpecs(mHost, QSTileHost.getDefaultSpecs(mContext));
- }
-
- private void setTileSpecs() {
- List<String> specs = new ArrayList<>();
- for (QSTile tile : mHost.getTiles()) {
- specs.add(tile.getTileSpec());
- }
- mTileAdapter.setTileSpecs(specs);
- mRecyclerView.setAdapter(mTileAdapter);
- }
-
- private void save() {
- if (mTileQueryHelper.isFinished()) {
- mTileAdapter.saveSpecs(mHost);
- }
- }
-
-
- public void saveInstanceState(Bundle outState) {
- if (isShown) {
- mKeyguardStateController.removeCallback(mKeyguardCallback);
- }
- outState.putBoolean(EXTRA_QS_CUSTOMIZING, mCustomizing);
- }
-
- public void restoreInstanceState(Bundle savedInstanceState) {
- boolean customizing = savedInstanceState.getBoolean(EXTRA_QS_CUSTOMIZING);
- if (customizing) {
- setVisibility(VISIBLE);
- addOnLayoutChangeListener(new OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft,
- int oldTop, int oldRight, int oldBottom) {
- removeOnLayoutChangeListener(this);
- showImmediately();
- }
- });
- }
- }
/** @param x,y Location on screen of animation center.
*/
public void setEditLocation(int x, int y) {
- int containerLocation[] = findViewById(R.id.customize_container).getLocationOnScreen();
+ int[] containerLocation = findViewById(R.id.customize_container).getLocationOnScreen();
mX = x - containerLocation[0];
mY = y - containerLocation[1];
}
- private final Callback mKeyguardCallback = new Callback() {
- @Override
- public void onKeyguardShowingChanged() {
- if (!isAttachedToWindow()) return;
- if (mKeyguardStateController.isShowing() && !mOpening) {
- hide();
- }
- }
- };
+ class ExpandAnimatorListener extends AnimatorListenerAdapter {
+ private final TileAdapter mTileAdapter;
- private final AnimatorListener mExpandAnimationListener = new AnimatorListenerAdapter() {
+ ExpandAnimatorListener(TileAdapter tileAdapter) {
+ mTileAdapter = tileAdapter;
+ }
+
@Override
public void onAnimationEnd(Animator animation) {
if (isShown) {
@@ -356,6 +208,7 @@
}
mOpening = false;
mNotifQsContainer.setCustomizerAnimating(false);
+ mRecyclerView.setAdapter(mTileAdapter);
}
@Override
@@ -363,7 +216,7 @@
mOpening = false;
mNotifQsContainer.setCustomizerAnimating(false);
}
- };
+ }
private final AnimatorListener mCollapseAnimationListener = new AnimatorListenerAdapter() {
@Override
@@ -372,7 +225,6 @@
setVisibility(View.GONE);
}
mNotifQsContainer.setCustomizerAnimating(false);
- mRecyclerView.setAdapter(mTileAdapter);
}
@Override
@@ -383,4 +235,12 @@
mNotifQsContainer.setCustomizerAnimating(false);
}
};
-}
+
+ public RecyclerView getRecyclerView() {
+ return mRecyclerView;
+ }
+
+ public boolean isOpening() {
+ return mOpening;
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
new file mode 100644
index 0000000..9f4c58b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.qs.customize;
+
+import static com.android.systemui.qs.customize.QSCustomizer.EXTRA_QS_CUSTOMIZING;
+import static com.android.systemui.qs.customize.QSCustomizer.MENU_RESET;
+
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.Toolbar;
+import android.widget.Toolbar.OnMenuItemClickListener;
+
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.R;
+import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.qs.QSEditEvent;
+import com.android.systemui.qs.QSFragment;
+import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.dagger.QSScope;
+import com.android.systemui.statusbar.phone.LightBarController;
+import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.ViewController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+/** {@link ViewController} for {@link QSCustomizer}. */
+@QSScope
+public class QSCustomizerController extends ViewController<QSCustomizer> {
+ private final TileQueryHelper mTileQueryHelper;
+ private final QSTileHost mQsTileHost;
+ private final TileAdapter mTileAdapter;
+ private final ScreenLifecycle mScreenLifecycle;
+ private final KeyguardStateController mKeyguardStateController;
+ private final LightBarController mLightBarController;
+ private final ConfigurationController mConfigurationController;
+ private final UiEventLogger mUiEventLogger;
+ private final Toolbar mToolbar;
+
+ private final OnMenuItemClickListener mOnMenuItemClickListener = new OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ if (item.getItemId() == MENU_RESET) {
+ mUiEventLogger.log(QSEditEvent.QS_EDIT_RESET);
+ reset();
+ }
+ return false;
+ }
+ };
+
+ private final KeyguardStateController.Callback mKeyguardCallback =
+ new KeyguardStateController.Callback() {
+ @Override
+ public void onKeyguardShowingChanged() {
+ if (!mView.isAttachedToWindow()) return;
+ if (mKeyguardStateController.isShowing() && !mView.isOpening()) {
+ hide();
+ }
+ }
+ };
+
+ private final ConfigurationListener mConfigurationListener = new ConfigurationListener() {
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ mView.updateNavBackDrop(newConfig, mLightBarController);
+ mView.updateResources();
+ }
+ };
+
+ @Inject
+ protected QSCustomizerController(QSCustomizer view, TileQueryHelper tileQueryHelper,
+ QSTileHost qsTileHost, TileAdapter tileAdapter, ScreenLifecycle screenLifecycle,
+ KeyguardStateController keyguardStateController, LightBarController lightBarController,
+ ConfigurationController configurationController, UiEventLogger uiEventLogger) {
+ super(view);
+ mTileQueryHelper = tileQueryHelper;
+ mQsTileHost = qsTileHost;
+ mTileAdapter = tileAdapter;
+ mScreenLifecycle = screenLifecycle;
+ mKeyguardStateController = keyguardStateController;
+ mLightBarController = lightBarController;
+ mConfigurationController = configurationController;
+ mUiEventLogger = uiEventLogger;
+
+ mToolbar = mView.findViewById(com.android.internal.R.id.action_bar);
+ }
+
+ @Override
+ protected void onViewAttached() {
+ mView.updateNavBackDrop(getResources().getConfiguration(), mLightBarController);
+
+ mConfigurationController.addCallback(mConfigurationListener);
+
+ mTileQueryHelper.setListener(mTileAdapter);
+ int halfMargin =
+ getResources().getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal) / 2;
+ mTileAdapter.changeHalfMargin(halfMargin);
+
+ RecyclerView recyclerView = mView.getRecyclerView();
+ recyclerView.setAdapter(mTileAdapter);
+ mTileAdapter.getItemTouchHelper().attachToRecyclerView(recyclerView);
+ GridLayoutManager layout = new GridLayoutManager(getContext(), 3) {
+ @Override
+ public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler,
+ RecyclerView.State state, View host, AccessibilityNodeInfoCompat info) {
+ // Do not read row and column every time it changes.
+ }
+ };
+ layout.setSpanSizeLookup(mTileAdapter.getSizeLookup());
+ recyclerView.setLayoutManager(layout);
+ recyclerView.addItemDecoration(mTileAdapter.getItemDecoration());
+ recyclerView.addItemDecoration(mTileAdapter.getMarginItemDecoration());
+
+ mToolbar.setOnMenuItemClickListener(mOnMenuItemClickListener);
+ mToolbar.setNavigationOnClickListener(v -> hide());
+ }
+
+ @Override
+ protected void onViewDetached() {
+ mTileQueryHelper.setListener(null);
+ mToolbar.setOnMenuItemClickListener(null);
+ mConfigurationController.removeCallback(mConfigurationListener);
+ }
+
+
+ private void reset() {
+ mTileAdapter.resetTileSpecs(QSTileHost.getDefaultSpecs(getContext()));
+ }
+
+ public boolean isCustomizing() {
+ return mView.isCustomizing();
+ }
+
+ /** */
+ public void show(int x, int y, boolean immediate) {
+ if (!mView.isShown()) {
+ setTileSpecs();
+ if (immediate) {
+ mView.showImmediately();
+ } else {
+ mView.show(x, y, mTileAdapter);
+ mUiEventLogger.log(QSEditEvent.QS_EDIT_OPEN);
+ }
+ mTileQueryHelper.queryTiles(mQsTileHost);
+ mKeyguardStateController.addCallback(mKeyguardCallback);
+ mView.updateNavColors(mLightBarController);
+ }
+ }
+
+ /** */
+ public void setQs(QSFragment qsFragment) {
+ mView.setQs(qsFragment);
+ }
+
+ /** */
+ public void restoreInstanceState(Bundle savedInstanceState) {
+ boolean customizing = savedInstanceState.getBoolean(EXTRA_QS_CUSTOMIZING);
+ if (customizing) {
+ mView.setVisibility(View.VISIBLE);
+ mView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft,
+ int oldTop, int oldRight, int oldBottom) {
+ mView.removeOnLayoutChangeListener(this);
+ show(0, 0, true);
+ }
+ });
+ }
+ }
+
+ /** */
+ public void saveInstanceState(Bundle outState) {
+ if (mView.isShown()) {
+ mKeyguardStateController.removeCallback(mKeyguardCallback);
+ }
+ outState.putBoolean(EXTRA_QS_CUSTOMIZING, mView.isCustomizing());
+ }
+
+ /** */
+ public void setEditLocation(int x, int y) {
+ mView.setEditLocation(x, y);
+ }
+
+ /** */
+ public void setContainer(NotificationsQuickSettingsContainer container) {
+ mView.setContainer(container);
+ }
+
+ public boolean isShown() {
+ return mView.isShown();
+ }
+
+ /** Hice the customizer. */
+ public void hide() {
+ final boolean animate = mScreenLifecycle.getScreenState() != ScreenLifecycle.SCREEN_OFF;
+ if (mView.isShown()) {
+ mUiEventLogger.log(QSEditEvent.QS_EDIT_CLOSED);
+ mToolbar.dismissPopupMenus();
+ mView.setCustomizing(false);
+ save();
+ mView.hide(animate);
+ mView.updateNavColors(mLightBarController);
+ mKeyguardStateController.removeCallback(mKeyguardCallback);
+ }
+ }
+
+ private void save() {
+ if (mTileQueryHelper.isFinished()) {
+ mTileAdapter.saveSpecs(mQsTileHost);
+ }
+ }
+
+ private void setTileSpecs() {
+ List<String> specs = new ArrayList<>();
+ for (QSTile tile : mQsTileHost.getTiles()) {
+ specs.add(tile.getTileSpec());
+ }
+ mTileAdapter.setTileSpecs(specs);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index b471dfa..dfc771b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -46,12 +46,17 @@
import com.android.systemui.qs.customize.TileAdapter.Holder;
import com.android.systemui.qs.customize.TileQueryHelper.TileInfo;
import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
+import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.tileimpl.QSIconViewImpl;
import java.util.ArrayList;
import java.util.List;
+import javax.inject.Inject;
+
+/** */
+@QSScope
public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileStateListener {
private static final long DRAG_LENGTH = 100;
private static final float DRAG_SCALE = 1.2f;
@@ -78,6 +83,7 @@
private final ItemDecoration mDecoration;
private final MarginTileDecoration mMarginDecoration;
private final int mMinNumTiles;
+ private final QSTileHost mHost;
private int mEditIndex;
private int mTileDividerIndex;
private int mFocusIndex;
@@ -89,13 +95,14 @@
private Holder mCurrentDrag;
private int mAccessibilityAction = ACTION_NONE;
private int mAccessibilityFromIndex;
- private QSTileHost mHost;
private final UiEventLogger mUiEventLogger;
private final AccessibilityDelegateCompat mAccessibilityDelegate;
private RecyclerView mRecyclerView;
- public TileAdapter(Context context, UiEventLogger uiEventLogger) {
+ @Inject
+ public TileAdapter(Context context, QSTileHost qsHost, UiEventLogger uiEventLogger) {
mContext = context;
+ mHost = qsHost;
mUiEventLogger = uiEventLogger;
mItemTouchHelper = new ItemTouchHelper(mCallbacks);
mDecoration = new TileItemDecoration(context);
@@ -114,10 +121,6 @@
mRecyclerView = null;
}
- public void setHost(QSTileHost host) {
- mHost = host;
- }
-
public ItemTouchHelper getItemTouchHelper() {
return mItemTouchHelper;
}
@@ -154,9 +157,10 @@
mAccessibilityAction = ACTION_NONE;
}
- public void resetTileSpecs(QSTileHost host, List<String> specs) {
+ /** */
+ public void resetTileSpecs(List<String> specs) {
// Notify the host so the tiles get removed callbacks.
- host.changeTiles(mCurrentSpecs, specs);
+ mHost.changeTiles(mCurrentSpecs, specs);
setTileSpecs(specs);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index b795a5f..59490c6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -37,6 +37,7 @@
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTile.State;
import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon;
import com.android.systemui.settings.UserTracker;
@@ -50,6 +51,8 @@
import javax.inject.Inject;
+/** */
+@QSScope
public class TileQueryHelper {
private static final String TAG = "TileQueryHelper";
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java
index 51b2c8d..8cc0502 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java
@@ -22,6 +22,7 @@
import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSPanelController;
import com.android.systemui.qs.QuickQSPanelController;
+import com.android.systemui.qs.customize.QSCustomizerController;
import dagger.BindsInstance;
import dagger.Subcomponent;
@@ -32,6 +33,7 @@
@Subcomponent(modules = {QSFragmentModule.class})
@QSScope
public interface QSFragmentComponent {
+
/** Factory for building a {@link QSFragmentComponent}. */
@Subcomponent.Factory
interface Factory {
@@ -52,4 +54,7 @@
/** Construct a {@link QSFooter} */
QSFooter getQSFooter();
+
+ /** Construct a {@link QSCustomizerController}. */
+ QSCustomizerController getQSCustomizerController();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
index 4bf4eff..354b2c9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
@@ -29,6 +29,7 @@
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QuickQSPanel;
import com.android.systemui.qs.QuickStatusBarHeader;
+import com.android.systemui.qs.customize.QSCustomizer;
import dagger.Binds;
import dagger.Module;
@@ -87,4 +88,11 @@
qsFooterViewController.init();
return qsFooterViewController;
}
+
+ /** */
+ @Provides
+ @QSScope
+ static QSCustomizer providesQSCutomizer(@RootView View view) {
+ return view.findViewById(R.id.qs_customize);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index 7c799ae..cfc81ee 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -30,6 +30,7 @@
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.util.settings.SecureSettings;
import dagger.Binds;
import dagger.Module;
@@ -48,14 +49,24 @@
AutoAddTracker.Builder autoAddTrackerBuilder,
QSTileHost host,
@Background Handler handler,
+ SecureSettings secureSettings,
HotspotController hotspotController,
DataSaverController dataSaverController,
ManagedProfileController managedProfileController,
NightDisplayListener nightDisplayListener,
CastController castController) {
- AutoTileManager manager = new AutoTileManager(context, autoAddTrackerBuilder,
- host, handler, hotspotController, dataSaverController, managedProfileController,
- nightDisplayListener, castController);
+ AutoTileManager manager = new AutoTileManager(
+ context,
+ autoAddTrackerBuilder,
+ host,
+ handler,
+ secureSettings,
+ hotspotController,
+ dataSaverController,
+ managedProfileController,
+ nightDisplayListener,
+ castController
+ );
manager.init();
return manager;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index c64fc50..bf3e4be 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -36,6 +36,7 @@
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.util.settings.SecureSettings;
import javax.inject.Inject;
@@ -62,15 +63,20 @@
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
- BatteryController batteryController
+ BatteryController batteryController,
+ SecureSettings secureSettings
) {
super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
activityStarter, qsLogger);
mBatteryController = batteryController;
mBatteryController.observe(getLifecycle(), this);
int currentUser = host.getUserContext().getUserId();
- mSetting = new SecureSetting(mContext, mHandler, Secure.LOW_POWER_WARNING_ACKNOWLEDGED,
- currentUser) {
+ mSetting = new SecureSetting(
+ secureSettings,
+ mHandler,
+ Secure.LOW_POWER_WARNING_ACKNOWLEDGED,
+ currentUser
+ ) {
@Override
protected void handleValueChanged(int value, boolean observedChange) {
// mHandler is the background handler so calling this is OK
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 5e6a6ce..f742752 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -25,6 +25,7 @@
import android.content.res.Resources;
import android.os.Handler;
import android.os.Looper;
+import android.os.UserHandle;
import android.provider.Settings;
import android.service.quicksettings.Tile;
import android.telephony.SubscriptionManager;
@@ -244,7 +245,8 @@
@Override
public boolean isAvailable() {
- return mController.hasMobileDataFeature();
+ return mController.hasMobileDataFeature()
+ && mHost.getUserContext().getUserId() == UserHandle.USER_SYSTEM;
}
private static final class CallbackInfo {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 98782f7..3995248 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -39,6 +39,7 @@
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.util.settings.SecureSettings;
import javax.inject.Inject;
@@ -63,12 +64,13 @@
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
- UserTracker userTracker
+ UserTracker userTracker,
+ SecureSettings secureSettings
) {
super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
activityStarter, qsLogger);
- mSetting = new SecureSetting(mContext, mainHandler,
+ mSetting = new SecureSetting(secureSettings, mainHandler,
Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, userTracker.getUserId()) {
@Override
protected void handleValueChanged(int value, boolean observedChange) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 260f557..7fe88b9 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -27,7 +27,6 @@
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.Notification;
-import android.app.WindowContext;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Configuration;
@@ -43,6 +42,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.provider.DeviceConfig;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -58,8 +58,10 @@
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
+import com.android.systemui.util.DeviceConfigProxy;
import java.util.List;
import java.util.function.Consumer;
@@ -143,6 +145,8 @@
private final DisplayMetrics mDisplayMetrics;
private final AccessibilityManager mAccessibilityManager;
private final MediaActionSound mCameraSound;
+ private final ScrollCaptureClient mScrollCaptureClient;
+ private final DeviceConfigProxy mConfigProxy;
private final Binder mWindowToken;
private ScreenshotView mScreenshotView;
@@ -173,11 +177,16 @@
};
@Inject
- ScreenshotController(Context context, ScreenshotSmartActions screenshotSmartActions,
+ ScreenshotController(
+ Context context,
+ ScreenshotSmartActions screenshotSmartActions,
ScreenshotNotificationsController screenshotNotificationsController,
- UiEventLogger uiEventLogger) {
+ ScrollCaptureClient scrollCaptureClient,
+ UiEventLogger uiEventLogger,
+ DeviceConfigProxy configProxy) {
mScreenshotSmartActions = screenshotSmartActions;
mNotificationsController = screenshotNotificationsController;
+ mScrollCaptureClient = scrollCaptureClient;
mUiEventLogger = uiEventLogger;
final DisplayManager dm = requireNonNull(context.getSystemService(DisplayManager.class));
@@ -186,6 +195,7 @@
mWindowManager = mContext.getSystemService(WindowManager.class);
mAccessibilityManager = AccessibilityManager.getInstance(mContext);
+ mConfigProxy = configProxy;
reloadAssets();
Configuration config = mContext.getResources().getConfiguration();
@@ -193,6 +203,7 @@
mDirectionLTR = config.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
mOrientationPortrait = config.orientation == ORIENTATION_PORTRAIT;
mWindowToken = new Binder("ScreenshotController");
+ mScrollCaptureClient.setHostWindowToken(mWindowToken);
// Setup the window that we are going to use
mWindowLayoutParams = new WindowManager.LayoutParams(
@@ -455,6 +466,19 @@
// Start the post-screenshot animation
startAnimation(finisher, screenRect, screenInsets, showFlash);
+
+ if (mConfigProxy.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.SCREENSHOT_SCROLLING_ENABLED, false)) {
+ mScrollCaptureClient.request(DEFAULT_DISPLAY, (connection) ->
+ mScreenshotView.showScrollChip(() ->
+ runScrollCapture(connection,
+ () -> dismissScreenshot(true))));
+ }
+ }
+
+ private void runScrollCapture(ScrollCaptureClient.Connection connection,
+ Runnable after) {
+ new ScrollCaptureController(mContext, connection).run(after);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index 29f6e8b..3383f80 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -113,6 +113,7 @@
private FrameLayout mDismissButton;
private ScreenshotActionChip mShareChip;
private ScreenshotActionChip mEditChip;
+ private ScreenshotActionChip mScrollChip;
private final ArrayList<ScreenshotActionChip> mSmartChips = new ArrayList<>();
private PendingInteraction mPendingInteraction;
@@ -152,6 +153,20 @@
mContext.getDisplay().getRealMetrics(mDisplayMetrics);
}
+ /**
+ * Called to display the scroll action chip when support is detected.
+ *
+ * @param onClick the action to take when the chip is clicked.
+ */
+ public void showScrollChip(Runnable onClick) {
+ mScrollChip.setVisibility(VISIBLE);
+ mScrollChip.setOnClickListener((v) ->
+ onClick.run()
+ // TODO Logging, store event consumer to a field
+ //onElementTapped.accept(ScreenshotEvent.SCREENSHOT_SCROLL_TAPPED);
+ );
+ }
+
@Override // ViewTreeObserver.OnComputeInternalInsetsListener
public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
inoutInfo.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
@@ -193,6 +208,7 @@
mScreenshotSelectorView = requireNonNull(findViewById(R.id.global_screenshot_selector));
mShareChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_share_chip));
mEditChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_edit_chip));
+ mScrollChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_scroll_chip));
mScreenshotPreview.setClipToOutline(true);
mScreenshotPreview.setOutlineProvider(new ViewOutlineProvider() {
@@ -387,7 +403,7 @@
});
chips.add(mShareChip);
- mEditChip.setText(mContext.getString(com.android.internal.R.string.screenshot_edit));
+ mEditChip.setText(mContext.getString(R.string.screenshot_edit_label));
mEditChip.setIcon(Icon.createWithResource(mContext, R.drawable.ic_screenshot_edit), true);
mEditChip.setOnClickListener(v -> {
mEditChip.setIsPending(true);
@@ -402,6 +418,11 @@
mPendingInteraction = PendingInteraction.PREVIEW;
});
+ mScrollChip.setText(mContext.getString(R.string.screenshot_scroll_label));
+ mScrollChip.setIcon(Icon.createWithResource(mContext,
+ R.drawable.ic_screenshot_scroll), true);
+ chips.add(mScrollChip);
+
// remove the margin from the last chip so that it's correctly aligned with the end
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)
mActionsView.getChildAt(0).getLayoutParams();
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
new file mode 100644
index 0000000..ea835fa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.screenshot;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.UiContext;
+import android.app.ActivityTaskManager;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
+import android.media.Image;
+import android.media.ImageReader;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.IScrollCaptureCallbacks;
+import android.view.IScrollCaptureConnection;
+import android.view.IWindowManager;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.view.ScrollCaptureViewSupport;
+
+import java.util.function.Consumer;
+
+import javax.inject.Inject;
+
+/**
+ * High level interface to scroll capture API.
+ */
+public class ScrollCaptureClient {
+
+ @VisibleForTesting
+ static final int MATCH_ANY_TASK = ActivityTaskManager.INVALID_TASK_ID;
+
+ private static final String TAG = "ScrollCaptureClient";
+
+ /** Whether to log method names and arguments for most calls */
+ private static final boolean DEBUG_TRACE = false;
+
+ /**
+ * A connection to a remote window. Starts a capture session.
+ */
+ public interface Connection {
+ /**
+ * Session start should be deferred until UI is active because of resource allocation and
+ * potential visible side effects in the target window.
+ *
+ * @param maxBuffers the maximum number of buffers (tiles) that may be in use at one
+ * time, tiles are not cached anywhere so set this to a large enough
+ * number to retain offscreen content until it is no longer needed
+ * @param sessionConsumer listener to receive the session once active
+ */
+ void start(int maxBuffers, Consumer<Session> sessionConsumer);
+
+ /**
+ * Close the connection.
+ */
+ void close();
+ }
+
+ static class CaptureResult {
+ public final Image image;
+ /**
+ * The area requested, in content rect space, relative to scroll-bounds.
+ */
+ public final Rect requested;
+ /**
+ * The actual area captured, in content rect space, relative to scroll-bounds. This may be
+ * cropped or empty depending on available content.
+ */
+ public final Rect captured;
+
+ // Error?
+
+ private CaptureResult(Image image, Rect request, Rect captured) {
+ this.image = image;
+ this.requested = request;
+ this.captured = captured;
+ }
+ }
+
+ /**
+ * Represents the connection to a target window and provides a mechanism for requesting tiles.
+ */
+ interface Session {
+ /**
+ * Request the given horizontal strip. Values are y-coordinates in captured space, relative
+ * to start position.
+ *
+ * @param contentRect the area to capture, in content rect space, relative to scroll-bounds
+ * @param consumer listener to be informed of the result
+ */
+ void requestTile(Rect contentRect, Consumer<CaptureResult> consumer);
+
+ /**
+ * End the capture session, return the target app to original state. The returned
+ * stage must be waited for to complete to allow the target app a chance to restore to
+ * original state before becoming visible.
+ *
+ * @return a stage presenting the session shutdown
+ */
+ void end(Runnable listener);
+
+ int getMaxTileHeight();
+
+ int getMaxTileWidth();
+ }
+
+ private final IWindowManager mWindowManagerService;
+ private IBinder mHostWindowToken;
+
+ @Inject
+ public ScrollCaptureClient(@UiContext Context context, IWindowManager windowManagerService) {
+ requireNonNull(context.getDisplay(), "context must be associated with a Display!");
+ mWindowManagerService = windowManagerService;
+ }
+
+ public void setHostWindowToken(IBinder token) {
+ mHostWindowToken = token;
+ }
+
+ /**
+ * Check for scroll capture support.
+ *
+ * @param displayId id for the display containing the target window
+ * @param consumer receives a connection when available
+ */
+ public void request(int displayId, Consumer<Connection> consumer) {
+ request(displayId, MATCH_ANY_TASK, consumer);
+ }
+
+ /**
+ * Check for scroll capture support.
+ *
+ * @param displayId id for the display containing the target window
+ * @param taskId id for the task containing the target window or {@link #MATCH_ANY_TASK}.
+ * @param consumer receives a connection when available
+ */
+ public void request(int displayId, int taskId, Consumer<Connection> consumer) {
+ try {
+ if (DEBUG_TRACE) {
+ Log.d(TAG, "requestScrollCapture(displayId=" + displayId + ", " + mHostWindowToken
+ + ", taskId=" + taskId + ", consumer=" + consumer + ")");
+ }
+ mWindowManagerService.requestScrollCapture(displayId, mHostWindowToken, taskId,
+ new ControllerCallbacks(consumer));
+ } catch (RemoteException e) {
+ Log.e(TAG, "Ignored remote exception", e);
+ }
+ }
+
+ private static class ControllerCallbacks extends IScrollCaptureCallbacks.Stub implements
+ Connection, Session, IBinder.DeathRecipient {
+
+ private IScrollCaptureConnection mConnection;
+ private Consumer<Connection> mConnectionConsumer;
+ private Consumer<Session> mSessionConsumer;
+ private Consumer<CaptureResult> mResultConsumer;
+ private Runnable mShutdownListener;
+
+ private ImageReader mReader;
+ private Rect mScrollBounds;
+ private Rect mRequestRect;
+ private boolean mStarted;
+
+ private ControllerCallbacks(Consumer<Connection> connectionConsumer) {
+ mConnectionConsumer = connectionConsumer;
+ }
+
+ // IScrollCaptureCallbacks
+
+ @Override
+ public void onConnected(IScrollCaptureConnection connection, Rect scrollBounds,
+ Point positionInWindow) throws RemoteException {
+ if (DEBUG_TRACE) {
+ Log.d(TAG, "onConnected(connection=" + connection + ", scrollBounds=" + scrollBounds
+ + ", positionInWindow=" + positionInWindow + ")");
+ }
+ mConnection = connection;
+ mConnection.asBinder().linkToDeath(this, 0);
+ mScrollBounds = scrollBounds;
+ mConnectionConsumer.accept(this);
+ mConnectionConsumer = null;
+ }
+
+ @Override
+ public void onUnavailable() throws RemoteException {
+ if (DEBUG_TRACE) {
+ Log.d(TAG, "onUnavailable");
+ }
+ // The targeted app does not support scroll capture
+ // or the window could not be found... etc etc.
+ }
+
+ @Override
+ public void onCaptureStarted() {
+ if (DEBUG_TRACE) {
+ Log.d(TAG, "onCaptureStarted()");
+ }
+ mSessionConsumer.accept(this);
+ mSessionConsumer = null;
+ }
+
+ @Override
+ public void onCaptureBufferSent(long frameNumber, Rect contentArea) {
+ Image image = null;
+ if (frameNumber != ScrollCaptureViewSupport.NO_FRAME_PRODUCED) {
+ image = mReader.acquireNextImage();
+ }
+ if (DEBUG_TRACE) {
+ Log.d(TAG, "onCaptureBufferSent(frameNumber=" + frameNumber
+ + ", contentArea=" + contentArea + ") image=" + image);
+ }
+ // Save and clear first, since the consumer will likely request the next
+ // tile, otherwise the new consumer will be wiped out.
+ Consumer<CaptureResult> consumer = mResultConsumer;
+ mResultConsumer = null;
+ consumer.accept(new CaptureResult(image, mRequestRect, contentArea));
+ }
+
+ @Override
+ public void onConnectionClosed() {
+ if (DEBUG_TRACE) {
+ Log.d(TAG, "onConnectionClosed()");
+ }
+ disconnect();
+ if (mShutdownListener != null) {
+ mShutdownListener.run();
+ mShutdownListener = null;
+ }
+ }
+
+ // Misc
+
+ private void disconnect() {
+ if (mConnection != null) {
+ mConnection.asBinder().unlinkToDeath(this, 0);
+ }
+ mConnection = null;
+ }
+
+ // ScrollCaptureController.Connection
+
+ // -> Error handling: BiConsumer<Session, Throwable> ?
+ @Override
+ public void start(int maxBufferCount, Consumer<Session> sessionConsumer) {
+ if (DEBUG_TRACE) {
+ Log.d(TAG, "start(maxBufferCount=" + maxBufferCount
+ + ", sessionConsumer=" + sessionConsumer + ")");
+ }
+ mReader = ImageReader.newInstance(mScrollBounds.width(), mScrollBounds.height(),
+ PixelFormat.RGBA_8888, maxBufferCount, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
+ mSessionConsumer = sessionConsumer;
+ try {
+ mConnection.startCapture(mReader.getSurface());
+ mStarted = true;
+ } catch (RemoteException e) {
+ Log.w(TAG, "should not be happening :-(");
+ // ?
+ //mSessionListener.onError(e);
+ //mSessionListener = null;
+ }
+ }
+
+ @Override
+ public void close() {
+ end(null);
+ }
+
+ // ScrollCaptureController.Session
+
+ @Override
+ public void end(Runnable listener) {
+ if (DEBUG_TRACE) {
+ Log.d(TAG, "end(listener=" + listener + ")");
+ }
+ if (mStarted) {
+ mShutdownListener = listener;
+ try {
+ // listener called from onConnectionClosed callback
+ mConnection.endCapture();
+ } catch (RemoteException e) {
+ Log.d(TAG, "Ignored exception from endCapture()", e);
+ disconnect();
+ listener.run();
+ }
+ } else {
+ disconnect();
+ listener.run();
+ }
+ }
+
+ @Override
+ public int getMaxTileHeight() {
+ return mScrollBounds.height();
+ }
+
+ @Override
+ public int getMaxTileWidth() {
+ return mScrollBounds.width();
+ }
+
+ @Override
+ public void requestTile(Rect contentRect, Consumer<CaptureResult> consumer) {
+ if (DEBUG_TRACE) {
+ Log.d(TAG, "requestTile(contentRect=" + contentRect + "consumer=" + consumer + ")");
+ }
+ mRequestRect = new Rect(contentRect);
+ mResultConsumer = consumer;
+ try {
+ mConnection.requestImage(mRequestRect);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Caught remote exception from requestImage", e);
+ // ?
+ }
+ }
+
+ /**
+ * The process hosting the window went away abruptly!
+ */
+ @Override
+ public void binderDied() {
+ if (DEBUG_TRACE) {
+ Log.d(TAG, "binderDied()");
+ }
+ disconnect();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
index 5ced40c..800d679 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
@@ -16,46 +16,231 @@
package com.android.systemui.screenshot;
-import android.os.IBinder;
-import android.view.IWindowManager;
+import static android.graphics.ColorSpace.Named.SRGB;
-import javax.inject.Inject;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.ColorSpace;
+import android.graphics.Picture;
+import android.graphics.Rect;
+import android.media.ExifInterface;
+import android.media.Image;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
+import android.provider.MediaStore;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.android.systemui.screenshot.ScrollCaptureClient.Connection;
+import com.android.systemui.screenshot.ScrollCaptureClient.Session;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.sql.Date;
+import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Objects;
+import java.util.UUID;
+import java.util.function.Consumer;
/**
- * Stub
+ * Interaction controller between the UI and ScrollCaptureClient.
*/
public class ScrollCaptureController {
+ private static final String TAG = "ScrollCaptureController";
- public static final int STATUS_A = 0;
- public static final int STATUS_B = 1;
+ public static final int MAX_PAGES = 5;
+ public static final int MAX_HEIGHT = 12000;
- private final IWindowManager mWindowManagerService;
- private StatusListener mListener;
+ private final Connection mConnection;
+ private final Context mContext;
+ private Picture mPicture;
- /**
- *
- * @param windowManagerService
- */
- @Inject
- public ScrollCaptureController(IWindowManager windowManagerService) {
- mWindowManagerService = windowManagerService;
- }
-
- interface StatusListener {
- void onScrollCaptureStatus(boolean available);
+ public ScrollCaptureController(Context context, Connection connection) {
+ mContext = context;
+ mConnection = connection;
}
/**
+ * Run scroll capture!
*
- * @param window
- * @param listener
+ * @param after action to take after the flow is complete
*/
- public void getStatus(IBinder window, StatusListener listener) {
- mListener = listener;
-// try {
-// mWindowManagerService.requestScrollCapture(window, new ClientCallbacks());
-// } catch (RemoteException e) {
-// }
+ public void run(final Runnable after) {
+ mConnection.start(MAX_PAGES, (session) -> startCapture(session, after));
}
+ private void startCapture(Session session, final Runnable after) {
+ Rect requestRect = new Rect(0, 0,
+ session.getMaxTileWidth(), session.getMaxTileHeight());
+ Consumer<ScrollCaptureClient.CaptureResult> consumer =
+ new Consumer<ScrollCaptureClient.CaptureResult>() {
+
+ int mFrameCount = 0;
+
+ @Override
+ public void accept(ScrollCaptureClient.CaptureResult result) {
+ mFrameCount++;
+ boolean emptyFrame = result.captured.height() == 0;
+ if (!emptyFrame) {
+ mPicture = stackBelow(mPicture, result.image, result.captured.width(),
+ result.captured.height());
+ }
+ if (emptyFrame || mFrameCount > MAX_PAGES
+ || requestRect.bottom > MAX_HEIGHT) {
+ Uri uri = null;
+ if (mPicture != null) {
+ // This is probably on a binder thread right now ¯\_(ツ)_/¯
+ uri = writeImage(Bitmap.createBitmap(mPicture));
+ // Release those buffers!
+ mPicture.close();
+ }
+ if (uri != null) {
+ launchViewer(uri);
+ } else {
+ Toast.makeText(mContext, "Failed to create tall screenshot",
+ Toast.LENGTH_SHORT).show();
+ }
+ session.end(after); // end session, close connection, after.run()
+ return;
+ }
+ requestRect.offset(0, session.getMaxTileHeight());
+ session.requestTile(requestRect, /* consumer */ this);
+ }
+ };
+
+ // fire it up!
+ session.requestTile(requestRect, consumer);
+ };
+
+
+ /**
+ * Combine the top {@link Picture} with an {@link Image} by appending the image directly
+ * below, creating a result that is the combined height of both.
+ * <p>
+ * Note: no pixel data is transferred here, only a record of drawing commands. Backing
+ * hardware buffers must not be modified/recycled until the picture is
+ * {@link Picture#close closed}.
+ *
+ * @param top the existing picture
+ * @param below the image to append below
+ * @param cropWidth the width of the pixel data to use from the image
+ * @param cropHeight the height of the pixel data to use from the image
+ *
+ * @return a new Picture which draws the previous picture with the image below it
+ */
+ private static Picture stackBelow(Picture top, Image below, int cropWidth, int cropHeight) {
+ int width = cropWidth;
+ int height = cropHeight;
+ if (top != null) {
+ height += top.getHeight();
+ width = Math.max(width, top.getWidth());
+ }
+ Picture combined = new Picture();
+ Canvas canvas = combined.beginRecording(width, height);
+ int y = 0;
+ if (top != null) {
+ canvas.drawPicture(top, new Rect(0, 0, top.getWidth(), top.getHeight()));
+ y += top.getHeight();
+ }
+ canvas.drawBitmap(Bitmap.wrapHardwareBuffer(
+ below.getHardwareBuffer(), ColorSpace.get(SRGB)), 0, y, null);
+ combined.endRecording();
+ return combined;
+ }
+
+ Uri writeImage(Bitmap image) {
+ ContentResolver resolver = mContext.getContentResolver();
+ long mImageTime = System.currentTimeMillis();
+ String imageDate = new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date(mImageTime));
+ String mImageFileName = String.format("tall_Screenshot_%s.png", imageDate);
+ String mScreenshotId = String.format("Screenshot_%s", UUID.randomUUID());
+ try {
+ // Save the screenshot to the MediaStore
+ final ContentValues values = new ContentValues();
+ values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES
+ + File.separator + Environment.DIRECTORY_SCREENSHOTS);
+ values.put(MediaStore.MediaColumns.DISPLAY_NAME, mImageFileName);
+ values.put(MediaStore.MediaColumns.MIME_TYPE, "image/png");
+ values.put(MediaStore.MediaColumns.DATE_ADDED, mImageTime / 1000);
+ values.put(MediaStore.MediaColumns.DATE_MODIFIED, mImageTime / 1000);
+ values.put(
+ MediaStore.MediaColumns.DATE_EXPIRES,
+ (mImageTime + DateUtils.DAY_IN_MILLIS) / 1000);
+ values.put(MediaStore.MediaColumns.IS_PENDING, 1);
+
+ final Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+ values);
+ try {
+ try (OutputStream out = resolver.openOutputStream(uri)) {
+ if (!image.compress(Bitmap.CompressFormat.PNG, 100, out)) {
+ throw new IOException("Failed to compress");
+ }
+ }
+
+ // Next, write metadata to help index the screenshot
+ try (ParcelFileDescriptor pfd = resolver.openFile(uri, "rw", null)) {
+ final ExifInterface exif = new ExifInterface(pfd.getFileDescriptor());
+
+ exif.setAttribute(ExifInterface.TAG_SOFTWARE,
+ "Android " + Build.DISPLAY);
+
+ exif.setAttribute(ExifInterface.TAG_IMAGE_WIDTH,
+ Integer.toString(image.getWidth()));
+ exif.setAttribute(ExifInterface.TAG_IMAGE_LENGTH,
+ Integer.toString(image.getHeight()));
+
+ final ZonedDateTime time = ZonedDateTime.ofInstant(
+ Instant.ofEpochMilli(mImageTime), ZoneId.systemDefault());
+ exif.setAttribute(ExifInterface.TAG_DATETIME_ORIGINAL,
+ DateTimeFormatter.ofPattern("yyyy:MM:dd HH:mm:ss").format(time));
+ exif.setAttribute(ExifInterface.TAG_SUBSEC_TIME_ORIGINAL,
+ DateTimeFormatter.ofPattern("SSS").format(time));
+
+ if (Objects.equals(time.getOffset(), ZoneOffset.UTC)) {
+ exif.setAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL, "+00:00");
+ } else {
+ exif.setAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL,
+ DateTimeFormatter.ofPattern("XXX").format(time));
+ }
+ exif.saveAttributes();
+ }
+
+ // Everything went well above, publish it!
+ values.clear();
+ values.put(MediaStore.MediaColumns.IS_PENDING, 0);
+ values.putNull(MediaStore.MediaColumns.DATE_EXPIRES);
+ resolver.update(uri, values, null, null);
+ return uri;
+ } catch (Exception e) {
+ resolver.delete(uri, null);
+ throw e;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "unable to save screenshot", e);
+ }
+ return null;
+ }
+
+ void launchViewer(Uri uri) {
+ Intent editIntent = new Intent(Intent.ACTION_VIEW);
+ editIntent.setType("image/png");
+ editIntent.setData(uri);
+ editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ editIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ mContext.startActivityAsUser(editIntent, UserHandle.CURRENT);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index a92b9e4..9bd34ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -26,7 +26,6 @@
import android.view.ViewGroup;
import com.android.systemui.R;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.dagger.StatusBarModule;
@@ -43,6 +42,7 @@
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.util.Assert;
+import com.android.wm.shell.bubbles.Bubbles;
import java.util.ArrayList;
import java.util.HashMap;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index cee9c70..efd0519 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -21,7 +21,6 @@
import android.os.Handler;
import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.media.MediaDataManager;
@@ -62,6 +61,7 @@
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.wm.shell.bubbles.Bubbles;
import java.util.Optional;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index 382715a..45e8098 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_APP_START;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
@@ -32,6 +34,7 @@
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
import android.view.View;
+import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.systemui.Interpolators;
import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -226,10 +229,27 @@
}
});
anim.addListener(new AnimatorListenerAdapter() {
+ private boolean mWasCancelled;
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ InteractionJankMonitor.getInstance().begin(CUJ_NOTIFICATION_APP_START);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mWasCancelled = true;
+ }
+
@Override
public void onAnimationEnd(Animator animation) {
setExpandAnimationRunning(false);
invokeCallback(iRemoteAnimationFinishedCallback);
+ if (!mWasCancelled) {
+ InteractionJankMonitor.getInstance().end(CUJ_NOTIFICATION_APP_START);
+ } else {
+ InteractionJankMonitor.getInstance().cancel(CUJ_NOTIFICATION_APP_START);
+ }
}
});
anim.start();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java
index eee9cc6..967524c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java
@@ -16,9 +16,7 @@
package com.android.systemui.statusbar.notification;
-import android.graphics.drawable.Drawable;
import android.util.FloatProperty;
-import android.util.Log;
import android.util.Property;
import android.view.View;
@@ -34,9 +32,14 @@
public static final AnimatableProperty X = AnimatableProperty.from(View.X,
R.id.x_animator_tag, R.id.x_animator_tag_start_value, R.id.x_animator_tag_end_value);
+
public static final AnimatableProperty Y = AnimatableProperty.from(View.Y,
R.id.y_animator_tag, R.id.y_animator_tag_start_value, R.id.y_animator_tag_end_value);
+ public static final AnimatableProperty TRANSLATION_X = AnimatableProperty.from(
+ View.TRANSLATION_X, R.id.x_animator_tag, R.id.x_animator_tag_start_value,
+ R.id.x_animator_tag_end_value);
+
/**
* Similar to X, however this doesn't allow for any other modifications other than from this
* property. When using X, it's possible that the view is laid out during the animation,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
index 7d8979c..aef01e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
@@ -22,10 +22,10 @@
import android.view.View;
import com.android.systemui.DejankUtils;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.wm.shell.bubbles.Bubbles;
import java.util.Optional;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
index 83a569b..29a030f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
-import com.android.systemui.bubbles.BubbleController;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -26,6 +24,8 @@
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
import com.android.systemui.wmshell.BubblesManager;
+import com.android.wm.shell.bubbles.BubbleController;
+import com.android.wm.shell.bubbles.Bubbles;
import java.util.HashSet;
import java.util.Optional;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
index 36adfac..3db5440 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
@@ -22,7 +22,6 @@
import android.util.Log;
import com.android.systemui.Dumpable;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
@@ -34,6 +33,7 @@
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
+import com.android.wm.shell.bubbles.Bubbles;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
index 049b471..52b9b06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
@@ -17,13 +17,13 @@
package com.android.systemui.statusbar.notification.init
import android.service.notification.StatusBarNotification
-import com.android.systemui.bubbles.Bubbles
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption
import com.android.systemui.statusbar.NotificationPresenter
import com.android.systemui.statusbar.notification.NotificationActivityStarter
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.phone.StatusBar
+import com.android.wm.shell.bubbles.Bubbles
import java.io.FileDescriptor
import java.io.PrintWriter
import java.util.Optional
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
index 45a5d10..8f352ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.notification.init
import android.service.notification.StatusBarNotification
-import com.android.systemui.bubbles.Bubbles
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption
import com.android.systemui.statusbar.FeatureFlags
@@ -41,6 +40,7 @@
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.statusbar.policy.HeadsUpManager
import com.android.systemui.statusbar.policy.RemoteInputUriController
+import com.android.wm.shell.bubbles.Bubbles
import dagger.Lazy
import java.io.FileDescriptor
import java.io.PrintWriter
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
index 7569c1b..d0e68bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.notification.init
import android.service.notification.StatusBarNotification
-import com.android.systemui.bubbles.Bubbles
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption
import com.android.systemui.statusbar.NotificationListener
import com.android.systemui.statusbar.NotificationPresenter
@@ -25,6 +24,7 @@
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.phone.StatusBar
+import com.android.wm.shell.bubbles.Bubbles
import java.io.FileDescriptor
import java.io.PrintWriter
import java.util.Optional
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 094e866..10273cbb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -33,6 +33,7 @@
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+import com.android.internal.jank.InteractionJankMonitor;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -750,12 +751,16 @@
if (!mWasCancelled) {
enableAppearDrawing(false);
onAppearAnimationFinished(isAppearing);
+ InteractionJankMonitor.getInstance().end(getCujType(isAppearing));
+ } else {
+ InteractionJankMonitor.getInstance().cancel(getCujType(isAppearing));
}
}
@Override
public void onAnimationStart(Animator animation) {
mWasCancelled = false;
+ InteractionJankMonitor.getInstance().begin(getCujType(isAppearing));
}
@Override
@@ -766,6 +771,18 @@
mAppearAnimator.start();
}
+ private int getCujType(boolean isAppearing) {
+ if (mIsHeadsUpAnimation) {
+ return isAppearing
+ ? InteractionJankMonitor.CUJ_NOTIFICATION_HEADS_UP_APPEAR
+ : InteractionJankMonitor.CUJ_NOTIFICATION_HEADS_UP_DISAPPEAR;
+ } else {
+ return isAppearing
+ ? InteractionJankMonitor.CUJ_NOTIFICATION_ADD
+ : InteractionJankMonitor.CUJ_NOTIFICATION_REMOVE;
+ }
+ }
+
protected void onAppearAnimationFinished(boolean wasAppearing) {
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 280c525..a011d36 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -35,6 +35,7 @@
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.Color;
import android.graphics.Path;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.AnimationDrawable;
@@ -43,6 +44,7 @@
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
+import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.AttributeSet;
@@ -327,6 +329,7 @@
private boolean mShelfIconVisible;
private boolean mAboveShelf;
private OnUserInteractionCallback mOnUserInteractionCallback;
+ private NotificationGutsManager mNotificationGutsManager;
private boolean mIsLowPriority;
private boolean mIsColorized;
private boolean mUseIncreasedCollapsedHeight;
@@ -1089,6 +1092,13 @@
};
}
+ /** The click listener for the snooze button. */
+ public View.OnClickListener getSnoozeClickListener(MenuItem item) {
+ return v -> {
+ mNotificationGutsManager.openGuts(this, 0, 0, item);
+ };
+ }
+
private void updateClickAndFocus() {
boolean normalChild = !isChildInGroup() || isGroupExpanded();
boolean clickable = mOnClickListener != null && normalChild;
@@ -1155,10 +1165,11 @@
*/
@Nullable
public NotificationMenuRowPlugin createMenu() {
- if (mMenuRow == null) {
+ final boolean removeShelf = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.SHOW_NEW_NOTIF_DISMISS, 0 /* show shelf by default */) == 1;
+ if (mMenuRow == null || removeShelf) {
return null;
}
-
if (mMenuRow.getMenuView() == null) {
mMenuRow.createMenu(this, mEntry.getSbn());
mMenuRow.setAppName(mAppName);
@@ -1555,7 +1566,8 @@
StatusBarStateController statusBarStateController,
PeopleNotificationIdentifier peopleNotificationIdentifier,
OnUserInteractionCallback onUserInteractionCallback,
- Optional<BubblesManager> bubblesManagerOptional) {
+ Optional<BubblesManager> bubblesManagerOptional,
+ NotificationGutsManager gutsManager) {
mEntry = entry;
mAppName = appName;
if (mMenuRow == null) {
@@ -1584,6 +1596,7 @@
}
mOnUserInteractionCallback = onUserInteractionCallback;
mBubblesManagerOptional = bubblesManagerOptional;
+ mNotificationGutsManager = gutsManager;
cacheIsSystemNotification();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index 05b1dba..cb2af54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -154,7 +154,8 @@
mStatusBarStateController,
mPeopleNotificationIdentifier,
mOnUserInteractionCallback,
- mBubblesManagerOptional
+ mBubblesManagerOptional,
+ mNotificationGutsManager
);
mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
if (mAllowLongPress) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 71e1d12..79c3007 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -18,12 +18,14 @@
import static android.provider.Settings.Global.NOTIFICATION_BUBBLES;
+import static android.provider.Settings.Secure.SHOW_NOTIFICATION_SNOOZE;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
@@ -31,6 +33,7 @@
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.NotificationHeaderView;
import android.view.View;
@@ -44,6 +47,7 @@
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.TransformableView;
@@ -458,7 +462,7 @@
mExpandedWrapper = NotificationViewWrapper.wrap(getContext(), child,
mContainingNotification);
if (mContainingNotification != null) {
- applyBubbleAction(mExpandedChild, mContainingNotification.getEntry());
+ applySystemActions(mExpandedChild, mContainingNotification.getEntry());
}
}
@@ -500,7 +504,7 @@
mHeadsUpWrapper = NotificationViewWrapper.wrap(getContext(), child,
mContainingNotification);
if (mContainingNotification != null) {
- applyBubbleAction(mHeadsUpChild, mContainingNotification.getEntry());
+ applySystemActions(mHeadsUpChild, mContainingNotification.getEntry());
}
}
@@ -1161,8 +1165,8 @@
mForceSelectNextLayout = true;
mPreviousExpandedRemoteInputIntent = null;
mPreviousHeadsUpRemoteInputIntent = null;
- applyBubbleAction(mExpandedChild, entry);
- applyBubbleAction(mHeadsUpChild, entry);
+ applySystemActions(mExpandedChild, entry);
+ applySystemActions(mHeadsUpChild, entry);
}
private void updateAllSingleLineViews() {
@@ -1340,6 +1344,14 @@
NOTIFICATION_BUBBLES, 0) == 1;
}
+ /**
+ * Setup icon buttons provided by System UI.
+ */
+ private void applySystemActions(View layout, NotificationEntry entry) {
+ applySnoozeAction(layout);
+ applyBubbleAction(layout, entry);
+ }
+
private void applyBubbleAction(View layout, NotificationEntry entry) {
if (layout == null || mContainingNotification == null || mPeopleIdentifier == null) {
return;
@@ -1359,8 +1371,8 @@
&& entry.getBubbleMetadata() != null;
if (showButton) {
Drawable d = mContext.getResources().getDrawable(entry.isBubble()
- ? R.drawable.ic_stop_bubble
- : R.drawable.ic_create_bubble);
+ ? R.drawable.bubble_ic_stop_bubble
+ : R.drawable.bubble_ic_create_bubble);
mContainingNotification.updateNotificationColor();
final int tint = mContainingNotification.getNotificationColor();
d.setTint(tint);
@@ -1387,6 +1399,45 @@
}
}
+ private void applySnoozeAction(View layout) {
+ if (layout == null || mContainingNotification == null) {
+ return;
+ }
+ ImageView snoozeButton = layout.findViewById(com.android.internal.R.id.snooze_button);
+ View actionContainer = layout.findViewById(com.android.internal.R.id.actions_container);
+ LinearLayout actionContainerLayout =
+ layout.findViewById(com.android.internal.R.id.actions_container_layout);
+ if (snoozeButton == null || actionContainer == null || actionContainerLayout == null) {
+ return;
+ }
+ final boolean showSnooze = Settings.Secure.getInt(mContext.getContentResolver(),
+ SHOW_NOTIFICATION_SNOOZE, 0) == 1;
+ if (!showSnooze) {
+ snoozeButton.setVisibility(GONE);
+ return;
+ }
+
+ Resources res = mContext.getResources();
+ Drawable snoozeDrawable = res.getDrawable(R.drawable.ic_snooze);
+ mContainingNotification.updateNotificationColor();
+ snoozeDrawable.setTint(mContainingNotification.getNotificationColor());
+ snoozeButton.setImageDrawable(snoozeDrawable);
+
+ final NotificationSnooze snoozeGuts = (NotificationSnooze) LayoutInflater.from(mContext)
+ .inflate(R.layout.notification_snooze, null, false);
+ final String snoozeDescription = res.getString(
+ R.string.notification_menu_snooze_description);
+ final NotificationMenuRowPlugin.MenuItem snoozeMenuItem =
+ new NotificationMenuRow.NotificationMenuItem(
+ mContext, snoozeDescription, snoozeGuts, R.drawable.ic_snooze);
+ snoozeButton.setContentDescription(
+ mContext.getResources().getString(R.string.notification_menu_snooze_description));
+ snoozeButton.setOnClickListener(
+ mContainingNotification.getSnoozeClickListener(snoozeMenuItem));
+ snoozeButton.setVisibility(VISIBLE);
+ actionContainer.setVisibility(VISIBLE);
+ }
+
private void applySmartReplyView(
SmartRepliesAndActions smartRepliesAndActions,
NotificationEntry entry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 7a976ac..6ff5ed1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -236,6 +236,7 @@
NotificationChannel.DEFAULT_CHANNEL_ID)
&& numTotalChannels == 1;
}
+ mIsAutomaticChosen = getAlertingBehavior() == BEHAVIOR_AUTOMATIC;
bindHeader();
bindChannelDetails();
@@ -658,13 +659,14 @@
try {
if (mChannelToUpdate != null) {
if (mUnlockImportance) {
- mChannelToUpdate.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
+ mINotificationManager.unlockNotificationChannel(
+ mPackageName, mAppUid, mChannelToUpdate.getId());
} else {
mChannelToUpdate.setImportance(mNewImportance);
mChannelToUpdate.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
+ mINotificationManager.updateNotificationChannelForPackage(
+ mPackageName, mAppUid, mChannelToUpdate);
}
- mINotificationManager.updateNotificationChannelForPackage(
- mPackageName, mAppUid, mChannelToUpdate);
} else {
// For notifications with more than one channel, update notification enabled
// state. If the importance was lowered, we disable notifications.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index 76c5baf..3622f1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -36,6 +36,7 @@
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.HotspotController.Callback;
import com.android.systemui.util.UserAwareController;
+import com.android.systemui.util.settings.SecureSettings;
import java.util.ArrayList;
import java.util.Objects;
@@ -60,6 +61,7 @@
protected final Context mContext;
protected final QSTileHost mHost;
protected final Handler mHandler;
+ protected final SecureSettings mSecureSettings;
protected final AutoAddTracker mAutoTracker;
private final HotspotController mHotspotController;
private final DataSaverController mDataSaverController;
@@ -71,6 +73,7 @@
public AutoTileManager(Context context, AutoAddTracker.Builder autoAddTrackerBuilder,
QSTileHost host,
@Background Handler handler,
+ SecureSettings secureSettings,
HotspotController hotspotController,
DataSaverController dataSaverController,
ManagedProfileController managedProfileController,
@@ -78,6 +81,7 @@
CastController castController) {
mContext = context;
mHost = host;
+ mSecureSettings = secureSettings;
mCurrentUser = mHost.getUserContext().getUser();
mAutoTracker = autoAddTrackerBuilder.setUserId(mCurrentUser.getIdentifier()).build();
mHandler = handler;
@@ -170,7 +174,7 @@
String spec = split[1];
// Populate all the settings. As they may not have been added in other users
AutoAddSetting s = new AutoAddSetting(
- mContext, mHandler, setting, mCurrentUser.getIdentifier(), spec);
+ mSecureSettings, mHandler, setting, mCurrentUser.getIdentifier(), spec);
mAutoAddSettingList.add(s);
} else {
Log.w(TAG, "Malformed item in array: " + tile);
@@ -321,13 +325,13 @@
private final String mSpec;
AutoAddSetting(
- Context context,
+ SecureSettings secureSettings,
Handler handler,
String setting,
int userId,
String tileSpec
) {
- super(context, handler, setting, userId);
+ super(secureSettings, handler, setting, userId);
mSpec = tileSpec;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index bd22893..5c225e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -257,7 +257,7 @@
// TODO(b/12836565) - prototyping only adjustment
if (mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL) {
// This will keep the clock at the top for AOD
- darkAmount = 0f;
+ return (int) (clockY + burnInPreventionOffsetY() + mEmptyDragAmount);
}
return (int) (MathUtils.lerp(clockY, clockYDark, darkAmount) + mEmptyDragAmount);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
index 5e883be..289ff71 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
@@ -39,7 +39,6 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.R;
-import com.android.systemui.biometrics.AuthController;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
@@ -77,7 +76,6 @@
private final KeyguardStateController mKeyguardStateController;
private final Resources mResources;
private final HeadsUpManagerPhone mHeadsUpManagerPhone;
- private final AuthController mAuthController;
private boolean mKeyguardShowing;
private boolean mKeyguardJustShown;
private boolean mBlockUpdates;
@@ -326,8 +324,7 @@
@Nullable DockManager dockManager,
KeyguardStateController keyguardStateController,
@Main Resources resources,
- HeadsUpManagerPhone headsUpManagerPhone,
- AuthController authController) {
+ HeadsUpManagerPhone headsUpManagerPhone) {
mLockscreenGestureLogger = lockscreenGestureLogger;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
@@ -342,7 +339,6 @@
mKeyguardStateController = keyguardStateController;
mResources = resources;
mHeadsUpManagerPhone = headsUpManagerPhone;
- mAuthController = authController;
mKeyguardIndicationController.setLockIconController(this);
}
@@ -508,7 +504,7 @@
* @return true if the visibility changed
*/
private boolean updateIconVisibility() {
- if (mAuthController.isUdfpsEnrolled()) {
+ if (mKeyguardUpdateMonitor.isUdfpsEnrolled()) {
boolean changed = mLockIcon.getVisibility() == GONE;
mLockIcon.setVisibility(GONE);
return changed;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index f2ae3da..ac91b70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -19,7 +19,6 @@
import com.android.settingslib.Utils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
@@ -32,10 +31,14 @@
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
+import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.stack.AnimationProperties;
+import com.android.wm.shell.bubbles.Bubbles;
import java.util.ArrayList;
import java.util.List;
@@ -175,6 +178,16 @@
updateIconLayoutParams(mContext);
}
+ /**
+ * Update position of the view, with optional animation
+ */
+ public void updatePosition(int x, AnimationProperties props, boolean animate) {
+ if (mAodIcons != null) {
+ PropertyAnimator.setProperty(mAodIcons, AnimatableProperty.TRANSLATION_X, x, props,
+ animate);
+ }
+ }
+
public void setupShelf(NotificationShelfController notificationShelfController) {
mShelfIcons = notificationShelfController.getShelfIcons();
notificationShelfController.setCollapsedIcons(mNotificationIcons);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index e9a7132..231d157 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -873,7 +873,7 @@
clockPreferredY, hasCustomClock(),
hasVisibleNotifications, mInterpolatedDarkAmount, mEmptyDragAmount,
bypassEnabled, getUnlockedStackScrollerPadding(),
- mAuthController.isUdfpsEnrolled());
+ mUpdateMonitor.isUdfpsEnrolled());
mClockPositionAlgorithm.run(mClockPositionResult);
mKeyguardStatusViewController.updatePosition(
mClockPositionResult.clockX, mClockPositionResult.clockY, animateClock);
@@ -914,7 +914,7 @@
- Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding)
- mKeyguardStatusViewController.getLogoutButtonHeight();
- if (mAuthController.isUdfpsEnrolled()) {
+ if (mUpdateMonitor.isUdfpsEnrolled()) {
availableSpace = mNotificationStackScrollLayoutController.getHeight()
- minPadding - shelfSize
- (mStatusBar.getDisplayHeight() - mAuthController.getUdfpsRegion().top);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java
index af2f3e5..a930a89 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java
@@ -22,13 +22,13 @@
import android.view.WindowManager;
import com.android.systemui.assist.AssistManager;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.wm.shell.bubbles.Bubbles;
import java.util.ArrayList;
import java.util.Optional;
@@ -51,7 +51,7 @@
private final int mDisplayId;
protected final Lazy<StatusBar> mStatusBarLazy;
private final Lazy<AssistManager> mAssistManagerLazy;
- private final Optional<Lazy<Bubbles>> mBubblesOptional;
+ private final Optional<Bubbles> mBubblesOptional;
private final ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>();
@@ -64,7 +64,7 @@
WindowManager windowManager,
Lazy<StatusBar> statusBarLazy,
Lazy<AssistManager> assistManagerLazy,
- Optional<Lazy<Bubbles>> bubblesOptional
+ Optional<Bubbles> bubblesOptional
) {
mCommandQueue = commandQueue;
mStatusBarStateController = statusBarStateController;
@@ -135,7 +135,7 @@
getStatusBar().getNotificationShadeWindowViewController().cancelExpandHelper();
getStatusBarView().collapsePanel(true /* animate */, delayed, speedUpFactor);
} else if (mBubblesOptional.isPresent()) {
- mBubblesOptional.get().get().collapseStack();
+ mBubblesOptional.get().collapseStack();
}
}
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 a8d4104..5c7f54b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -144,7 +144,6 @@
import com.android.systemui.SystemUI;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.charging.WirelessChargingAnimation;
import com.android.systemui.classifier.FalsingLog;
import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -229,6 +228,7 @@
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.volume.VolumeComponent;
import com.android.systemui.wmshell.BubblesManager;
+import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.splitscreen.SplitScreen;
import java.io.FileDescriptor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index b69da85..13d5bf5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -31,7 +31,6 @@
import com.android.systemui.InitController;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -98,6 +97,7 @@
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.volume.VolumeComponent;
import com.android.systemui.wmshell.BubblesManager;
+import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.splitscreen.SplitScreen;
import java.util.Optional;
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index e79d432..4b4e1df 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -26,7 +26,6 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QuickQSPanel;
-import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import java.lang.reflect.InvocationTargetException;
@@ -104,11 +103,6 @@
* Creates the QuickQSPanel.
*/
QuickQSPanel createQuickQSPanel();
-
- /**
- * Creates the QSCustomizer.
- */
- QSCustomizer createQSCustomizer();
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index ad596c2..844f12e 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -27,10 +27,10 @@
import static android.service.notification.NotificationStats.DISMISSAL_BUBBLE;
import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import android.app.INotificationManager;
import android.app.Notification;
@@ -53,8 +53,6 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dumpable;
-import com.android.systemui.bubbles.BubbleEntry;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.model.SysUiState;
@@ -80,6 +78,8 @@
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.wm.shell.bubbles.BubbleEntry;
+import com.android.wm.shell.bubbles.Bubbles;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 91ae08e..bdca503 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -18,21 +18,27 @@
import android.app.IActivityManager;
import android.content.Context;
+import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.view.IWindowManager;
+import android.view.WindowManager;
import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.bubbles.Bubbles;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.dagger.WMSingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.wm.shell.ShellDump;
import com.android.wm.shell.ShellInit;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.bubbles.BubbleController;
+import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.common.AnimationThread;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.HandlerExecutor;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
@@ -116,6 +122,18 @@
@WMSingleton
@Provides
+ static FloatingContentCoordinator provideFloatingContentCoordinator() {
+ return new FloatingContentCoordinator();
+ }
+
+ @WMSingleton
+ @Provides
+ static WindowManagerShellWrapper provideWindowManagerShellWrapper() {
+ return new WindowManagerShellWrapper();
+ }
+
+ @WMSingleton
+ @Provides
static PipAppOpsListener providePipAppOpsListener(Context context,
IActivityManager activityManager,
PipTouchHandler pipTouchHandler) {
@@ -166,8 +184,21 @@
@BindsOptionalOf
abstract SplitScreen optionalSplitScreen();
- @BindsOptionalOf
- abstract Bubbles optionalBubbles();
+ @WMSingleton
+ @Provides
+ static Optional<Bubbles> provideBubbles(Context context,
+ FloatingContentCoordinator floatingContentCoordinator,
+ IStatusBarService statusBarService,
+ WindowManager windowManager,
+ WindowManagerShellWrapper windowManagerShellWrapper,
+ LauncherApps launcherApps,
+ UiEventLogger uiEventLogger,
+ @Main Handler mainHandler,
+ ShellTaskOrganizer organizer) {
+ return Optional.of(BubbleController.create(context, null /* synchronizer */,
+ floatingContentCoordinator, statusBarService, windowManager,
+ windowManagerShellWrapper, launcherApps, uiEventLogger, mainHandler, organizer));
+ }
@WMSingleton
@Provides
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index e5847b0..f1c687f 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -63,7 +63,7 @@
</intent-filter>
</receiver>
- <activity android:name="com.android.systemui.bubbles.BubblesTestActivity"
+ <activity android:name=".wmshell.BubblesTestActivity"
android:allowEmbedded="true"
android:documentLaunchMode="always"
android:excludeFromRecents="true"
diff --git a/packages/SystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java b/packages/SystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
index 594f0b1..cbd6e86 100644
--- a/packages/SystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
+++ b/packages/SystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
@@ -116,6 +116,13 @@
filter.add(s -> s.startsWith("com.android.systemui")
|| s.startsWith("com.android.keyguard"));
+ // Screenshots run in an isolated process and should not be run
+ // with the main process dependency graph because it will not exist
+ // at runtime and could lead to incorrect tests which assume
+ // the main SystemUI process. Therefore, exclude this package
+ // from the base class whitelist.
+ filter.add(s -> !s.startsWith("com.android.systemui.screenshot"));
+
try {
return scanner.getClassPathEntries(filter);
} catch (IOException e) {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index caab2ab..d78090a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -201,7 +201,7 @@
when(mTelephonyManager.getServiceStateForSubscriber(anyInt()))
.thenReturn(new ServiceState());
when(mLockPatternUtils.getLockSettings()).thenReturn(mLockSettings);
- when(mAuthController.isUdfpsEnrolled()).thenReturn(false);
+ when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false);
mSpiedContext.addMockSystemService(TrustManager.class, mTrustManager);
mSpiedContext.addMockSystemService(FingerprintManager.class, mFingerprintManager);
mSpiedContext.addMockSystemService(BiometricManager.class, mBiometricManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index 0c87f59..59262cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -64,6 +64,8 @@
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.tuner.TunerService;
+import com.android.systemui.util.settings.FakeSettings;
+import com.android.systemui.util.settings.SecureSettings;
import org.junit.Before;
import org.junit.Test;
@@ -84,6 +86,7 @@
private ScreenDecorations mScreenDecorations;
private WindowManager mWindowManager;
private DisplayManager mDisplayManager;
+ private SecureSettings mSecureSettings;
private Handler mMainHandler;
@Mock
private TunerService mTunerService;
@@ -98,6 +101,7 @@
mTestableLooper = TestableLooper.get(this);
mMainHandler = new Handler(mTestableLooper.getLooper());
+ mSecureSettings = new FakeSettings();
mWindowManager = mock(WindowManager.class);
WindowMetrics metrics = mContext.getSystemService(WindowManager.class)
@@ -111,7 +115,7 @@
when(mDisplayManager.getDisplay(anyInt())).thenReturn(display);
mContext.addMockSystemService(DisplayManager.class, mDisplayManager);
- mScreenDecorations = spy(new ScreenDecorations(mContext, mMainHandler,
+ mScreenDecorations = spy(new ScreenDecorations(mContext, mMainHandler, mSecureSettings,
mBroadcastDispatcher, mTunerService, mUserTracker) {
@Override
public void start() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index a39bc70..f28322f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -275,6 +275,7 @@
@Test
public void performA11yActions_visible_expectedResults() {
+ final int displayId = mContext.getDisplayId();
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnification(2.5f, Float.NaN,
Float.NaN);
@@ -284,10 +285,10 @@
assertTrue(
mMirrorView.performAccessibilityAction(R.id.accessibility_action_zoom_out, null));
// Minimum scale is 2.0.
- assertEquals(2.0f, mWindowMagnificationController.getScale(), 0f);
+ verify(mWindowMagnifierCallback).onPerformScaleAction(eq(displayId), eq(2.0f));
assertTrue(mMirrorView.performAccessibilityAction(R.id.accessibility_action_zoom_in, null));
- assertEquals(3.0f, mWindowMagnificationController.getScale(), 0f);
+ verify(mWindowMagnifierCallback).onPerformScaleAction(eq(displayId), eq(3.5f));
// TODO: Verify the final state when the mirror surface is visible.
assertTrue(mMirrorView.performAccessibilityAction(R.id.accessibility_action_move_up, null));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
index 4a0e216..ad1ce76 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
@@ -18,6 +18,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
@@ -42,7 +43,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@SmallTest
@@ -56,6 +56,8 @@
private ModeSwitchesController mModeSwitchesController;
@Mock
private NavigationModeController mNavigationModeController;
+ @Mock
+ private IWindowMagnificationConnectionCallback mConnectionCallback;
private CommandQueue mCommandQueue;
private WindowMagnification mWindowMagnification;
@@ -63,6 +65,12 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
getContext().addMockSystemService(Context.ACCESSIBILITY_SERVICE, mAccessibilityManager);
+ doAnswer(invocation -> {
+ IWindowMagnificationConnection connection = invocation.getArgument(0);
+ connection.setConnectionCallback(mConnectionCallback);
+ return null;
+ }).when(mAccessibilityManager).setWindowMagnificationConnection(
+ any(IWindowMagnificationConnection.class));
mCommandQueue = new CommandQueue(getContext());
mWindowMagnification = new WindowMagnification(getContext(),
@@ -87,25 +95,29 @@
@Test
public void onWindowMagnifierBoundsChanged() throws RemoteException {
- final IWindowMagnificationConnectionCallback connectionCallback = Mockito.mock(
- IWindowMagnificationConnectionCallback.class);
final Rect testBounds = new Rect(0, 0, 500, 600);
- doAnswer(invocation -> {
- IWindowMagnificationConnection connection = invocation.getArgument(0);
- connection.setConnectionCallback(connectionCallback);
- return null;
- }).when(mAccessibilityManager).setWindowMagnificationConnection(
- any(IWindowMagnificationConnection.class));
mCommandQueue.requestWindowMagnificationConnection(true);
waitForIdleSync();
mWindowMagnification.onWindowMagnifierBoundsChanged(Display.DEFAULT_DISPLAY, testBounds);
- verify(connectionCallback).onWindowMagnifierBoundsChanged(Display.DEFAULT_DISPLAY,
+ verify(mConnectionCallback).onWindowMagnifierBoundsChanged(Display.DEFAULT_DISPLAY,
testBounds);
}
@Test
+ public void onPerformScaleAction_enabled_notifyCallback() throws RemoteException {
+ final float newScale = 4.0f;
+ mCommandQueue.requestWindowMagnificationConnection(true);
+ waitForIdleSync();
+
+ mWindowMagnification.onPerformScaleAction(Display.DEFAULT_DISPLAY, newScale);
+
+ verify(mConnectionCallback).onPerformScaleAction(eq(Display.DEFAULT_DISPLAY),
+ eq(newScale));
+ }
+
+ @Test
public void onConfigurationChanged_updateModeSwitches() {
final Configuration config = new Configuration();
config.densityDpi = Configuration.DENSITY_DPI_ANY;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index 5218886..6e21642 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -50,6 +50,7 @@
private static final String TEST_DEVICE_NAME_2 = "test_device_name_2";
private static final String TEST_DEVICE_ID_1 = "test_device_id_1";
private static final String TEST_DEVICE_ID_2 = "test_device_id_2";
+ private static final String TEST_SESSION_NAME = "test_session_name";
// Mock
private MediaOutputController mMediaOutputController = mock(MediaOutputController.class);
@@ -102,6 +103,14 @@
}
@Test
+ public void getItemCount_withDynamicGroup_containExtraOneForGroup() {
+ when(mMediaOutputController.getSelectedMediaDevice()).thenReturn(mMediaDevices);
+ when(mMediaOutputController.isZeroMode()).thenReturn(false);
+
+ assertThat(mMediaOutputAdapter.getItemCount()).isEqualTo(mMediaDevices.size() + 1);
+ }
+
+ @Test
public void onBindViewHolder_zeroMode_bindPairNew_verifyView() {
when(mMediaOutputController.isZeroMode()).thenReturn(true);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 2);
@@ -118,6 +127,45 @@
}
@Test
+ public void onBindViewHolder_bindGroup_withSessionName_verifyView() {
+ when(mMediaOutputController.getSelectedMediaDevice()).thenReturn(mMediaDevices);
+ when(mMediaOutputController.isZeroMode()).thenReturn(false);
+ when(mMediaOutputController.getSessionName()).thenReturn(TEST_SESSION_NAME);
+ mMediaOutputAdapter.getItemCount();
+ mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
+
+ assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_SESSION_NAME);
+ }
+
+ @Test
+ public void onBindViewHolder_bindGroup_noSessionName_verifyView() {
+ when(mMediaOutputController.getSelectedMediaDevice()).thenReturn(mMediaDevices);
+ when(mMediaOutputController.isZeroMode()).thenReturn(false);
+ when(mMediaOutputController.getSessionName()).thenReturn(null);
+ mMediaOutputAdapter.getItemCount();
+ mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
+
+ assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(mContext.getString(
+ R.string.media_output_dialog_group));
+ }
+
+ @Test
public void onBindViewHolder_bindConnectedDevice_verifyView() {
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java
index 3494bd6..fa29fd4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java
@@ -49,7 +49,6 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.recents.OverviewProxyService;
import org.junit.Before;
@@ -66,7 +65,6 @@
private KeyButtonView mKeyButtonView;
private MetricsLogger mMetricsLogger;
- private Bubbles mBubbles;
private UiEventLogger mUiEventLogger;
private InputManager mInputManager = mock(InputManager.class);
@Captor
@@ -76,7 +74,6 @@
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
- mBubbles = mDependency.injectMockDependency(Bubbles.class);
mDependency.injectMockDependency(OverviewProxyService.class);
mUiEventLogger = mDependency.injectMockDependency(UiEventLogger.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
index 8039192..c050b62 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
@@ -52,7 +52,7 @@
private MetricsLogger mMetricsLogger;
private QSDetail mQsDetail;
- private QSPanel mQsPanel;
+ private QSPanelController mQsPanelController;
private QuickStatusBarHeader mQuickHeader;
private ActivityStarter mActivityStarter;
private DetailAdapter mMockDetailAdapter;
@@ -68,9 +68,9 @@
mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
mActivityStarter = mDependency.injectMockDependency(ActivityStarter.class);
mQsDetail = (QSDetail) LayoutInflater.from(mContext).inflate(R.layout.qs_detail, null);
- mQsPanel = mock(QSPanel.class);
+ mQsPanelController = mock(QSPanelController.class);
mQuickHeader = mock(QuickStatusBarHeader.class);
- mQsDetail.setQsPanel(mQsPanel, mQuickHeader, mock(QSFooter.class));
+ mQsDetail.setQsPanel(mQsPanelController, mQuickHeader, mock(QSFooter.class));
mMockDetailAdapter = mock(DetailAdapter.class);
when(mMockDetailAdapter.createDetailView(any(), any(), any()))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
index bf0e084..64ef6dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
@@ -38,6 +38,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QSTileView;
+import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import org.junit.Before;
@@ -61,6 +62,12 @@
@Mock
private QSTileHost mQSTileHost;
@Mock
+ private QSCustomizerController mQSCustomizerController;
+ @Mock
+ private QSTileRevealController.Factory mQSTileRevealControllerFactory;
+ @Mock
+ private QSTileRevealController mQSTileRevealController;
+ @Mock
private MediaHost mMediaHost;
@Mock
private MetricsLogger mMetricsLogger;
@@ -70,15 +77,19 @@
QSTileImpl mQSTile;
@Mock
QSTileView mQSTileView;
+ @Mock
+ PagedTileLayout mPagedTileLayout;
private QSPanelControllerBase<QSPanel> mController;
/** Implementation needed to ensure we have a reflectively-available class name. */
private static class TestableQSPanelControllerBase extends QSPanelControllerBase<QSPanel> {
protected TestableQSPanelControllerBase(QSPanel view, QSTileHost host,
- MetricsLogger metricsLogger,
- UiEventLogger uiEventLogger, DumpManager dumpManager) {
- super(view, host, metricsLogger, uiEventLogger, dumpManager);
+ QSCustomizerController qsCustomizerController,
+ QSTileRevealController.Factory qsTileRevealControllerFactory,
+ MetricsLogger metricsLogger, UiEventLogger uiEventLogger, DumpManager dumpManager) {
+ super(view, host, qsCustomizerController, qsTileRevealControllerFactory, metricsLogger,
+ uiEventLogger, dumpManager);
}
}
@@ -91,11 +102,14 @@
when(mQSPanel.getDumpableTag()).thenReturn("QSPanel");
when(mQSPanel.openPanelEvent()).thenReturn(QSEvent.QS_PANEL_EXPANDED);
when(mQSPanel.closePanelEvent()).thenReturn(QSEvent.QS_PANEL_COLLAPSED);
+ when(mQSPanel.createRegularTileLayout()).thenReturn(mPagedTileLayout);
when(mQSTileHost.getTiles()).thenReturn(Collections.singleton(mQSTile));
when(mQSTileHost.createTileView(eq(mQSTile), anyBoolean())).thenReturn(mQSTileView);
+ when(mQSTileRevealControllerFactory.create(any())).thenReturn(mQSTileRevealController);
mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
- mMetricsLogger, mUiEventLogger, mDumpManager);
+ mQSCustomizerController, mQSTileRevealControllerFactory, mMetricsLogger,
+ mUiEventLogger, mDumpManager);
mController.init();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
index 0ba0214..bce376a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
@@ -35,6 +35,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QSTileView;
+import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.settings.BrightnessController;
import com.android.systemui.settings.ToggleSlider;
@@ -58,6 +59,12 @@
@Mock
private QSTileHost mQSTileHost;
@Mock
+ private QSCustomizerController mQSCustomizerController;
+ @Mock
+ private QSTileRevealController.Factory mQSTileRevealControllerFactory;
+ @Mock
+ private QSTileRevealController mQSTileRevealController;
+ @Mock
private MediaHost mMediaHost;
@Mock
private MetricsLogger mMetricsLogger;
@@ -75,6 +82,9 @@
QSTileImpl mQSTile;
@Mock
QSTileView mQSTileView;
+ @Mock
+ PagedTileLayout mPagedTileLayout;
+
private QSPanelController mController;
@@ -85,14 +95,16 @@
when(mQSPanel.getMediaHost()).thenReturn(mMediaHost);
when(mQSPanel.isAttachedToWindow()).thenReturn(true);
when(mQSPanel.getDumpableTag()).thenReturn("QSPanel");
+ when(mQSPanel.createRegularTileLayout()).thenReturn(mPagedTileLayout);
when(mQSTileHost.getTiles()).thenReturn(Collections.singleton(mQSTile));
when(mQSTileHost.createTileView(eq(mQSTile), anyBoolean())).thenReturn(mQSTileView);
when(mBrightnessControllerFactory.create(any(ToggleSlider.class)))
.thenReturn(mBrightnessController);
+ when(mQSTileRevealControllerFactory.create(any())).thenReturn(mQSTileRevealController);
mController = new QSPanelController(mQSPanel, mQSSecurityFooter, mTunerService,
- mQSTileHost, mDumpManager, mMetricsLogger, mUiEventLogger,
- mBrightnessControllerFactory);
+ mQSTileHost, mQSCustomizerController, mQSTileRevealControllerFactory, mDumpManager,
+ mMetricsLogger, mUiEventLogger, mBrightnessControllerFactory);
mController.init();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
index e38d54b..450ffac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
@@ -39,7 +39,6 @@
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QSTileView;
-import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.policy.SecurityController;
@@ -65,12 +64,8 @@
@Mock
private QSTileHost mHost;
@Mock
- private QSCustomizer mCustomizer;
- @Mock
private QSTileImpl dndTile;
@Mock
- private QSTileImpl mNonTile;
- @Mock
private QSPanelControllerBase.TileRecord mDndTileRecord;
@Mock
private QSLogger mQSLogger;
@@ -84,7 +79,6 @@
@Mock
private ActivityStarter mActivityStarter;
private UiEventLoggerFake mUiEventLogger;
- private String mCachedSpecs = "";
@Before
public void setup() throws Exception {
@@ -113,8 +107,6 @@
when(dndTile.getTileSpec()).thenReturn("dnd");
when(mHost.getTiles()).thenReturn(Collections.emptyList());
when(mHost.createTileView(any(), anyBoolean())).thenReturn(mQSTileView);
-
- mQsPanel.setCustomizer(mCustomizer);
mQsPanel.addTile(mDndTileRecord);
mQsPanel.setCallback(mCallback);
});
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/SecureSettingTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/SecureSettingTest.kt
new file mode 100644
index 0000000..418fa61
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/SecureSettingTest.kt
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.qs
+
+import android.os.Handler
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.settings.FakeSettings
+import com.android.systemui.util.settings.SecureSettings
+import com.google.common.truth.Truth.assertThat
+import junit.framework.Assert.fail
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private typealias Callback = (Int, Boolean) -> Unit
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class SecureSettingTest : SysuiTestCase() {
+
+ companion object {
+ private const val TEST_SETTING = "setting"
+ private const val USER = 0
+ private const val OTHER_USER = 1
+ private val FAIL_CALLBACK: Callback = { _, _ -> fail("Callback should not be called") }
+ }
+
+ private lateinit var testableLooper: TestableLooper
+ private lateinit var setting: SecureSetting
+ private lateinit var secureSettings: SecureSettings
+
+ private lateinit var callback: Callback
+
+ @Before
+ fun setUp() {
+ testableLooper = TestableLooper.get(this)
+ secureSettings = FakeSettings()
+
+ setting = object : SecureSetting(
+ secureSettings,
+ Handler(testableLooper.looper),
+ TEST_SETTING,
+ USER
+ ) {
+ override fun handleValueChanged(value: Int, observedChange: Boolean) {
+ callback(value, observedChange)
+ }
+ }
+
+ // Default empty callback
+ callback = { _, _ -> Unit }
+ }
+
+ @After
+ fun tearDown() {
+ setting.isListening = false
+ }
+
+ @Test
+ fun testNotListeningByDefault() {
+ callback = FAIL_CALLBACK
+
+ assertThat(setting.isListening).isFalse()
+ secureSettings.putIntForUser(TEST_SETTING, 2, USER)
+ testableLooper.processAllMessages()
+ }
+
+ @Test
+ fun testChangedWhenListeningCallsCallback() {
+ var changed = false
+ callback = { _, _ -> changed = true }
+
+ setting.isListening = true
+ secureSettings.putIntForUser(TEST_SETTING, 2, USER)
+ testableLooper.processAllMessages()
+
+ assertThat(changed).isTrue()
+ }
+
+ @Test
+ fun testListensToCorrectSetting() {
+ callback = FAIL_CALLBACK
+
+ setting.isListening = true
+ secureSettings.putIntForUser("other", 2, USER)
+ testableLooper.processAllMessages()
+ }
+
+ @Test
+ fun testGetCorrectValue() {
+ secureSettings.putIntForUser(TEST_SETTING, 2, USER)
+ assertThat(setting.value).isEqualTo(2)
+
+ secureSettings.putIntForUser(TEST_SETTING, 4, USER)
+ assertThat(setting.value).isEqualTo(4)
+ }
+
+ @Test
+ fun testSetValue() {
+ setting.value = 5
+ assertThat(secureSettings.getIntForUser(TEST_SETTING, USER)).isEqualTo(5)
+ }
+
+ @Test
+ fun testChangeUser() {
+ setting.isListening = true
+ setting.setUserId(OTHER_USER)
+
+ setting.isListening = true
+ assertThat(setting.currentUser).isEqualTo(OTHER_USER)
+ }
+
+ @Test
+ fun testDoesntListenInOtherUsers() {
+ callback = FAIL_CALLBACK
+ setting.isListening = true
+
+ secureSettings.putIntForUser(TEST_SETTING, 3, OTHER_USER)
+ testableLooper.processAllMessages()
+ }
+
+ @Test
+ fun testListensToCorrectUserAfterChange() {
+ var changed = false
+ callback = { _, _ -> changed = true }
+
+ setting.isListening = true
+ setting.setUserId(OTHER_USER)
+ secureSettings.putIntForUser(TEST_SETTING, 2, OTHER_USER)
+ testableLooper.processAllMessages()
+
+ assertThat(changed).isTrue()
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
index 204de929..3d53062 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
@@ -15,7 +15,6 @@
package com.android.systemui.qs.customize;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import android.testing.AndroidTestingRunner;
@@ -31,6 +30,8 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.util.Collections;
@@ -40,17 +41,20 @@
public class TileAdapterTest extends SysuiTestCase {
private TileAdapter mTileAdapter;
+ @Mock
+ private QSTileHost mQSTileHost;
@Before
public void setup() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
TestableLooper.get(this).runWithLooper(() -> mTileAdapter =
- new TileAdapter(mContext, new UiEventLoggerFake()));
+ new TileAdapter(mContext, mQSTileHost, new UiEventLoggerFake()));
}
@Test
public void testResetNotifiesHost() {
- QSTileHost host = mock(QSTileHost.class);
- mTileAdapter.resetTileSpecs(host, Collections.emptyList());
- verify(host).changeTiles(any(), any());
+ mTileAdapter.resetTileSpecs(Collections.emptyList());
+ verify(mQSTileHost).changeTiles(any(), any());
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
index 2006a75..bcfc835 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
@@ -29,6 +29,8 @@
import com.android.systemui.qs.QSHost
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.statusbar.policy.BatteryController
+import com.android.systemui.util.settings.FakeSettings
+import com.android.systemui.util.settings.SecureSettings
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
@@ -60,6 +62,7 @@
private lateinit var qsLogger: QSLogger
@Mock
private lateinit var batteryController: BatteryController
+ private lateinit var secureSettings: SecureSettings
private lateinit var testableLooper: TestableLooper
private lateinit var tile: BatterySaverTile
@@ -70,6 +73,8 @@
`when`(qsHost.userContext).thenReturn(userContext)
`when`(userContext.userId).thenReturn(USER)
+ secureSettings = FakeSettings()
+
tile = BatterySaverTile(
qsHost,
testableLooper.looper,
@@ -78,7 +83,8 @@
statusBarStateController,
activityStarter,
qsLogger,
- batteryController)
+ batteryController,
+ secureSettings)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScrollCaptureConnection.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScrollCaptureConnection.java
new file mode 100644
index 0000000..a75c39c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScrollCaptureConnection.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.screenshot;
+
+import android.content.pm.ActivityInfo;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.HardwareRenderer;
+import android.graphics.Paint;
+import android.graphics.RecordingCanvas;
+import android.graphics.Rect;
+import android.graphics.RenderNode;
+import android.os.RemoteException;
+import android.view.IScrollCaptureCallbacks;
+import android.view.IScrollCaptureConnection;
+import android.view.Surface;
+
+/**
+ * An IScrollCaptureConnection which returns a sequence of solid filled rectangles in the
+ * locations requested, in alternating colors.
+ */
+class FakeScrollCaptureConnection extends IScrollCaptureConnection.Stub {
+ private final int[] mColors = {Color.RED, Color.GREEN, Color.BLUE};
+ private IScrollCaptureCallbacks mCallbacks;
+ private Surface mSurface;
+ private Paint mPaint;
+ private int mNextColor;
+ private HwuiContext mHwuiContext;
+
+ FakeScrollCaptureConnection(IScrollCaptureCallbacks cb) {
+ mCallbacks = cb;
+ }
+
+ @Override
+ public void startCapture(Surface surface) {
+ mSurface = surface;
+ mHwuiContext = new HwuiContext(false, surface);
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaint.setStyle(Paint.Style.FILL);
+ try {
+ mCallbacks.onCaptureStarted();
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ }
+
+ @Override
+ public void requestImage(Rect rect) {
+ Canvas canvas = mHwuiContext.lockCanvas(rect.width(), rect.height());
+ mPaint.setColor(mColors[mNextColor]);
+ canvas.drawRect(rect, mPaint);
+ mNextColor = (mNextColor++) % mColors.length;
+ long frameNumber = mSurface.getNextFrameNumber();
+ mHwuiContext.unlockAndPost(canvas);
+ try {
+ mCallbacks.onCaptureBufferSent(frameNumber, rect);
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ }
+
+ @Override
+ public void endCapture() {
+ try {
+ mCallbacks.onConnectionClosed();
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ } finally {
+ mHwuiContext.destroy();
+ mSurface = null;
+ mCallbacks = null;
+ }
+ }
+
+ // From android.view.Surface, but issues render requests synchronously with waitForPresent(true)
+ private static final class HwuiContext {
+ private final RenderNode mRenderNode;
+ private final HardwareRenderer mHardwareRenderer;
+ private RecordingCanvas mCanvas;
+ private final boolean mIsWideColorGamut;
+
+ HwuiContext(boolean isWideColorGamut, Surface surface) {
+ mRenderNode = RenderNode.create("HwuiCanvas", null);
+ mRenderNode.setClipToBounds(false);
+ mRenderNode.setForceDarkAllowed(false);
+ mIsWideColorGamut = isWideColorGamut;
+
+ mHardwareRenderer = new HardwareRenderer();
+ mHardwareRenderer.setContentRoot(mRenderNode);
+ mHardwareRenderer.setSurface(surface, true);
+ mHardwareRenderer.setColorMode(
+ isWideColorGamut
+ ? ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT
+ : ActivityInfo.COLOR_MODE_DEFAULT);
+ mHardwareRenderer.setLightSourceAlpha(0.0f, 0.0f);
+ mHardwareRenderer.setLightSourceGeometry(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+
+ Canvas lockCanvas(int width, int height) {
+ if (mCanvas != null) {
+ throw new IllegalStateException("Surface was already locked!");
+ }
+ mCanvas = mRenderNode.beginRecording(width, height);
+ return mCanvas;
+ }
+
+ void unlockAndPost(Canvas canvas) {
+ if (canvas != mCanvas) {
+ throw new IllegalArgumentException("canvas object must be the same instance that "
+ + "was previously returned by lockCanvas");
+ }
+ mRenderNode.endRecording();
+ mCanvas = null;
+ mHardwareRenderer.createRenderRequest()
+ .setVsyncTime(System.nanoTime())
+ .setWaitForPresent(true) // sync!
+ .syncAndDraw();
+ }
+
+ void destroy() {
+ mHardwareRenderer.destroy();
+ }
+
+ boolean isWideColorGamut() {
+ return mIsWideColorGamut;
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
new file mode 100644
index 0000000..4aa730e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.screenshot;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+import static java.util.Objects.requireNonNull;
+
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
+import android.os.RemoteException;
+import android.testing.AndroidTestingRunner;
+import android.view.Display;
+import android.view.IScrollCaptureCallbacks;
+import android.view.IWindowManager;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.screenshot.ScrollCaptureClient.CaptureResult;
+import com.android.systemui.screenshot.ScrollCaptureClient.Connection;
+import com.android.systemui.screenshot.ScrollCaptureClient.Session;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.mockito.stubbing.Answer;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class ScrollCaptureClientTest extends SysuiTestCase {
+ private Context mContext;
+ private IWindowManager mWm;
+
+ @Spy private TestableConsumer<Session> mSessionConsumer;
+ @Spy private TestableConsumer<Connection> mConnectionConsumer;
+ @Spy private TestableConsumer<CaptureResult> mResultConsumer;
+ @Mock private Runnable mRunnable;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ DisplayManager displayManager = requireNonNull(
+ context.getSystemService(DisplayManager.class));
+ mContext = context.createDisplayContext(
+ displayManager.getDisplay(Display.DEFAULT_DISPLAY));
+ mWm = mock(IWindowManager.class);
+ }
+
+ @Test
+ public void testBasicClientFlow() throws RemoteException {
+ doAnswer((Answer<Void>) invocation -> {
+ IScrollCaptureCallbacks cb = invocation.getArgument(3);
+ cb.onConnected(
+ new FakeScrollCaptureConnection(cb),
+ /* scrollBounds */ new Rect(0, 0, 100, 100),
+ /* positionInWindow */ new Point(0, 0));
+ return null;
+ }).when(mWm).requestScrollCapture(/* displayId */ anyInt(), /* token */ isNull(),
+ /* taskId */ anyInt(), any(IScrollCaptureCallbacks.class));
+
+ // Create client
+ ScrollCaptureClient client = new ScrollCaptureClient(mContext, mWm);
+
+ client.request(Display.DEFAULT_DISPLAY, mConnectionConsumer);
+ verify(mConnectionConsumer, timeout(100)).accept(any(Connection.class));
+
+ Connection conn = mConnectionConsumer.getValue();
+
+ conn.start(5, mSessionConsumer);
+ verify(mSessionConsumer, timeout(100)).accept(any(Session.class));
+
+ Session session = mSessionConsumer.getValue();
+ Rect request = new Rect(0, 0, session.getMaxTileWidth(), session.getMaxTileHeight());
+
+ session.requestTile(request, mResultConsumer);
+ verify(mResultConsumer, timeout(100)).accept(any(CaptureResult.class));
+
+ CaptureResult result = mResultConsumer.getValue();
+ assertThat(result.requested).isEqualTo(request);
+ assertThat(result.captured).isEqualTo(result.requested);
+ assertThat(result.image).isNotNull();
+
+ session.end(mRunnable);
+ verify(mRunnable, timeout(100)).run();
+
+ // TODO verify image
+ // TODO test threading
+ // TODO test failures
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TestableConsumer.java
similarity index 63%
copy from packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
copy to packages/SystemUI/tests/src/com/android/systemui/screenshot/TestableConsumer.java
index 24768cd..a554e5f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TestableConsumer.java
@@ -13,17 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
-import android.annotation.DimenRes
-import android.annotation.UserIdInt
+package com.android.systemui.screenshot;
-data class BubbleEntity(
- @UserIdInt val userId: Int,
- val packageName: String,
- val shortcutId: String,
- val key: String,
- val desiredHeight: Int,
- @DimenRes val desiredHeightResId: Int,
- val title: String? = null
-)
+import java.util.function.Consumer;
+
+/** Accepts and retains the most recent value for verification */
+class TestableConsumer<T> implements Consumer<T> {
+ T mValue;
+
+ @Override
+ public void accept(T t) {
+ mValue = t;
+ }
+
+ public T getValue() {
+ return mValue;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 10eca00..7fb7b86 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -36,7 +36,6 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
import com.android.systemui.statusbar.notification.DynamicChildBindController;
@@ -54,6 +53,7 @@
import com.android.systemui.statusbar.notification.stack.ForegroundServiceSectionController;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.wm.shell.bubbles.Bubbles;
import com.google.android.collect.Lists;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
index cd46dda..05cf33a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
@@ -42,7 +42,6 @@
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -54,6 +53,7 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.wm.shell.bubbles.Bubbles;
import org.junit.After;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index 4698b8e..f7dfe0b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -76,12 +76,12 @@
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.BubblesTestActivity;
import com.android.systemui.statusbar.SbnBuilder;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.wmshell.BubblesManager;
+import com.android.systemui.wmshell.BubblesTestActivity;
import org.junit.Before;
import org.junit.Rule;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index b482968..4a2cbcc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -860,6 +860,33 @@
}
@Test
+ public void testHandleCloseControls_persistAutomatic()
+ throws Exception {
+ mNotificationChannel.unlockFields(USER_LOCKED_IMPORTANCE);
+ mNotificationInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ mOnUserInteractionCallback,
+ mChannelEditorDialogController,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ mEntry,
+ null,
+ null,
+ mUiEventLogger,
+ true,
+ false,
+ true,
+ true);
+
+ mNotificationInfo.handleCloseControls(true, false);
+ mTestableLooper.processAllMessages();
+ verify(mMockINotificationManager, times(1)).unlockNotificationChannel(
+ anyString(), eq(TEST_UID), any());
+ }
+
+ @Test
public void testHandleCloseControls_DoesNotUpdateNotificationChannelIfUnchanged()
throws Exception {
int originalImportance = mNotificationChannel.getImportance();
@@ -1015,16 +1042,17 @@
mUiEventLogger,
true,
false,
- false,
- false);
+ true,
+ true);
mNotificationInfo.findViewById(R.id.automatic).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
- assertTrue(mNotificationChannel.hasUserSetImportance());
- assertEquals(mNotificationChannel.getImportance(), IMPORTANCE_DEFAULT);
+ verify(mMockINotificationManager, times(1)).unlockNotificationChannel(
+ anyString(), eq(TEST_UID), any());
+ assertEquals(IMPORTANCE_DEFAULT, mNotificationChannel.getImportance());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 48375e0..baae8fd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -45,8 +45,6 @@
import com.android.systemui.R;
import com.android.systemui.TestableDependency;
-import com.android.systemui.bubbles.Bubbles;
-import com.android.systemui.bubbles.BubblesTestActivity;
import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.plugins.FalsingManager;
@@ -71,6 +69,8 @@
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.InflatedSmartReplies;
import com.android.systemui.wmshell.BubblesManager;
+import com.android.systemui.wmshell.BubblesTestActivity;
+import com.android.wm.shell.bubbles.Bubbles;
import org.mockito.ArgumentCaptor;
@@ -432,7 +432,8 @@
mStatusBarStateController,
mPeopleNotificationIdentifier,
mock(OnUserInteractionCallback.class),
- Optional.of(mock(BubblesManager.class)));
+ Optional.of(mock(BubblesManager.class)),
+ mock(NotificationGutsManager.class));
row.setAboveShelfChangedListener(aboveShelf -> { });
mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index 3ebb77a..82d1f43 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -22,31 +22,22 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.isNotNull;
import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
-import android.content.ContextWrapper;
import android.hardware.display.ColorDisplayManager;
import android.hardware.display.NightDisplayListener;
import android.os.Handler;
import android.os.UserHandle;
-import android.provider.Settings;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableContentResolver;
-import android.testing.TestableContext;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
@@ -61,6 +52,8 @@
import com.android.systemui.statusbar.policy.CastController.CastDevice;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.util.settings.FakeSettings;
+import com.android.systemui.util.settings.SecureSettings;
import org.junit.After;
import org.junit.Before;
@@ -100,10 +93,12 @@
@Mock private Context mUserContext;
private AutoTileManager mAutoTileManager;
+ private SecureSettings mSecureSettings;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mSecureSettings = new FakeSettings();
mContext.getOrCreateTestableResources().addOverride(
R.array.config_quickSettingsAutoAdd,
@@ -119,7 +114,7 @@
when(mQsTileHost.getUserContext()).thenReturn(mUserContext);
when(mUserContext.getUser()).thenReturn(UserHandle.of(USER));
- mAutoTileManager = createAutoTileManager(new MyContextWrapper(mContext));
+ mAutoTileManager = createAutoTileManager(mContext);
mAutoTileManager.init();
}
@@ -138,6 +133,7 @@
CastController castController) {
return new AutoTileManager(context, autoAddTrackerBuilder, mQsTileHost,
Handler.createAsync(TestableLooper.get(this).getLooper()),
+ mSecureSettings,
hotspotController,
dataSaverController,
managedProfileController,
@@ -342,7 +338,6 @@
@Test
public void testSettingTileAdded_onChanged() {
changeValue(TEST_SETTING, 1);
- waitForIdleSync();
verify(mAutoAddTracker).setTileAdded(TEST_SPEC);
verify(mQsTileHost).addTile(TEST_SPEC);
}
@@ -350,7 +345,6 @@
@Test
public void testSettingTileAddedComponentAtEnd_onChanged() {
changeValue(TEST_SETTING_COMPONENT, 1);
- waitForIdleSync();
verify(mAutoAddTracker).setTileAdded(TEST_CUSTOM_SPEC);
verify(mQsTileHost).addTile(ComponentName.unflattenFromString(TEST_COMPONENT)
, /* end */ true);
@@ -359,10 +353,7 @@
@Test
public void testSettingTileAdded_onlyOnce() {
changeValue(TEST_SETTING, 1);
- waitForIdleSync();
- TestableLooper.get(this).processAllMessages();
changeValue(TEST_SETTING, 2);
- waitForIdleSync();
verify(mAutoAddTracker).setTileAdded(TEST_SPEC);
verify(mQsTileHost).addTile(TEST_SPEC);
}
@@ -370,7 +361,6 @@
@Test
public void testSettingTileNotAdded_onChangedTo0() {
changeValue(TEST_SETTING, 0);
- waitForIdleSync();
verify(mAutoAddTracker, never()).setTileAdded(TEST_SPEC);
verify(mQsTileHost, never()).addTile(TEST_SPEC);
}
@@ -380,7 +370,6 @@
when(mAutoAddTracker.isAdded(TEST_SPEC)).thenReturn(true);
changeValue(TEST_SETTING, 1);
- waitForIdleSync();
verify(mAutoAddTracker, never()).setTileAdded(TEST_SPEC);
verify(mQsTileHost, never()).addTile(TEST_SPEC);
}
@@ -401,28 +390,7 @@
// Will only notify if it's listening
private void changeValue(String key, int value) {
- SecureSetting s = mAutoTileManager.getSecureSettingForKey(key);
- Settings.Secure.putInt(mContext.getContentResolver(), key, value);
- if (s != null && s.isListening()) {
- s.onChange(false);
- }
- }
-
- class MyContextWrapper extends ContextWrapper {
-
- private TestableContentResolver mSpiedTCR;
-
- MyContextWrapper(TestableContext context) {
- super(context);
- mSpiedTCR = spy(context.getContentResolver());
- doNothing().when(mSpiedTCR).registerContentObserver(any(), anyBoolean(), any(),
- anyInt());
- doNothing().when(mSpiedTCR).unregisterContentObserver(any());
- }
-
- @Override
- public ContentResolver getContentResolver() {
- return mSpiedTCR;
- }
+ mSecureSettings.putIntForUser(key, value, USER);
+ TestableLooper.get(this).processAllMessages();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
index 72a0258..aca3424 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
@@ -32,7 +32,6 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.biometrics.AuthController;
import com.android.systemui.dock.DockManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -81,25 +80,21 @@
private Resources mResources;
@Mock
private HeadsUpManagerPhone mHeadsUpManagerPhone;
- @Mock
- private AuthController mAuthController;
private LockscreenLockIconController mLockIconController;
private OnAttachStateChangeListener mOnAttachStateChangeListener;
-
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- when(mAuthController.isUdfpsEnrolled()).thenReturn(false);
when(mLockIcon.getContext()).thenReturn(mContext);
mLockIconController = new LockscreenLockIconController(
mLockscreenGestureLogger, mKeyguardUpdateMonitor, mLockPatternUtils,
mShadeController, mAccessibilityController, mKeyguardIndicationController,
mStatusBarStateController, mConfigurationController, mNotificationWakeUpCoordinator,
mKeyguardBypassController, mDockManager, mKeyguardStateController, mResources,
- mHeadsUpManagerPhone, mAuthController);
+ mHeadsUpManagerPhone);
ArgumentCaptor<OnAttachStateChangeListener> onAttachStateChangeListenerArgumentCaptor =
ArgumentCaptor.forClass(OnAttachStateChangeListener.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
index b0086ef..7c8b413 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
@@ -37,7 +37,6 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -48,6 +47,7 @@
import com.android.systemui.statusbar.notification.row.RowContentBindParams;
import com.android.systemui.statusbar.notification.row.RowContentBindStage;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.wm.shell.bubbles.Bubbles;
import org.junit.Before;
import org.junit.Rule;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java
index f81672a..3e9fd51 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java
@@ -30,12 +30,12 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.wm.shell.bubbles.Bubbles;
import org.junit.Before;
import org.junit.Rule;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
index a1d419c..858227f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
@@ -27,7 +27,6 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -35,6 +34,7 @@
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
+import com.android.wm.shell.bubbles.Bubbles;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 3b123f6..e1f8596 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -21,6 +21,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.inOrder;
@@ -204,7 +205,7 @@
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- when(mAuthController.isUdfpsEnrolled()).thenReturn(false);
+ when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false);
when(mHeadsUpCallback.getContext()).thenReturn(mContext);
when(mView.getResources()).thenReturn(mResources);
when(mResources.getConfiguration()).thenReturn(mConfiguration);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 9f096da..2f9b601 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -83,7 +83,6 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.demomode.DemoModeController;
@@ -146,6 +145,7 @@
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.volume.VolumeComponent;
import com.android.systemui.wmshell.BubblesManager;
+import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.splitscreen.SplitScreen;
import org.junit.Before;
@@ -337,7 +337,7 @@
mShadeController = new ShadeControllerImpl(mCommandQueue,
mStatusBarStateController, mNotificationShadeWindowController,
mStatusBarKeyguardViewManager, mContext.getSystemService(WindowManager.class),
- () -> mStatusBar, () -> mAssistManager, Optional.of(() -> mBubbles));
+ () -> mStatusBar, () -> mAssistManager, Optional.of(mBubbles));
mStatusBar = new StatusBar(
mContext,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 88d0401..a46e563 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -64,14 +64,6 @@
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.Bubble;
-import com.android.systemui.bubbles.BubbleData;
-import com.android.systemui.bubbles.BubbleDataRepository;
-import com.android.systemui.bubbles.BubbleEntry;
-import com.android.systemui.bubbles.BubbleLogger;
-import com.android.systemui.bubbles.BubblePositioner;
-import com.android.systemui.bubbles.BubbleStackView;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -102,6 +94,14 @@
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.bubbles.Bubble;
+import com.android.wm.shell.bubbles.BubbleData;
+import com.android.wm.shell.bubbles.BubbleDataRepository;
+import com.android.wm.shell.bubbles.BubbleEntry;
+import com.android.wm.shell.bubbles.BubbleLogger;
+import com.android.wm.shell.bubbles.BubblePositioner;
+import com.android.wm.shell.bubbles.BubbleStackView;
+import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.google.common.collect.ImmutableList;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubblesTestActivity.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTestActivity.java
similarity index 82%
rename from packages/SystemUI/tests/src/com/android/systemui/bubbles/BubblesTestActivity.java
rename to packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTestActivity.java
index 43d2ad1..f4d96a1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubblesTestActivity.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTestActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.systemui.wmshell;
import android.app.Activity;
import android.content.Intent;
@@ -27,8 +27,7 @@
*/
public class BubblesTestActivity extends Activity {
- public static final String BUBBLE_ACTIVITY_OPENED =
- "com.android.systemui.bubbles.BUBBLE_ACTIVITY_OPENED";
+ public static final String BUBBLE_ACTIVITY_OPENED = "BUBBLE_ACTIVITY_OPENED";
@Override
public void onCreate(Bundle savedInstanceState) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index 99c8ca4..d8033db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -60,13 +60,6 @@
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.BubbleData;
-import com.android.systemui.bubbles.BubbleDataRepository;
-import com.android.systemui.bubbles.BubbleEntry;
-import com.android.systemui.bubbles.BubbleLogger;
-import com.android.systemui.bubbles.BubblePositioner;
-import com.android.systemui.bubbles.BubbleStackView;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -95,6 +88,13 @@
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.bubbles.BubbleData;
+import com.android.wm.shell.bubbles.BubbleDataRepository;
+import com.android.wm.shell.bubbles.BubbleEntry;
+import com.android.wm.shell.bubbles.BubbleLogger;
+import com.android.wm.shell.bubbles.BubblePositioner;
+import com.android.wm.shell.bubbles.BubbleStackView;
+import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.common.FloatingContentCoordinator;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
index 2273bc4..fd39b6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
@@ -22,13 +22,13 @@
import android.view.WindowManager;
import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.bubbles.BubbleController;
-import com.android.systemui.bubbles.BubbleData;
-import com.android.systemui.bubbles.BubbleDataRepository;
-import com.android.systemui.bubbles.BubbleLogger;
-import com.android.systemui.bubbles.BubblePositioner;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.bubbles.BubbleController;
+import com.android.wm.shell.bubbles.BubbleData;
+import com.android.wm.shell.bubbles.BubbleDataRepository;
+import com.android.wm.shell.bubbles.BubbleLogger;
+import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.common.FloatingContentCoordinator;
/**
diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
index 374bd28..ca4b5d4 100644
--- a/packages/VpnDialogs/AndroidManifest.xml
+++ b/packages/VpnDialogs/AndroidManifest.xml
@@ -23,6 +23,9 @@
<uses-permission android:name="android.permission.CONTROL_ALWAYS_ON_VPN" />
<uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"/>
+ <!-- Query all packages on device on R+ -->
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+
<application android:label="VpnDialogs"
android:allowBackup="false">
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index b3fc07a..6f81b5c 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -37,7 +37,7 @@
* Handles all magnification controllers initialization, generic interactions
* and magnification mode transition.
*/
-public class MagnificationController {
+public class MagnificationController implements WindowMagnificationManager.Callback {
private static final boolean DEBUG = false;
private static final String TAG = "MagnificationController";
@@ -78,6 +78,14 @@
mWindowMagnificationMgr = windowMagnificationManager;
}
+ @Override
+ public void onPerformScaleAction(int displayId, float scale) {
+ getWindowMagnificationMgr().setScale(displayId, scale);
+ getWindowMagnificationMgr().persistScale(displayId);
+ mAms.onMagnificationScaleChanged(displayId,
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
+ }
+
/**
* Transitions to the target Magnification mode with current center of the magnification mode
* if it is available.
@@ -223,7 +231,8 @@
synchronized (mLock) {
if (mWindowMagnificationMgr == null) {
mWindowMagnificationMgr = new WindowMagnificationManager(mContext,
- mAms.getCurrentUserIdLocked());
+ mAms.getCurrentUserIdLocked(),
+ this);
}
return mWindowMagnificationMgr;
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index ed3085f..40668d8 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -16,6 +16,7 @@
package com.android.server.accessibility.magnification;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -79,9 +80,27 @@
}
};
- public WindowMagnificationManager(Context context, int userId) {
+ /**
+ * Callback to handle magnification actions from system UI.
+ */
+ public interface Callback {
+
+ /**
+ * Called when the accessibility action of scale requests to be performed.
+ * It is invoked from System UI. And the action is provided by the mirror window.
+ *
+ * @param displayId The logical display id.
+ * @param scale the target scale, or {@link Float#NaN} to leave unchanged
+ */
+ void onPerformScaleAction(int displayId, float scale);
+ }
+
+ private final Callback mCallback;
+
+ public WindowMagnificationManager(Context context, int userId, @NonNull Callback callback) {
mContext = context;
mUserId = userId;
+ mCallback = callback;
}
/**
@@ -498,6 +517,13 @@
}
@Override
+ public void onPerformScaleAction(int displayId, float scale) {
+ synchronized (mLock) {
+ mCallback.onPerformScaleAction(displayId, scale);
+ }
+ }
+
+ @Override
public void binderDied() {
synchronized (mLock) {
Slog.w(TAG, "binderDied DeathRecipient :" + mExpiredDeathRecipient);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index ad85784..a1ad72c 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -84,7 +84,6 @@
import com.android.internal.util.SyncResultReceiver;
import com.android.server.FgThread;
import com.android.server.LocalServices;
-import com.android.server.SystemService.TargetUser;
import com.android.server.autofill.ui.AutoFillUI;
import com.android.server.infra.AbstractMasterSystemService;
import com.android.server.infra.FrameworkResourcesServiceNameResolver;
@@ -170,7 +169,7 @@
// beneath it is brought back to top. Ideally, we should just hide the UI and
// bring it back when the activity resumes.
synchronized (mLock) {
- visitServicesLocked((s) -> s.destroyFinishedSessionsLocked());
+ visitServicesLocked((s) -> s.forceRemoveFinishedSessionsLocked());
}
mUi.hideAll(null);
}
@@ -386,18 +385,18 @@
}
// Called by Shell command.
- void destroySessions(@UserIdInt int userId, IResultReceiver receiver) {
- Slog.i(TAG, "destroySessions() for userId " + userId);
+ void removeAllSessions(@UserIdInt int userId, IResultReceiver receiver) {
+ Slog.i(TAG, "removeAllSessions() for userId " + userId);
enforceCallingPermissionForManagement();
synchronized (mLock) {
if (userId != UserHandle.USER_ALL) {
AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
if (service != null) {
- service.destroySessionsLocked();
+ service.forceRemoveAllSessionsLocked();
}
} else {
- visitServicesLocked((s) -> s.destroySessionsLocked());
+ visitServicesLocked((s) -> s.forceRemoveAllSessionsLocked());
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 864ead1..3212698 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -215,14 +215,14 @@
@GuardedBy("mLock")
@Override // from PerUserSystemService
protected boolean updateLocked(boolean disabled) {
- destroySessionsLocked();
+ forceRemoveAllSessionsLocked();
final boolean enabledChanged = super.updateLocked(disabled);
if (enabledChanged) {
if (!isEnabledLocked()) {
final int sessionCount = mSessions.size();
for (int i = sessionCount - 1; i >= 0; i--) {
final Session session = mSessions.valueAt(i);
- session.removeSelfLocked();
+ session.removeFromServiceLocked();
}
}
sendStateToClients(/* resetClient= */ false);
@@ -442,7 +442,7 @@
if (sVerbose) Slog.v(TAG, "finishSessionLocked(): session finished on save? " + finished);
if (finished) {
- session.removeSelfLocked();
+ session.removeFromServiceLocked();
}
}
@@ -457,7 +457,7 @@
Slog.w(TAG, "cancelSessionLocked(): no session for " + sessionId + "(" + uid + ")");
return;
}
- session.removeSelfLocked();
+ session.removeFromServiceLocked();
}
@GuardedBy("mLock")
@@ -483,7 +483,7 @@
componentName.getPackageName());
Settings.Secure.putStringForUser(getContext().getContentResolver(),
Settings.Secure.AUTOFILL_SERVICE, null, mUserId);
- destroySessionsLocked();
+ forceRemoveAllSessionsLocked();
} else {
Slog.w(TAG, "disableOwnedServices(): ignored because current service ("
+ serviceInfo + ") does not match Settings (" + autoFillService + ")");
@@ -1107,35 +1107,41 @@
}
@GuardedBy("mLock")
- void destroySessionsLocked() {
- if (mSessions.size() == 0) {
+ void forceRemoveAllSessionsLocked() {
+ final int sessionCount = mSessions.size();
+ if (sessionCount == 0) {
mUi.destroyAll(null, null, false);
return;
}
- while (mSessions.size() > 0) {
- mSessions.valueAt(0).forceRemoveSelfLocked();
+
+ for (int i = sessionCount - 1; i >= 0; i--) {
+ mSessions.valueAt(i).forceRemoveFromServiceLocked();
}
}
@GuardedBy("mLock")
- void destroySessionsForAugmentedAutofillOnlyLocked() {
+ void forceRemoveForAugmentedOnlySessionsLocked() {
final int sessionCount = mSessions.size();
for (int i = sessionCount - 1; i >= 0; i--) {
- mSessions.valueAt(i).forceRemoveSelfIfForAugmentedAutofillOnlyLocked();
+ mSessions.valueAt(i).forceRemoveFromServiceIfForAugmentedOnlyLocked();
}
}
+ /**
+ * This method is called exclusively in response to {@code Intent.ACTION_CLOSE_SYSTEM_DIALOGS}.
+ * The method removes all sessions that are finished but showing SaveUI due to how SaveUI is
+ * managed (see b/64940307). Otherwise it will remove any augmented autofill generated windows.
+ */
// TODO(b/64940307): remove this method if SaveUI is refactored to be attached on activities
@GuardedBy("mLock")
- void destroyFinishedSessionsLocked() {
+ void forceRemoveFinishedSessionsLocked() {
final int sessionCount = mSessions.size();
for (int i = sessionCount - 1; i >= 0; i--) {
final Session session = mSessions.valueAt(i);
if (session.isSavingLocked()) {
if (sDebug) Slog.d(TAG, "destroyFinishedSessionsLocked(): " + session.id);
- session.forceRemoveSelfLocked();
- }
- else {
+ session.forceRemoveFromServiceLocked();
+ } else {
session.destroyAugmentedAutofillWindowsLocked();
}
}
@@ -1261,7 +1267,7 @@
Slog.v(TAG, "updateRemoteAugmentedAutofillService(): "
+ "destroying old remote service");
}
- destroySessionsForAugmentedAutofillOnlyLocked();
+ forceRemoveForAugmentedOnlySessionsLocked();
mRemoteAugmentedAutofillService.unbind();
mRemoteAugmentedAutofillService = null;
mRemoteAugmentedAutofillServiceInfo = null;
@@ -1663,7 +1669,7 @@
Slog.i(TAG, "Prune session " + sessionToRemove.id + " ("
+ sessionToRemove.getActivityTokenLocked() + ")");
}
- sessionToRemove.removeSelfLocked();
+ sessionToRemove.removeFromServiceLocked();
}
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
index bbe37a5..68e6290 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
@@ -355,7 +355,7 @@
latch.countDown();
}
};
- return requestSessionCommon(pw, latch, () -> mService.destroySessions(userId, receiver));
+ return requestSessionCommon(pw, latch, () -> mService.removeAllSessions(userId, receiver));
}
private int requestList(PrintWriter pw) {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 0302b22..b48d71a 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -227,8 +227,8 @@
private boolean mHasCallback;
/**
- * Extras sent by service on {@code onFillRequest()} calls; the first non-null extra is saved
- * and used on subsequent {@code onFillRequest()} and {@code onSaveRequest()} calls.
+ * Extras sent by service on {@code onFillRequest()} calls; the most recent non-null extra is
+ * saved and used on subsequent {@code onFillRequest()} and {@code onSaveRequest()} calls.
*/
@GuardedBy("mLock")
private Bundle mClientState;
@@ -1086,7 +1086,7 @@
if (showMessage) {
getUiForShowing().showError(message, this);
}
- removeSelf();
+ removeFromService();
}
// FillServiceCallbacks
@@ -1111,7 +1111,7 @@
}
// Nothing left to do...
- removeSelf();
+ removeFromService();
}
// FillServiceCallbacks
@@ -1147,7 +1147,7 @@
if (showMessage) {
getUiForShowing().showError(message, this);
}
- removeSelf();
+ removeFromService();
}
/**
@@ -1179,7 +1179,7 @@
@Override
public void onServiceDied(@NonNull RemoteFillService service) {
Slog.w(TAG, "removing session because service died");
- forceRemoveSelfLocked();
+ forceRemoveFromServiceLocked();
}
// AutoFillUiCallback
@@ -1199,7 +1199,7 @@
}
fillInIntent = createAuthFillInIntentLocked(requestId, extras);
if (fillInIntent == null) {
- forceRemoveSelfLocked();
+ forceRemoveFromServiceLocked();
return;
}
}
@@ -1255,7 +1255,7 @@
}
}
mHandler.sendMessage(obtainMessage(
- Session::removeSelf, this));
+ Session::removeFromService, this));
}
// AutoFillUiCallback
@@ -1327,7 +1327,7 @@
@Override
public void cancelSession() {
synchronized (mLock) {
- removeSelfLocked();
+ removeFromServiceLocked();
}
}
@@ -1347,7 +1347,7 @@
return;
}
if (intent == null) {
- removeSelfLocked();
+ removeFromServiceLocked();
}
}
mHandler.sendMessage(obtainMessage(
@@ -1401,13 +1401,13 @@
// Typically happens when app explicitly called cancel() while the service was showing
// the auth UI.
Slog.w(TAG, "setAuthenticationResultLocked(" + authenticationId + "): no responses");
- removeSelf();
+ removeFromService();
return;
}
final FillResponse authenticatedResponse = mResponses.get(requestId);
if (authenticatedResponse == null || data == null) {
Slog.w(TAG, "no authenticated response");
- removeSelf();
+ removeFromService();
return;
}
@@ -1418,7 +1418,7 @@
final Dataset dataset = authenticatedResponse.getDatasets().get(datasetIdx);
if (dataset == null) {
Slog.w(TAG, "no dataset with index " + datasetIdx + " on fill response");
- removeSelf();
+ removeFromService();
return;
}
}
@@ -1504,7 +1504,7 @@
Slog.d(TAG, "Rejecting empty/invalid auth result");
}
mService.resetLastAugmentedAutofillResponse();
- removeSelfLocked();
+ removeFromServiceLocked();
return;
}
@@ -2715,7 +2715,7 @@
return;
}
if (sDebug) Slog.d(TAG, "Finishing session because URL bar changed");
- forceRemoveSelfLocked(AutofillManager.STATE_UNKNOWN_COMPAT_MODE);
+ forceRemoveFromServiceLocked(AutofillManager.STATE_UNKNOWN_COMPAT_MODE);
return;
}
if (!Objects.equals(value, viewState.getCurrentValue())) {
@@ -3226,7 +3226,7 @@
}
// Nothing to be done, but need to notify client.
notifyUnavailableToClient(AutofillManager.STATE_FINISHED, autofillableIds);
- removeSelf();
+ removeFromService();
} else {
if ((flags & FLAG_PASSWORD_INPUT_TYPE) != 0) {
if (sVerbose) {
@@ -3393,20 +3393,6 @@
}
@GuardedBy("mLock")
- private void logAugmentedAutofillRequestLocked(int mode,
- ComponentName augmentedRemoteServiceName, AutofillId focusedId, boolean isWhitelisted,
- Boolean isInline) {
- final String historyItem =
- "aug:id=" + id + " u=" + uid + " m=" + mode
- + " a=" + ComponentName.flattenToShortString(mComponentName)
- + " f=" + focusedId
- + " s=" + augmentedRemoteServiceName
- + " w=" + isWhitelisted
- + " i=" + isInline;
- mService.getMaster().logRequestLocked(historyItem);
- }
-
- @GuardedBy("mLock")
private void cancelAugmentedAutofillLocked() {
final RemoteAugmentedAutofillService remoteService = mService
.getRemoteAugmentedAutofillServiceLocked();
@@ -3574,7 +3560,7 @@
setViewStatesLocked(null, dataset, ViewState.STATE_WAITING_DATASET_AUTH, false);
final Intent fillInIntent = createAuthFillInIntentLocked(requestId, mClientState);
if (fillInIntent == null) {
- forceRemoveSelfLocked();
+ forceRemoveFromServiceLocked();
return;
}
final int authenticationId = AutofillManager.makeAuthenticationId(requestId,
@@ -3923,12 +3909,12 @@
}
/**
- * Cleans up this session.
+ * Destroy this session and perform any clean up work.
*
* <p>Typically called in 2 scenarios:
*
* <ul>
- * <li>When the session naturally finishes (i.e., from {@link #removeSelfLocked()}.
+ * <li>When the session naturally finishes (i.e., from {@link #removeFromServiceLocked()}.
* <li>When the service hosting the session is finished (for example, because the user
* disabled it).
* </ul>
@@ -3990,32 +3976,32 @@
}
/**
- * Cleans up this session and remove it from the service always, even if it does have a pending
+ * Destroy this session and remove it from the service always, even if it does have a pending
* Save UI.
*/
@GuardedBy("mLock")
- void forceRemoveSelfLocked() {
- forceRemoveSelfLocked(AutofillManager.STATE_UNKNOWN);
+ void forceRemoveFromServiceLocked() {
+ forceRemoveFromServiceLocked(AutofillManager.STATE_UNKNOWN);
}
@GuardedBy("mLock")
- void forceRemoveSelfIfForAugmentedAutofillOnlyLocked() {
+ void forceRemoveFromServiceIfForAugmentedOnlyLocked() {
if (sVerbose) {
- Slog.v(TAG, "forceRemoveSelfIfForAugmentedAutofillOnly(" + this.id + "): "
+ Slog.v(TAG, "forceRemoveFromServiceIfForAugmentedOnlyLocked(" + this.id + "): "
+ mForAugmentedAutofillOnly);
}
if (!mForAugmentedAutofillOnly) return;
- forceRemoveSelfLocked();
+ forceRemoveFromServiceLocked();
}
@GuardedBy("mLock")
- void forceRemoveSelfLocked(int clientState) {
- if (sVerbose) Slog.v(TAG, "forceRemoveSelfLocked(): " + mPendingSaveUi);
+ void forceRemoveFromServiceLocked(int clientState) {
+ if (sVerbose) Slog.v(TAG, "forceRemoveFromServiceLocked(): " + mPendingSaveUi);
final boolean isPendingSaveUi = isSaveUiPendingLocked();
mPendingSaveUi = null;
- removeSelfLocked();
+ removeFromServiceLocked();
mUi.destroyAll(mPendingSaveUi, this, false);
if (!isPendingSaveUi) {
try {
@@ -4036,28 +4022,28 @@
}
/**
- * Thread-safe version of {@link #removeSelfLocked()}.
+ * Thread-safe version of {@link #removeFromServiceLocked()}.
*/
- private void removeSelf() {
+ private void removeFromService() {
synchronized (mLock) {
- removeSelfLocked();
+ removeFromServiceLocked();
}
}
/**
- * Cleans up this session and remove it from the service, but but only if it does not have a
+ * Destroy this session and remove it from the service, but but only if it does not have a
* pending Save UI.
*/
@GuardedBy("mLock")
- void removeSelfLocked() {
- if (sVerbose) Slog.v(TAG, "removeSelfLocked(" + this.id + "): " + mPendingSaveUi);
+ void removeFromServiceLocked() {
+ if (sVerbose) Slog.v(TAG, "removeFromServiceLocked(" + this.id + "): " + mPendingSaveUi);
if (mDestroyed) {
- Slog.w(TAG, "Call to Session#removeSelfLocked() rejected - session: "
+ Slog.w(TAG, "Call to Session#removeFromServiceLocked() rejected - session: "
+ id + " destroyed");
return;
}
if (isSaveUiPendingLocked()) {
- Slog.i(TAG, "removeSelfLocked() ignored, waiting for pending save ui");
+ Slog.i(TAG, "removeFromServiceLocked() ignored, waiting for pending save ui");
return;
}
@@ -4139,6 +4125,20 @@
requestLog.addTaggedData(tag, value);
}
+ @GuardedBy("mLock")
+ private void logAugmentedAutofillRequestLocked(int mode,
+ ComponentName augmentedRemoteServiceName, AutofillId focusedId, boolean isWhitelisted,
+ Boolean isInline) {
+ final String historyItem =
+ "aug:id=" + id + " u=" + uid + " m=" + mode
+ + " a=" + ComponentName.flattenToShortString(mComponentName)
+ + " f=" + focusedId
+ + " s=" + augmentedRemoteServiceName
+ + " w=" + isWhitelisted
+ + " i=" + isInline;
+ mService.getMaster().logRequestLocked(historyItem);
+ }
+
private void wtf(@Nullable Exception e, String fmt, Object...args) {
final String message = String.format(fmt, args);
synchronized (mLock) {
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 75bbec6..ac6ed44 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -32,6 +32,7 @@
import android.app.backup.IFullBackupRestoreObserver;
import android.app.backup.IRestoreSession;
import android.app.backup.ISelectBackupTransportCallback;
+import android.app.compat.CompatChanges;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.job.JobService;
@@ -61,7 +62,6 @@
import com.android.internal.util.DumpUtils;
import com.android.server.SystemConfig;
import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
import com.android.server.backup.utils.RandomAccessFileUtils;
import java.io.File;
@@ -509,6 +509,12 @@
*/
@Override
public boolean isBackupServiceActive(int userId) {
+ int callingUid = Binder.getCallingUid();
+ if (CompatChanges.isChangeEnabled(
+ BackupManager.IS_BACKUP_SERVICE_ACTIVE_ENFORCE_PERMISSION_IN_SERVICE, callingUid)) {
+ mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
+ "isBackupServiceActive");
+ }
synchronized (mStateLock) {
return !mGlobalDisable && isBackupActivatedForUser(userId);
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 22423fe..ca0f8b7 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -135,8 +135,6 @@
import android.net.metrics.NetworkEvent;
import android.net.netlink.InetDiagMessage;
import android.net.shared.PrivateDnsConfig;
-import android.net.util.LinkPropertiesUtils.CompareOrUpdateResult;
-import android.net.util.LinkPropertiesUtils.CompareResult;
import android.net.util.MultinetworkPolicyTracker;
import android.net.util.NetdService;
import android.os.BasicShellCommandHandler;
@@ -192,6 +190,8 @@
import com.android.internal.util.LocationPermissionChecker;
import com.android.internal.util.MessageUtils;
import com.android.internal.util.XmlUtils;
+import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult;
+import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
import com.android.server.am.BatteryStatsService;
import com.android.server.connectivity.AutodestructReference;
import com.android.server.connectivity.DataConnectionStats;
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index 78bd4cd..84f40cb 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -25,7 +25,6 @@
import android.net.nsd.INsdManager;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
-import android.net.util.nsd.DnsSdTxtRecord;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
@@ -42,6 +41,7 @@
import com.android.internal.util.DumpUtils;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
+import com.android.net.module.util.DnsSdTxtRecord;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index 9fc8f0b..ef6dab5 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -56,6 +56,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -100,6 +101,10 @@
private static final String PROP_VIRTUAL_DEVICE = "ro.hardware.virtual_device";
private static final String PROP_DEVICE_CONFIG_DISABLE_FLAG =
"persist.device_config.configuration.disable_rescue_party";
+ private static final String PROP_DISABLE_FACTORY_RESET_FLAG =
+ "persist.device_config.configuration.disable_rescue_party_factory_reset";
+ // The DeviceConfig namespace containing all RescueParty switches.
+ private static final String NAMESPACE_CONFIGURATION = "configuration";
private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT
| ApplicationInfo.FLAG_SYSTEM;
@@ -215,6 +220,10 @@
if (SettingsToPropertiesMapper.isNativeFlagsResetPerformed()) {
String[] resetNativeCategories = SettingsToPropertiesMapper.getResetNativeCategories();
for (int i = 0; i < resetNativeCategories.length; i++) {
+ // Don't let RescueParty reset the namespace for RescueParty switches.
+ if (NAMESPACE_CONFIGURATION.equals(resetNativeCategories[i])) {
+ continue;
+ }
DeviceConfig.resetToDefaults(Settings.RESET_MODE_TRUSTED_DEFAULTS,
resetNativeCategories[i]);
}
@@ -225,8 +234,10 @@
* Get the next rescue level. This indicates the next level of mitigation that may be taken.
*/
private static int getNextRescueLevel() {
+ int maxRescueLevel = SystemProperties.getBoolean(PROP_DISABLE_FACTORY_RESET_FLAG, false)
+ ? LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS : LEVEL_FACTORY_RESET;
return MathUtils.constrain(SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE) + 1,
- LEVEL_NONE, LEVEL_FACTORY_RESET);
+ LEVEL_NONE, maxRescueLevel);
}
/**
@@ -349,12 +360,30 @@
private static void resetDeviceConfig(Context context, int resetMode,
@Nullable String failedPackage) {
if (!shouldPerformScopedResets() || failedPackage == null) {
- DeviceConfig.resetToDefaults(resetMode, /*namespace=*/ null);
+ resetAllAffectedNamespaces(context, resetMode);
} else {
performScopedReset(context, resetMode, failedPackage);
}
}
+ private static void resetAllAffectedNamespaces(Context context, int resetMode) {
+ RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context);
+ Set<String> allAffectedNamespaces = rescuePartyObserver.getAllAffectedNamespaceSet();
+
+ Slog.w(TAG,
+ "Performing reset for all affected namespaces: "
+ + Arrays.toString(allAffectedNamespaces.toArray()));
+ Iterator<String> it = allAffectedNamespaces.iterator();
+ while (it.hasNext()) {
+ String namespace = it.next();
+ // Don't let RescueParty reset the namespace for RescueParty switches.
+ if (NAMESPACE_CONFIGURATION.equals(namespace)) {
+ continue;
+ }
+ DeviceConfig.resetToDefaults(resetMode, namespace);
+ }
+ }
+
private static boolean shouldPerformScopedResets() {
int rescueLevel = MathUtils.constrain(
SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE),
@@ -367,16 +396,21 @@
RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context);
Set<String> affectedNamespaces = rescuePartyObserver.getAffectedNamespaceSet(
failedPackage);
- if (affectedNamespaces == null) {
- DeviceConfig.resetToDefaults(resetMode, /*namespace=*/ null);
- } else {
+ // If we can't find namespaces affected for current package,
+ // skip this round of reset.
+ if (affectedNamespaces != null) {
Slog.w(TAG,
"Performing scoped reset for package: " + failedPackage
+ ", affected namespaces: "
+ Arrays.toString(affectedNamespaces.toArray()));
Iterator<String> it = affectedNamespaces.iterator();
while (it.hasNext()) {
- DeviceConfig.resetToDefaults(resetMode, it.next());
+ String namespace = it.next();
+ // Don't let RescueParty reset the namespace for RescueParty switches.
+ if (NAMESPACE_CONFIGURATION.equals(namespace)) {
+ continue;
+ }
+ DeviceConfig.resetToDefaults(resetMode, namespace);
}
}
}
@@ -514,6 +548,10 @@
return mCallingPackageNamespaceSetMap.get(failedPackage);
}
+ private synchronized Set<String> getAllAffectedNamespaceSet() {
+ return new HashSet<String>(mNamespaceCallingPackageSetMap.keySet());
+ }
+
private synchronized Set<String> getCallingPackagesSet(String namespace) {
return mNamespaceCallingPackageSetMap.get(namespace);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 112814c69..9f2216d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4890,6 +4890,15 @@
}
@Override
+ public boolean isIntentSenderImmutable(IIntentSender pendingResult) {
+ if (pendingResult instanceof PendingIntentRecord) {
+ final PendingIntentRecord res = (PendingIntentRecord) pendingResult;
+ return (res.key.flags & PendingIntent.FLAG_IMMUTABLE) != 0;
+ }
+ return false;
+ }
+
+ @Override
public boolean isIntentSenderAnActivity(IIntentSender pendingResult) {
if (!(pendingResult instanceof PendingIntentRecord)) {
return false;
@@ -7736,11 +7745,15 @@
* @return true if the process should exit immediately (WTF is fatal)
*/
@Override
- public boolean handleApplicationWtf(final IBinder app, final String tag, boolean system,
- final ApplicationErrorReport.ParcelableCrashInfo crashInfo, int immediateCallerPid) {
+ public boolean handleApplicationWtf(@Nullable final IBinder app, @Nullable final String tag,
+ boolean system, @NonNull final ApplicationErrorReport.ParcelableCrashInfo crashInfo,
+ int immediateCallerPid) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
+ // Internal callers in RuntimeInit should always generate a crashInfo.
+ Preconditions.checkNotNull(crashInfo);
+
// If this is coming from the system, we could very well have low-level
// system locks held, so we want to do this all asynchronously. And we
// never want this to become fatal, so there is that too.
@@ -7773,14 +7786,15 @@
}
}
- ProcessRecord handleApplicationWtfInner(int callingUid, int callingPid, IBinder app, String tag,
- final ApplicationErrorReport.CrashInfo crashInfo) {
+ ProcessRecord handleApplicationWtfInner(int callingUid, int callingPid, @Nullable IBinder app,
+ @Nullable String tag, @Nullable final ApplicationErrorReport.CrashInfo crashInfo) {
final ProcessRecord r = findAppProcess(app, "WTF");
final String processName = app == null ? "system_server"
: (r == null ? "unknown" : r.processName);
EventLogTags.writeAmWtf(UserHandle.getUserId(callingUid), callingPid,
- processName, r == null ? -1 : r.info.flags, tag, crashInfo.exceptionMessage);
+ processName, r == null ? -1 : r.info.flags, tag,
+ crashInfo == null ? "unknown" : crashInfo.exceptionMessage);
FrameworkStatsLog.write(FrameworkStatsLog.WTF_OCCURRED, callingUid, tag, processName,
callingPid, (r != null) ? r.getProcessClassEnum() : 0);
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index 5e59a35..cace260 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -247,6 +247,9 @@
private int mMemWatchDumpUid;
private boolean mMemWatchIsUserInitiated;
+ boolean mHasHomeProcess;
+ boolean mHasPreviousProcess;
+
/**
* Used to collect per-process CPU use for ANRs, battery stats, etc.
* Must acquire this object's lock when accessing it.
@@ -961,8 +964,8 @@
}
int factor = numTrimming / 3;
int minFactor = 2;
- if (mService.mAtmInternal.getHomeProcess() != null) minFactor++;
- if (mService.mAtmInternal.getPreviousProcess() != null) minFactor++;
+ if (mHasHomeProcess) minFactor++;
+ if (mHasPreviousProcess) minFactor++;
if (factor < minFactor) factor = minFactor;
int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
for (int i = 0; i < numOfLru; i++) {
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 9d49236..01d0a6d 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -500,6 +500,7 @@
final ProcessRecord topApp = mService.getTopAppLocked();
// Clear any pending ones because we are doing a full update now.
mPendingProcessSet.clear();
+ mService.mAppProfiler.mHasPreviousProcess = mService.mAppProfiler.mHasHomeProcess = false;
updateOomAdjLockedInner(oomAdjReason, topApp , null, null, true, true);
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index ccdd6a7..463ba6d 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1875,16 +1875,24 @@
boolean getCachedIsHomeProcess() {
if (mCachedIsHomeProcess == VALUE_INVALID) {
- mCachedIsHomeProcess = getWindowProcessController().isHomeProcess()
- ? VALUE_TRUE : VALUE_FALSE;
+ if (getWindowProcessController().isHomeProcess()) {
+ mCachedIsHomeProcess = VALUE_TRUE;
+ mService.mAppProfiler.mHasHomeProcess = true;
+ } else {
+ mCachedIsHomeProcess = VALUE_FALSE;
+ }
}
return mCachedIsHomeProcess == VALUE_TRUE;
}
boolean getCachedIsPreviousProcess() {
if (mCachedIsPreviousProcess == VALUE_INVALID) {
- mCachedIsPreviousProcess = getWindowProcessController().isPreviousProcess()
- ? VALUE_TRUE : VALUE_FALSE;
+ if (getWindowProcessController().isPreviousProcess()) {
+ mCachedIsPreviousProcess = VALUE_TRUE;
+ mService.mAppProfiler.mHasPreviousProcess = true;
+ } else {
+ mCachedIsPreviousProcess = VALUE_FALSE;
+ }
}
return mCachedIsPreviousProcess == VALUE_TRUE;
}
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 60e59e3..28afcbb 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -85,6 +85,7 @@
DeviceConfig.NAMESPACE_INTELLIGENCE_CONTENT_SUGGESTIONS,
DeviceConfig.NAMESPACE_MEDIA_NATIVE,
DeviceConfig.NAMESPACE_NETD_NATIVE,
+ DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT,
DeviceConfig.NAMESPACE_RUNTIME_NATIVE,
DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 5379f32..2b2d9b5 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -94,6 +94,7 @@
import android.app.RuntimeAppOpAccessMessage;
import android.app.SyncNotedAppOp;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -3015,6 +3016,25 @@
}
}
+ private boolean isTrustedVoiceServiceProxy(String packageName, int code) {
+ if (code != OP_RECORD_AUDIO) {
+ return false;
+ }
+ final String voiceRecognitionComponent = Settings.Secure.getString(
+ mContext.getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE);
+ final String voiceInteractionComponent = Settings.Secure.getString(
+ mContext.getContentResolver(), Settings.Secure.VOICE_INTERACTION_SERVICE);
+
+ final String voiceRecognitionServicePackageName =
+ voiceRecognitionComponent != null ? ComponentName.unflattenFromString(
+ voiceRecognitionComponent).getPackageName() : "";
+ final String voiceInteractionServicePackageName =
+ voiceInteractionComponent != null ? ComponentName.unflattenFromString(
+ voiceInteractionComponent).getPackageName() : "";
+ return Objects.equals(packageName, voiceRecognitionServicePackageName) && Objects.equals(
+ voiceRecognitionServicePackageName, voiceInteractionServicePackageName);
+ }
+
@Override
public int noteProxyOperation(int code, int proxiedUid, String proxiedPackageName,
String proxiedAttributionTag, int proxyUid, String proxyPackageName,
@@ -3030,9 +3050,12 @@
return AppOpsManager.MODE_IGNORED;
}
+ // This is a workaround for R QPR, new API change is not allowed. We only allow the current
+ // voice recognizer is also the voice interactor to noteproxy op.
+ final boolean isTrustVoiceServiceProxy = isTrustedVoiceServiceProxy(proxyPackageName, code);
final boolean isProxyTrusted = mContext.checkPermission(
Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid)
- == PackageManager.PERMISSION_GRANTED;
+ == PackageManager.PERMISSION_GRANTED || isTrustVoiceServiceProxy;
final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
: AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;
@@ -3494,9 +3517,12 @@
return AppOpsManager.MODE_IGNORED;
}
+ // This is a workaround for R QPR, new API change is not allowed. We only allow the current
+ // voice recognizer is also the voice interactor to noteproxy op.
+ final boolean isTrustVoiceServiceProxy = isTrustedVoiceServiceProxy(proxyPackageName, code);
final boolean isProxyTrusted = mContext.checkPermission(
Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid)
- == PackageManager.PERMISSION_GRANTED;
+ == PackageManager.PERMISSION_GRANTED || isTrustVoiceServiceProxy;
final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
: AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index cfc58a5..52fc93f 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -4306,7 +4306,7 @@
/** @see AudioManager#playSoundEffect(int, float) */
public void playSoundEffectVolume(int effectType, float volume) {
// do not try to play the sound effect if the system stream is muted
- if (isStreamMutedByRingerOrZenMode(STREAM_SYSTEM)) {
+ if (isStreamMute(STREAM_SYSTEM)) {
return;
}
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 54c1790..d52cf02 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -329,6 +329,10 @@
return;
}
+ // Initialize this outside of FingerprintAuthenticator. Only HIDL HALs require
+ // initialization from here. AIDL HALs are initialized by FingerprintService since
+ // the HAL interface provides ID, strength, and other configuration information.
+ fingerprintService.initializeConfiguration(config.id, config.strength);
authenticator = new FingerprintAuthenticator(fingerprintService, config);
break;
@@ -340,6 +344,10 @@
return;
}
+ // Initialize this outside of FingerprintAuthenticator. Only HIDL HALs require
+ // initialization from here. AIDL HALs are initialized by FaceService since
+ // the HAL interface provides ID, strength, and other configuration information.
+ faceService.initializeConfiguration(config.id, config.strength);
authenticator = new FaceAuthenticator(faceService, config);
break;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
index 3318bcb..e742d10 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
@@ -30,11 +30,12 @@
*/
public final class FaceAuthenticator extends IBiometricAuthenticator.Stub {
private final IFaceService mFaceService;
+ private final int mSensorId;
public FaceAuthenticator(IFaceService faceService, SensorConfig config)
throws RemoteException {
mFaceService = faceService;
- mFaceService.initializeConfiguration(config.id, config.strength);
+ mSensorId = config.id;
}
@Override
@@ -42,40 +43,41 @@
long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
String opPackageName, int cookie, int callingUid, int callingPid, int callingUserId)
throws RemoteException {
- mFaceService.prepareForAuthentication(requireConfirmation, token, operationId, userId,
- sensorReceiver, opPackageName, cookie, callingUid, callingPid, callingUserId);
+ mFaceService.prepareForAuthentication(mSensorId, requireConfirmation, token, operationId,
+ userId, sensorReceiver, opPackageName, cookie, callingUid, callingPid,
+ callingUserId);
}
@Override
public void startPreparedClient(int cookie) throws RemoteException {
- mFaceService.startPreparedClient(cookie);
+ mFaceService.startPreparedClient(mSensorId, cookie);
}
@Override
public void cancelAuthenticationFromService(IBinder token, String opPackageName, int callingUid,
int callingPid, int callingUserId) throws RemoteException {
- mFaceService.cancelAuthenticationFromService(token, opPackageName, callingUid, callingPid,
- callingUserId);
+ mFaceService.cancelAuthenticationFromService(mSensorId, token, opPackageName, callingUid,
+ callingPid, callingUserId);
}
@Override
public boolean isHardwareDetected(String opPackageName) throws RemoteException {
- return mFaceService.isHardwareDetected(opPackageName);
+ return mFaceService.isHardwareDetected(mSensorId, opPackageName);
}
@Override
public boolean hasEnrolledTemplates(int userId, String opPackageName) throws RemoteException {
- return mFaceService.hasEnrolledFaces(userId, opPackageName);
+ return mFaceService.hasEnrolledFaces(mSensorId, userId, opPackageName);
}
@Override
public @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId)
throws RemoteException {
- return mFaceService.getLockoutModeForUser(userId);
+ return mFaceService.getLockoutModeForUser(mSensorId, userId);
}
@Override
public long getAuthenticatorId(int callingUserId) throws RemoteException {
- return mFaceService.getAuthenticatorId(callingUserId);
+ return mFaceService.getAuthenticatorId(mSensorId, callingUserId);
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index a298e19..c635182 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -255,35 +255,35 @@
}
@Override // Binder call
- public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
- long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
- String opPackageName, int cookie, int callingUid, int callingPid,
- int callingUserId) {
+ public void prepareForAuthentication(int sensorId, boolean requireConfirmation,
+ IBinder token, long operationId, int userId,
+ IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie,
+ int callingUid, int callingPid, int callingUserId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for prepareForAuthentication");
return;
}
final boolean restricted = true; // BiometricPrompt is always restricted
- provider.second.scheduleAuthenticate(provider.first, token, operationId, userId, cookie,
+ provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie,
new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted,
BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, false /* isKeyguard */);
}
@Override // Binder call
- public void startPreparedClient(int cookie) {
+ public void startPreparedClient(int sensorId, int cookie) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for startPreparedClient");
return;
}
- provider.second.startPreparedClient(provider.first, cookie);
+ provider.startPreparedClient(sensorId, cookie);
}
@Override // Binder call
@@ -312,17 +312,17 @@
}
@Override // Binder call
- public void cancelAuthenticationFromService(final IBinder token, final String opPackageName,
- int callingUid, int callingPid, int callingUserId) {
+ public void cancelAuthenticationFromService(int sensorId, final IBinder token,
+ final String opPackageName, int callingUid, int callingPid, int callingUserId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for cancelAuthenticationFromService");
return;
}
- provider.second.cancelAuthentication(provider.first, token);
+ provider.cancelAuthentication(sensorId, token);
}
@Override // Binder call
@@ -384,24 +384,24 @@
}
@Override // Binder call
- public boolean isHardwareDetected(String opPackageName) {
+ public boolean isHardwareDetected(int sensorId, String opPackageName) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
final long token = Binder.clearCallingIdentity();
try {
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for isHardwareDetected, caller: " + opPackageName);
return false;
}
- return provider.second.isHardwareDetected(provider.first);
+ return provider.isHardwareDetected(sensorId);
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override // Binder call
- public List<Face> getEnrolledFaces(int userId, String opPackageName) {
+ public List<Face> getEnrolledFaces(int sensorId, int userId, String opPackageName) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
if (userId != UserHandle.getCallingUserId()) {
@@ -412,7 +412,7 @@
}
@Override // Binder call
- public boolean hasEnrolledFaces(int userId, String opPackageName) {
+ public boolean hasEnrolledFaces(int sensorId, int userId, String opPackageName) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
if (userId != UserHandle.getCallingUserId()) {
@@ -423,30 +423,29 @@
}
@Override // Binder call
- @LockoutTracker.LockoutMode
- public int getLockoutModeForUser(int userId) {
+ public @LockoutTracker.LockoutMode int getLockoutModeForUser(int sensorId, int userId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for getLockoutModeForUser");
return LockoutTracker.LOCKOUT_NONE;
}
- return provider.second.getLockoutModeForUser(provider.first, userId);
+ return provider.getLockoutModeForUser(sensorId, userId);
}
@Override // Binder call
- public long getAuthenticatorId(int userId) {
+ public long getAuthenticatorId(int sensorId, int userId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for getAuthenticatorId");
return 0;
}
- return provider.second.getAuthenticatorId(provider.first, userId);
+ return provider.getAuthenticatorId(sensorId, userId);
}
@Override // Binder call
@@ -454,13 +453,13 @@
String opPackageName) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for resetLockout, caller: " + opPackageName);
return;
}
- provider.second.scheduleResetLockout(provider.first, userId, hardwareAuthToken);
+ provider.scheduleResetLockout(sensorId, userId, hardwareAuthToken);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
index 4b59112..f77bc79 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
@@ -30,11 +30,12 @@
*/
public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub {
private final IFingerprintService mFingerprintService;
+ private final int mSensorId;
public FingerprintAuthenticator(IFingerprintService fingerprintService, SensorConfig config)
throws RemoteException {
mFingerprintService = fingerprintService;
- mFingerprintService.initializeConfiguration(config.id, config.strength);
+ mSensorId = config.id;
}
@Override
@@ -42,40 +43,40 @@
long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
String opPackageName, int cookie, int callingUid, int callingPid, int callingUserId)
throws RemoteException {
- mFingerprintService.prepareForAuthentication(token, operationId, userId, sensorReceiver,
- opPackageName, cookie, callingUid, callingPid, callingUserId);
+ mFingerprintService.prepareForAuthentication(mSensorId, token, operationId, userId,
+ sensorReceiver, opPackageName, cookie, callingUid, callingPid, callingUserId);
}
@Override
public void startPreparedClient(int cookie) throws RemoteException {
- mFingerprintService.startPreparedClient(cookie);
+ mFingerprintService.startPreparedClient(mSensorId, cookie);
}
@Override
public void cancelAuthenticationFromService(IBinder token, String opPackageName, int callingUid,
int callingPid, int callingUserId) throws RemoteException {
- mFingerprintService.cancelAuthenticationFromService(token, opPackageName, callingUid,
- callingPid, callingUserId);
+ mFingerprintService.cancelAuthenticationFromService(mSensorId, token, opPackageName,
+ callingUid, callingPid, callingUserId);
}
@Override
public boolean isHardwareDetected(String opPackageName) throws RemoteException {
- return mFingerprintService.isHardwareDetected(opPackageName);
+ return mFingerprintService.isHardwareDetected(mSensorId, opPackageName);
}
@Override
public boolean hasEnrolledTemplates(int userId, String opPackageName) throws RemoteException {
- return mFingerprintService.hasEnrolledFingerprints(userId, opPackageName);
+ return mFingerprintService.hasEnrolledFingerprints(mSensorId, userId, opPackageName);
}
@Override
public @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId)
throws RemoteException {
- return mFingerprintService.getLockoutModeForUser(userId);
+ return mFingerprintService.getLockoutModeForUser(mSensorId, userId);
}
@Override
public long getAuthenticatorId(int callingUserId) throws RemoteException {
- return mFingerprintService.getAuthenticatorId(callingUserId);
+ return mFingerprintService.getAuthenticatorId(mSensorId, callingUserId);
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 265ba05..99569b1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -255,34 +255,34 @@
}
@Override // Binder call
- public void prepareForAuthentication(IBinder token, long operationId, int userId,
- IBiometricSensorReceiver sensorReceiver, String opPackageName,
+ public void prepareForAuthentication(int sensorId, IBinder token, long operationId,
+ int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
int cookie, int callingUid, int callingPid, int callingUserId) {
Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for prepareForAuthentication");
return;
}
final boolean restricted = true; // BiometricPrompt is always restricted
- provider.second.scheduleAuthenticate(provider.first, token, operationId, userId, cookie,
+ provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie,
new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted,
BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, false /* isKeyguard */);
}
@Override // Binder call
- public void startPreparedClient(int cookie) {
+ public void startPreparedClient(int sensorId, int cookie) {
Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for startPreparedClient");
return;
}
- provider.second.startPreparedClient(provider.first, cookie);
+ provider.startPreparedClient(sensorId, cookie);
}
@@ -328,17 +328,17 @@
}
@Override // Binder call
- public void cancelAuthenticationFromService(final IBinder token, final String opPackageName,
- int callingUid, int callingPid, int callingUserId) {
+ public void cancelAuthenticationFromService(final int sensorId, final IBinder token,
+ final String opPackageName, int callingUid, int callingPid, int callingUserId) {
Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for cancelAuthenticationFromService");
return;
}
- provider.second.cancelAuthentication(provider.first, token);
+ provider.cancelAuthentication(sensorId, token);
}
@Override // Binder call
@@ -402,7 +402,7 @@
}
@Override // Binder call
- public boolean isHardwareDetected(String opPackageName) {
+ public boolean isHardwareDetectedDeprecated(String opPackageName) {
if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
Binder.getCallingUid(), Binder.getCallingPid(),
UserHandle.getCallingUserId())) {
@@ -413,7 +413,8 @@
try {
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
- Slog.w(TAG, "Null provider for isHardwareDetected, caller: " + opPackageName);
+ Slog.w(TAG, "Null provider for isHardwareDetectedDeprecated, caller: "
+ + opPackageName);
return false;
}
return provider.second.isHardwareDetected(provider.first);
@@ -423,6 +424,19 @@
}
@Override // Binder call
+ public boolean isHardwareDetected(int sensorId, String opPackageName) {
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for isHardwareDetected, caller: " + opPackageName);
+ return false;
+ }
+
+ return provider.isHardwareDetected(sensorId);
+ }
+
+ @Override // Binder call
public void rename(final int fingerId, final int userId, final String name) {
Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
if (!Utils.isCurrentUserOrProfile(getContext(), userId)) {
@@ -450,11 +464,11 @@
Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS);
}
- return FingerprintService.this.getEnrolledFingerprints(userId, opPackageName);
+ return FingerprintService.this.getEnrolledFingerprintsDeprecated(userId, opPackageName);
}
@Override // Binder call
- public boolean hasEnrolledFingerprints(int userId, String opPackageName) {
+ public boolean hasEnrolledFingerprintsDeprecated(int userId, String opPackageName) {
if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
Binder.getCallingUid(), Binder.getCallingPid(),
UserHandle.getCallingUserId())) {
@@ -464,7 +478,7 @@
if (userId != UserHandle.getCallingUserId()) {
Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS);
}
- return !FingerprintService.this.getEnrolledFingerprints(userId, opPackageName)
+ return !FingerprintService.this.getEnrolledFingerprintsDeprecated(userId, opPackageName)
.isEmpty();
}
@@ -489,28 +503,40 @@
return false;
}
- @Override // Binder call
- public @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId) {
+ public boolean hasEnrolledFingerprints(int sensorId, int userId, String opPackageName) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for hasEnrolledFingerprints, caller: " + opPackageName);
+ return false;
+ }
+
+ return provider.getEnrolledFingerprints(sensorId, userId).size() > 0;
+ }
+
+ @Override // Binder call
+ public @LockoutTracker.LockoutMode int getLockoutModeForUser(int sensorId, int userId) {
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for getLockoutModeForUser");
return LockoutTracker.LOCKOUT_NONE;
}
- return provider.second.getLockoutModeForUser(provider.first, userId);
+ return provider.getLockoutModeForUser(sensorId, userId);
}
@Override // Binder call
- public long getAuthenticatorId(int userId) {
+ public long getAuthenticatorId(int sensorId, int userId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for getAuthenticatorId");
return 0;
}
- return provider.second.getAuthenticatorId(provider.first, userId);
+ return provider.getAuthenticatorId(sensorId, userId);
}
@Override // Binder call
@@ -691,10 +717,11 @@
}
@NonNull
- private List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName) {
+ private List<Fingerprint> getEnrolledFingerprintsDeprecated(int userId, String opPackageName) {
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
- Slog.w(TAG, "Null provider for getEnrolledFingerprints, caller: " + opPackageName);
+ Slog.w(TAG, "Null provider for getEnrolledFingerprintsDeprecated, caller: "
+ + opPackageName);
return Collections.emptyList();
}
diff --git a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
index 62630300..fa03e59 100644
--- a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
+++ b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
@@ -60,12 +60,12 @@
import android.net.ipsec.ike.TunnelModeChildSessionParams;
import android.net.ipsec.ike.exceptions.IkeException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
-import android.net.util.IpRange;
import android.system.OsConstants;
import android.util.Log;
import com.android.internal.net.VpnProfile;
import com.android.internal.util.HexDump;
+import com.android.net.module.util.IpRange;
import java.net.Inet4Address;
import java.net.Inet6Address;
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 6a4ca8d..0b2d4d7 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -151,6 +151,8 @@
* run at a later time. Similarly, when a sync succeeds, backoff is cleared and all associated syncs
* are rescheduled. A rescheduled sync will get a new jobId.
*
+ * See also {@code SyncManager.md} in the same directory for how app-standby affects sync adapters.
+ *
* @hide
*/
public class SyncManager {
diff --git a/services/core/java/com/android/server/content/SyncManager.md b/services/core/java/com/android/server/content/SyncManager.md
new file mode 100644
index 0000000..8507abd
--- /dev/null
+++ b/services/core/java/com/android/server/content/SyncManager.md
@@ -0,0 +1,122 @@
+# Sync Manager notes
+
+## App-standby and Sync Manager
+
+Android 9 Pie introduced
+["App Standby Buckets"](https://developer.android.com/topic/performance/appstandby), which throttles various things
+including
+[JobScheduler](https://developer.android.com/reference/android/app/job/JobScheduler)
+and [AlarmManager](https://developer.android.com/reference/android/app/AlarmManager),
+[among other things](https://developer.android.com/topic/performance/power/power-details),
+for background applications.
+
+Because SyncManager executes sync operations as JobScheduler jobs, sync operations are subject
+to the same throttling.
+
+However, unlike JobScheduler jobs, any apps (with the proper permission) can schedule a sync
+operation in any other apps using
+[ContentResolver.requestSync()](https://developer.android.com/reference/android/content/ContentResolver#requestSync(android.content.SyncRequest)),
+whch means it's possible for a foreground app to request a sync in another app that is either in the
+background or is not even running.
+For example, when the user hits the refresh button on the Contacts app, it'll
+request sync to all the contacts sync adapters, which are implemented in other packages (and they're
+likely not in the foreground).
+
+Because of this, calls to
+[ContentResolver.requestSync()](https://developer.android.com/reference/android/content/ContentResolver#requestSync(android.content.SyncRequest))
+made by foreground apps are special cased such that the resulting sync operations will be
+exempted from app-standby throttling.
+
+### Two Levels of Exemption
+Specifically, there are two different levels of exemption, depending on the state of the caller:
+1. `ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET`
+2. `ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP`, which is more powerful than 1.
+
+The exemption level is calculated in
+[ContentService.getSyncExemptionAndCleanUpExtrasForCaller()](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/content/ContentService.java?q=%22int%20getSyncExemptionAndCleanUpExtrasForCaller%22&ss=android%2Fplatform%2Fsuperproject),
+which was [implemented slightly differently](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/content/ContentService.java?q=%22int%20getSyncExemptionAndCleanUpExtrasForCaller%22&ss=android%2Fplatform%2Fsuperproject)
+in Android 9, compared to Android 10 and later.
+
+The logic is as follows:
+- When the caller's procstate is `PROCESS_STATE_TOP` or above,
+ meaning if the caller has a foreground activity,
+ `SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP` will be set.
+
+- Otherwise, when the caller's procstate is `PROCESS_STATE_IMPORTANT_FOREGROUND` or above,
+ e.g. when the caller has a foreground service, a service bound by the system of a specific kind,
+ `SYNC_EXEMPTION_PROMOTE_BUCKET` will be set.
+
+- Additionally, on Android 10 and later, when the caller is
+ "UID-active" (but the procstate is below `PROCESS_STATE_TOP`),
+ `SYNC_EXEMPTION_PROMOTE_BUCKET` will be set.
+ This is what happens when the app has just received a high-priority FCM, for example.
+ Temp-allowlist is also used in various other situations.
+
+### Behavior of Each Exemption
+
+The exemptions are tracked in `SyncOperation.syncExemptionFlag`.
+
+- Behavior of `SYNC_EXEMPTION_PROMOTE_BUCKET`
+ - This will add `JobInfo.FLAG_EXEMPT_FROM_APP_STANDBY` to the sync job. This makes the job
+ subject to "ACTIVE" app quota, so minimum deferral will be applied to it.
+
+ - This also reports `AppStandbyController.reportExemptedSyncStart()`, so the package that owns
+ the sync adapter is temporarily put in the "ACTIVE" bucket for the
+ duration of `mExemptedSyncStartTimeoutMillis`, whose default is 10 minutes as of 2020-10-23.
+
+ This will allow the app to access network, even if it has been in the `RARE` bucket
+ (in which case, the system cuts its network access).
+
+ Note if the device is dozing or in battery saver, promoting to the "ACTIVE" bucket will still
+ _not_ give the app network access.
+
+- Behavior of `SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP`
+ - This gives all the perks given by `SYNC_EXEMPTION_PROMOTE_BUCKET`, plus puts the target app
+ in the temp-allowlist (by calling `DeviceIdleInternal.addPowerSaveTempWhitelistApp()`)
+ for the duration of `SyncManagerConstants.getKeyExemptionTempWhitelistDurationInSeconds()`,
+ whose default is 10 minutes.
+
+ Temp-allowlist will grant the app network access even if the device is in doze or in battery
+ saver.
+
+ (However, note that when the device is dozing, sync jobs will not run anyway.)
+
+### How Retries Are Handled
+
+- When a sync operation needs a retry, SyncManager creates a new operation (job) with a back-off
+ (in `SyncManager.maybeRescheduleSync()`). In this case, the new sync operation will inherit
+ `SyncOperation.syncExemptionFlag`, unless the number of retries (not counting the original sync
+ job) is equal to or greater than `SyncManagerConstants.getMaxRetriesWithAppStandbyExemption()`,
+ whose default is 5.
+
+### Special-handling of Pre-installed Packages
+
+- When a content provider is accessed, `AppStandbyController.reportContentProviderUsage()` is
+ triggered, which elevates the standby bucket of the associated sync adapters' packages to `ACTIVE`
+ for the duration of `mSyncAdapterTimeoutMillis`, whose default is 10 minutes, but _only for_
+ pre-installed packages. This is to help pre-installed sync adapters, which often don't have UI,
+ sync properly.
+
+- Also, since Android 11, all the pre-installed apps with no activities will be kept in
+ the `ACTIVE` bucket, which greatly relaxes app-standby throttling. But they're still subject
+ to doze and battery saver.
+
+### Summary
+
+- When the device is dozing, no sync operations will be executed.
+
+- Normally, sync operations are subject to App-Standby, which throttles jobs owned by background
+ apps. Jobs owned by foreground apps are not affected.
+
+- A sync operation requested by a foreground activity will be executed immediately even if the
+ app owning the sync adapter is in RARE bucket, and the device is in battery saver.
+
+- A sync operation requested by a foreground service (or a "bound foreground" service)
+ will be executed immediately even if the app owning the sync adapter is in RARE bucket,
+ *unless* the device is in battery saver.
+
+ Since Android 9 and later, the same thing will happen if the requester is temp-allowlisted (e.g.
+ when it has just received a "high-priority FCM").
+
+- There are certain exemptions for pre-installed apps, but doze and battery saver will still
+ block their sync adapters.
\ No newline at end of file
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index b10cd12..3ac2185 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1423,17 +1423,18 @@
private Optional<Integer> getViewportType(DisplayDeviceInfo info) {
// Get the corresponding viewport type.
- if ((info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) {
- return Optional.of(VIEWPORT_INTERNAL);
- } else if (info.touch == DisplayDeviceInfo.TOUCH_EXTERNAL) {
- return Optional.of(VIEWPORT_EXTERNAL);
- } else if (info.touch == DisplayDeviceInfo.TOUCH_VIRTUAL
- && !TextUtils.isEmpty(info.uniqueId)) {
- return Optional.of(VIEWPORT_VIRTUAL);
- } else {
- if (DEBUG) {
- Slog.i(TAG, "Display " + info + " does not support input device matching.");
- }
+ switch (info.touch) {
+ case DisplayDeviceInfo.TOUCH_INTERNAL:
+ return Optional.of(VIEWPORT_INTERNAL);
+ case DisplayDeviceInfo.TOUCH_EXTERNAL:
+ return Optional.of(VIEWPORT_EXTERNAL);
+ case DisplayDeviceInfo.TOUCH_VIRTUAL:
+ if (!TextUtils.isEmpty(info.uniqueId)) {
+ return Optional.of(VIEWPORT_VIRTUAL);
+ }
+ // fallthrough
+ default:
+ Slog.w(TAG, "Display " + info + " does not support input device matching.");
}
return Optional.empty();
}
@@ -1483,13 +1484,6 @@
return null;
}
- // Only allow a single INTERNAL or EXTERNAL viewport by forcing their uniqueIds
- // to be identical (in particular, empty).
- // TODO (b/116824030) allow multiple EXTERNAL viewports and remove this function.
- if (viewportType != VIEWPORT_VIRTUAL) {
- uniqueId = "";
- }
-
DisplayViewport viewport;
final int count = mViewports.size();
for (int i = 0; i < count; i++) {
diff --git a/services/core/java/com/android/server/display/TEST_MAPPING b/services/core/java/com/android/server/display/TEST_MAPPING
new file mode 100644
index 0000000..66ec5c4
--- /dev/null
+++ b/services/core/java/com/android/server/display/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksMockingServicesTests",
+ "options": [
+ {"include-filter": "com.android.server.display"},
+ {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
+ {"exclude-annotation": "androidx.test.filters.FlakyTest"}
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
index e906a7c..90d31f2 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
@@ -21,6 +21,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.StringDef;
import android.content.Context;
import android.hardware.hdmi.HdmiControlManager;
import android.os.Environment;
@@ -68,6 +69,15 @@
private static final int STORAGE_SYSPROPS = 0;
private static final int STORAGE_GLOBAL_SETTINGS = 1;
+ private static final String VALUE_TYPE_STRING = "string";
+ private static final String VALUE_TYPE_INT = "int";
+
+ @StringDef({
+ VALUE_TYPE_STRING,
+ VALUE_TYPE_INT,
+ })
+ private @interface ValueType {}
+
/**
* System property key for Power State Change on Active Source Lost.
*/
@@ -247,17 +257,15 @@
}
}
- private String retrieveValue(@NonNull Setting setting) {
+ private String retrieveValue(@NonNull Setting setting, @NonNull String defaultValue) {
@Storage int storage = getStorage(setting);
String storageKey = getStorageKey(setting);
if (storage == STORAGE_SYSPROPS) {
Slog.d(TAG, "Reading '" + storageKey + "' sysprop.");
- return mStorageAdapter.retrieveSystemProperty(storageKey,
- setting.getDefaultValue().getStringValue());
+ return mStorageAdapter.retrieveSystemProperty(storageKey, defaultValue);
} else if (storage == STORAGE_GLOBAL_SETTINGS) {
Slog.d(TAG, "Reading '" + storageKey + "' global setting.");
- return mStorageAdapter.retrieveGlobalSetting(mContext, storageKey,
- setting.getDefaultValue().getStringValue());
+ return mStorageAdapter.retrieveGlobalSetting(mContext, storageKey, defaultValue);
}
return null;
}
@@ -316,13 +324,41 @@
}
/**
- * For a given setting name returns values that are allowed for that setting.
+ * For a given setting name returns true if and only if the value type of that
+ * setting is a string.
*/
- public List<String> getAllowedValues(@NonNull @CecSettingName String name) {
+ public boolean isStringValueType(@NonNull @CecSettingName String name) {
Setting setting = getSetting(name);
if (setting == null) {
throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
}
+ return getSetting(name).getValueType().equals(VALUE_TYPE_STRING);
+ }
+
+ /**
+ * For a given setting name returns true if and only if the value type of that
+ * setting is an int.
+ */
+ public boolean isIntValueType(@NonNull @CecSettingName String name) {
+ Setting setting = getSetting(name);
+ if (setting == null) {
+ throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
+ }
+ return getSetting(name).getValueType().equals(VALUE_TYPE_INT);
+ }
+
+ /**
+ * For a given setting name returns values that are allowed for that setting (string).
+ */
+ public List<String> getAllowedStringValues(@NonNull @CecSettingName String name) {
+ Setting setting = getSetting(name);
+ if (setting == null) {
+ throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
+ }
+ if (!setting.getValueType().equals(VALUE_TYPE_STRING)) {
+ throw new IllegalArgumentException("Setting '" + name
+ + "' is not a string-type setting.");
+ }
List<String> allowedValues = new ArrayList<String>();
for (Value allowedValue : setting.getAllowedValues().getValue()) {
allowedValues.add(allowedValue.getStringValue());
@@ -331,32 +367,92 @@
}
/**
- * For a given setting name returns the default value for that setting.
+ * For a given setting name returns values that are allowed for that setting (string).
*/
- public String getDefaultValue(@NonNull @CecSettingName String name) {
+ public List<Integer> getAllowedIntValues(@NonNull @CecSettingName String name) {
Setting setting = getSetting(name);
if (setting == null) {
throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
}
+ if (!setting.getValueType().equals(VALUE_TYPE_INT)) {
+ throw new IllegalArgumentException("Setting '" + name
+ + "' is not a string-type setting.");
+ }
+ List<Integer> allowedValues = new ArrayList<Integer>();
+ for (Value allowedValue : setting.getAllowedValues().getValue()) {
+ allowedValues.add(allowedValue.getIntValue());
+ }
+ return allowedValues;
+ }
+
+ /**
+ * For a given setting name returns the default value for that setting (string).
+ */
+ public String getDefaultStringValue(@NonNull @CecSettingName String name) {
+ Setting setting = getSetting(name);
+ if (setting == null) {
+ throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
+ }
+ if (!setting.getValueType().equals(VALUE_TYPE_STRING)) {
+ throw new IllegalArgumentException("Setting '" + name
+ + "' is not a string-type setting.");
+ }
return getSetting(name).getDefaultValue().getStringValue();
}
/**
- * For a given setting name returns the current value of that setting.
+ * For a given setting name returns the default value for that setting (int).
*/
- public String getValue(@NonNull @CecSettingName String name) {
+ public int getDefaultIntValue(@NonNull @CecSettingName String name) {
Setting setting = getSetting(name);
if (setting == null) {
throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
}
- Slog.d(TAG, "Getting CEC setting value '" + name + "'.");
- return retrieveValue(setting);
+ if (!setting.getValueType().equals(VALUE_TYPE_INT)) {
+ throw new IllegalArgumentException("Setting '" + name
+ + "' is not a string-type setting.");
+ }
+ return getSetting(name).getDefaultValue().getIntValue();
}
/**
- * For a given setting name and value sets the current value of that setting.
+ * For a given setting name returns the current value of that setting (string).
*/
- public void setValue(@NonNull @CecSettingName String name, @NonNull String value) {
+ public String getStringValue(@NonNull @CecSettingName String name) {
+ Setting setting = getSetting(name);
+ if (setting == null) {
+ throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
+ }
+ if (!setting.getValueType().equals(VALUE_TYPE_STRING)) {
+ throw new IllegalArgumentException("Setting '" + name
+ + "' is not a string-type setting.");
+ }
+ Slog.d(TAG, "Getting CEC setting value '" + name + "'.");
+ return retrieveValue(setting, setting.getDefaultValue().getStringValue());
+ }
+
+ /**
+ * For a given setting name returns the current value of that setting (int).
+ */
+ public int getIntValue(@NonNull @CecSettingName String name) {
+ Setting setting = getSetting(name);
+ if (setting == null) {
+ throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
+ }
+ if (!setting.getValueType().equals(VALUE_TYPE_INT)) {
+ throw new IllegalArgumentException("Setting '" + name
+ + "' is not a int-type setting.");
+ }
+ Slog.d(TAG, "Getting CEC setting value '" + name + "'.");
+ String defaultValue = Integer.toString(setting.getDefaultValue().getIntValue());
+ String value = retrieveValue(setting, defaultValue);
+ return Integer.parseInt(value);
+ }
+
+ /**
+ * For a given setting name and value sets the current value of that setting (string).
+ */
+ public void setStringValue(@NonNull @CecSettingName String name, @NonNull String value) {
Setting setting = getSetting(name);
if (setting == null) {
throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
@@ -364,11 +460,38 @@
if (!setting.getUserConfigurable()) {
throw new IllegalArgumentException("Updating CEC setting '" + name + "' prohibited.");
}
- if (!getAllowedValues(name).contains(value)) {
+ if (!setting.getValueType().equals(VALUE_TYPE_STRING)) {
+ throw new IllegalArgumentException("Setting '" + name
+ + "' is not a string-type setting.");
+ }
+ if (!getAllowedStringValues(name).contains(value)) {
throw new IllegalArgumentException("Invalid CEC setting '" + name
+ "' value: '" + value + "'.");
}
Slog.d(TAG, "Updating CEC setting '" + name + "' to '" + value + "'.");
storeValue(setting, value);
}
+
+ /**
+ * For a given setting name and value sets the current value of that setting (int).
+ */
+ public void setIntValue(@NonNull @CecSettingName String name, int value) {
+ Setting setting = getSetting(name);
+ if (setting == null) {
+ throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
+ }
+ if (!setting.getUserConfigurable()) {
+ throw new IllegalArgumentException("Updating CEC setting '" + name + "' prohibited.");
+ }
+ if (!setting.getValueType().equals(VALUE_TYPE_INT)) {
+ throw new IllegalArgumentException("Setting '" + name
+ + "' is not a int-type setting.");
+ }
+ if (!getAllowedIntValues(name).contains(value)) {
+ throw new IllegalArgumentException("Invalid CEC setting '" + name
+ + "' value: '" + value + "'.");
+ }
+ Slog.d(TAG, "Updating CEC setting '" + name + "' to '" + value + "'.");
+ storeValue(setting, Integer.toString(value));
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index fe4fd38..9dc0079 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -495,17 +495,17 @@
private byte[] getSupportedShortAudioDescriptorsFromConfig(
List<DeviceConfig> deviceConfig, @AudioCodec int[] audioFormatCodes) {
DeviceConfig deviceConfigToUse = null;
+ String audioDeviceName = SystemProperties.get(
+ Constants.PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT,
+ "VX_AUDIO_DEVICE_IN_HDMI_ARC");
for (DeviceConfig device : deviceConfig) {
- // TODO(amyjojo) use PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT to get the audio device name
- if (device.name.equals("VX_AUDIO_DEVICE_IN_HDMI_ARC")) {
+ if (device.name.equals(audioDeviceName)) {
deviceConfigToUse = device;
break;
}
}
if (deviceConfigToUse == null) {
- // TODO(amyjojo) use PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT to get the audio device name
- Slog.w(TAG, "sadConfig.xml does not have required device info for "
- + "VX_AUDIO_DEVICE_IN_HDMI_ARC");
+ Slog.w(TAG, "sadConfig.xml does not have required device info for " + audioDeviceName);
return new byte[0];
}
HashMap<Integer, byte[]> map = new HashMap<>();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index 7d76628..fe97f70 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
@@ -122,7 +122,25 @@
addValidationInfo(Constants.MESSAGE_RECORD_STATUS,
new RecordStatusInfoValidator(), DEST_DIRECT);
- // TODO: Handle messages for the Timer Programming.
+ addValidationInfo(
+ Constants.MESSAGE_CLEAR_ANALOG_TIMER, new AnalogueTimerValidator(), DEST_DIRECT);
+ addValidationInfo(
+ Constants.MESSAGE_CLEAR_DIGITAL_TIMER, new DigitalTimerValidator(), DEST_DIRECT);
+ addValidationInfo(
+ Constants.MESSAGE_CLEAR_EXTERNAL_TIMER, new ExternalTimerValidator(), DEST_DIRECT);
+ addValidationInfo(
+ Constants.MESSAGE_SET_ANALOG_TIMER, new AnalogueTimerValidator(), DEST_DIRECT);
+ addValidationInfo(
+ Constants.MESSAGE_SET_DIGITAL_TIMER, new DigitalTimerValidator(), DEST_DIRECT);
+ addValidationInfo(
+ Constants.MESSAGE_SET_EXTERNAL_TIMER, new ExternalTimerValidator(), DEST_DIRECT);
+ addValidationInfo(
+ Constants.MESSAGE_SET_TIMER_PROGRAM_TITLE, new AsciiValidator(1, 14), DEST_DIRECT);
+ addValidationInfo(
+ Constants.MESSAGE_TIMER_CLEARED_STATUS,
+ new TimerClearedStatusValidator(),
+ DEST_DIRECT);
+ addValidationInfo(Constants.MESSAGE_TIMER_STATUS, new TimerStatusValidator(), DEST_DIRECT);
// Messages for the System Information.
FixedLengthValidator oneByteValidator = new FixedLengthValidator(1);
@@ -343,6 +361,277 @@
return true;
}
+ /**
+ * Check if the given value is a valid day of month. A valid value is one which falls within the
+ * range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
+ *
+ * @param value day of month
+ * @return true if the day of month is valid
+ */
+ private boolean isValidDayOfMonth(int value) {
+ return isWithinRange(value, 1, 31);
+ }
+
+ /**
+ * Check if the given value is a valid month of year. A valid value is one which falls within
+ * the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
+ *
+ * @param value month of year
+ * @return true if the month of year is valid
+ */
+ private boolean isValidMonthOfYear(int value) {
+ return isWithinRange(value, 1, 12);
+ }
+
+ /**
+ * Check if the given value is a valid hour. A valid value is one which falls within the range
+ * description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
+ *
+ * @param value hour
+ * @return true if the hour is valid
+ */
+ private boolean isValidHour(int value) {
+ return isWithinRange(value, 0, 23);
+ }
+
+ /**
+ * Check if the given value is a valid minute. A valid value is one which falls within the range
+ * description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
+ *
+ * @param value minute
+ * @return true if the minute is valid
+ */
+ private boolean isValidMinute(int value) {
+ return isWithinRange(value, 0, 59);
+ }
+
+ /**
+ * Check if the given value is a valid duration hours. A valid value is one which falls within
+ * the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
+ *
+ * @param value duration hours
+ * @return true if the duration hours is valid
+ */
+ private boolean isValidDurationHours(int value) {
+ return isWithinRange(value, 0, 99);
+ }
+
+ /**
+ * Check if the given value is a valid recording sequence. A valid value is adheres to range
+ * description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
+ *
+ * @param value recording sequence
+ * @return true if the given recording sequence is valid
+ */
+ private boolean isValidRecordingSequence(int value) {
+ value = value & 0xFF;
+ // Validate bit 7 is set to zero
+ if ((value & 0x80) != 0x00) {
+ return false;
+ }
+ // Validate than not more than one bit is set
+ return (Integer.bitCount(value) <= 1);
+ }
+
+ /**
+ * Check if the given value is a valid analogue broadcast type. A valid value is one which falls
+ * within the range description defined in CEC 1.4 Specification : Operand Descriptions (Section
+ * 17)
+ *
+ * @param value analogue broadcast type
+ * @return true if the analogue broadcast type is valid
+ */
+ private boolean isValidAnalogueBroadcastType(int value) {
+ return isWithinRange(value, 0x00, 0x02);
+ }
+
+ /**
+ * Check if the given value is a valid analogue frequency. A valid value is one which falls
+ * within the range description defined in CEC 1.4 Specification : Operand Descriptions (Section
+ * 17)
+ *
+ * @param value analogue frequency
+ * @return true if the analogue frequency is valid
+ */
+ private boolean isValidAnalogueFrequency(int value) {
+ value = value & 0xFFFF;
+ return (value != 0x000 && value != 0xFFFF);
+ }
+
+ /**
+ * Check if the given value is a valid broadcast system. A valid value is one which falls within
+ * the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
+ *
+ * @param value broadcast system
+ * @return true if the broadcast system is valid
+ */
+ private boolean isValidBroadcastSystem(int value) {
+ return isWithinRange(value, 0, 31);
+ }
+
+ /**
+ * Check if the given value is a ARIB type. A valid value is one which falls within the range
+ * description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
+ *
+ * @param value Digital Broadcast System
+ * @return true if the Digital Broadcast System is ARIB type
+ */
+ private boolean isAribDbs(int value) {
+ return (value == 0x00 || isWithinRange(value, 0x08, 0x0A));
+ }
+
+ /**
+ * Check if the given value is a ATSC type. A valid value is one which falls within the range
+ * description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
+ *
+ * @param value Digital Broadcast System
+ * @return true if the Digital Broadcast System is ATSC type
+ */
+ private boolean isAtscDbs(int value) {
+ return (value == 0x01 || isWithinRange(value, 0x10, 0x12));
+ }
+
+ /**
+ * Check if the given value is a DVB type. A valid value is one which falls within the range
+ * description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
+ *
+ * @param value Digital Broadcast System
+ * @return true if the Digital Broadcast System is DVB type
+ */
+ private boolean isDvbDbs(int value) {
+ return (value == 0x02 || isWithinRange(value, 0x18, 0x1B));
+ }
+
+ /**
+ * Check if the given value is a valid Digital Broadcast System. A valid value is one which
+ * falls within the range description defined in CEC 1.4 Specification : Operand Descriptions
+ * (Section 17)
+ *
+ * @param value Digital Broadcast System
+ * @return true if the Digital Broadcast System is valid
+ */
+ private boolean isValidDigitalBroadcastSystem(int value) {
+ return (isAribDbs(value) || isAtscDbs(value) || isDvbDbs(value));
+ }
+
+ /**
+ * Check if the given value is a valid Digital Service Identification. A valid value is one
+ * which falls within the range description defined in CEC 1.4 Specification : Operand
+ * Descriptions (Section 17)
+ *
+ * @param params Digital Timer Message parameters
+ * @param offset start offset of Digital Service Identification
+ * @return true if the Digital Service Identification is valid
+ */
+ private boolean isValidDigitalServiceIdentification(byte[] params, int offset) {
+ // MSB contains Service Identification Method
+ int serviceIdentificationMethod = params[offset] & 0x80;
+ // Last 7 bits contains Digital Broadcast System
+ int digitalBroadcastSystem = params[offset] & 0x7F;
+ offset = offset + 1;
+ if (serviceIdentificationMethod == 0x00) {
+ // Services identified by Digital IDs
+ if (isAribDbs(digitalBroadcastSystem)) {
+ // Validate ARIB type have 6 byte data
+ return params.length - offset >= 6;
+ } else if (isAtscDbs(digitalBroadcastSystem)) {
+ // Validate ATSC type have 4 byte data
+ return params.length - offset >= 4;
+ } else if (isDvbDbs(digitalBroadcastSystem)) {
+ // Validate DVB type have 6 byte data
+ return params.length - offset >= 6;
+ }
+ } else if (serviceIdentificationMethod == 0x80) {
+ // Services identified by Channel
+ if (isValidDigitalBroadcastSystem(digitalBroadcastSystem)) {
+ // First 6 bits contain Channel Number Format
+ int channelNumberFormat = params[offset] & 0xFC;
+ if (channelNumberFormat == 0x04) {
+ // Validate it contains 1-part Channel Number data (16 bits)
+ return params.length - offset >= 3;
+ } else if (channelNumberFormat == 0x08) {
+ // Validate it contains Major Channel Number and Minor Channel Number (26 bits)
+ return params.length - offset >= 4;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if the given value is a valid External Plug. A valid value is one which falls within
+ * the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
+ *
+ * @param value External Plug
+ * @return true if the External Plug is valid
+ */
+ private boolean isValidExternalPlug(int value) {
+ return isWithinRange(value, 1, 255);
+ }
+
+ /**
+ * Check if the given value is a valid External Source. A valid value is one which falls within
+ * the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
+ *
+ * @param value External Source Specifier
+ * @return true if the External Source is valid
+ */
+ private boolean isValidExternalSource(byte[] params, int offset) {
+ int externalSourceSpecifier = params[offset];
+ offset = offset + 1;
+ if (externalSourceSpecifier == 0x04) {
+ // External Plug
+ return isValidExternalPlug(params[offset]);
+ } else if (externalSourceSpecifier == 0x05) {
+ // External Physical Address
+ // Validate it contains 2 bytes Physical Address
+ if (params.length - offset >= 2) {
+ return isValidPhysicalAddress(params, offset);
+ }
+ }
+ return false;
+ }
+
+ private boolean isValidProgrammedInfo(int programedInfo) {
+ return (isWithinRange(programedInfo, 0x00, 0x0B));
+ }
+
+ private boolean isValidNotProgrammedErrorInfo(int nonProgramedErrorInfo) {
+ return (isWithinRange(nonProgramedErrorInfo, 0x00, 0x0E));
+ }
+
+ private boolean isValidTimerStatusData(byte[] params, int offset) {
+ int programedIndicator = params[offset] & 0x10;
+ boolean durationAvailable = false;
+ if (programedIndicator == 0x10) {
+ // Programmed
+ int programedInfo = params[offset] & 0x0F;
+ if (isValidProgrammedInfo(programedInfo)) {
+ if (programedInfo == 0x09 || programedInfo == 0x0B) {
+ durationAvailable = true;
+ } else {
+ return true;
+ }
+ }
+ } else {
+ // Non programmed
+ int nonProgramedErrorInfo = params[offset] & 0x0F;
+ if (isValidNotProgrammedErrorInfo(nonProgramedErrorInfo)) {
+ if (nonProgramedErrorInfo == 0x0E) {
+ durationAvailable = true;
+ } else {
+ return true;
+ }
+ }
+ }
+ offset = offset + 1;
+ // Duration Available (2 bytes)
+ if (durationAvailable && params.length - offset >= 2) {
+ return (isValidDurationHours(params[offset]) && isValidMinute(params[offset + 1]));
+ }
+ return false;
+ }
+
private class PhysicalAddressValidator implements ParameterValidator {
@Override
public int isValid(byte[] params) {
@@ -472,4 +761,106 @@
return toErrorCode(isWithinRange(params[0], mMinValue, mMaxValue));
}
}
+
+ /**
+ * Check if the given Analogue Timer message parameters are valid. Valid parameters should
+ * adhere to message description of Analogue Timer defined in CEC 1.4 Specification : Message
+ * Descriptions for Timer Programming Feature (CEC Table 12)
+ */
+ private class AnalogueTimerValidator implements ParameterValidator {
+ @Override
+ public int isValid(byte[] params) {
+ if (params.length < 11) {
+ return ERROR_PARAMETER_SHORT;
+ }
+ return toErrorCode(
+ isValidDayOfMonth(params[0]) // Day of Month
+ && isValidMonthOfYear(params[1]) // Month of Year
+ && isValidHour(params[2]) // Start Time - Hour
+ && isValidMinute(params[3]) // Start Time - Minute
+ && isValidDurationHours(params[4]) // Duration - Duration Hours
+ && isValidMinute(params[5]) // Duration - Minute
+ && isValidRecordingSequence(params[6]) // Recording Sequence
+ && isValidAnalogueBroadcastType(params[7]) // Analogue Broadcast Type
+ && isValidAnalogueFrequency(
+ HdmiUtils.twoBytesToInt(params, 8)) // Analogue Frequency
+ && isValidBroadcastSystem(params[10])); // Broadcast System
+ }
+ }
+
+ /**
+ * Check if the given Digital Timer message parameters are valid. Valid parameters should adhere
+ * to message description of Digital Timer defined in CEC 1.4 Specification : Message
+ * Descriptions for Timer Programming Feature (CEC Table 12)
+ */
+ private class DigitalTimerValidator implements ParameterValidator {
+ @Override
+ public int isValid(byte[] params) {
+ if (params.length < 11) {
+ return ERROR_PARAMETER_SHORT;
+ }
+ return toErrorCode(
+ isValidDayOfMonth(params[0]) // Day of Month
+ && isValidMonthOfYear(params[1]) // Month of Year
+ && isValidHour(params[2]) // Start Time - Hour
+ && isValidMinute(params[3]) // Start Time - Minute
+ && isValidDurationHours(params[4]) // Duration - Duration Hours
+ && isValidMinute(params[5]) // Duration - Minute
+ && isValidRecordingSequence(params[6]) // Recording Sequence
+ && isValidDigitalServiceIdentification(
+ params, 7)); // Digital Service Identification
+ }
+ }
+
+ /**
+ * Check if the given External Timer message parameters are valid. Valid parameters should
+ * adhere to message description of External Timer defined in CEC 1.4 Specification : Message
+ * Descriptions for Timer Programming Feature (CEC Table 12)
+ */
+ private class ExternalTimerValidator implements ParameterValidator {
+ @Override
+ public int isValid(byte[] params) {
+ if (params.length < 9) {
+ return ERROR_PARAMETER_SHORT;
+ }
+ return toErrorCode(
+ isValidDayOfMonth(params[0]) // Day of Month
+ && isValidMonthOfYear(params[1]) // Month of Year
+ && isValidHour(params[2]) // Start Time - Hour
+ && isValidMinute(params[3]) // Start Time - Minute
+ && isValidDurationHours(params[4]) // Duration - Duration Hours
+ && isValidMinute(params[5]) // Duration - Minute
+ && isValidRecordingSequence(params[6]) // Recording Sequence
+ && isValidExternalSource(params, 7)); // External Source
+ }
+ }
+
+ /**
+ * Check if the given timer cleared status parameter is valid. A valid parameter should lie
+ * within the range description defined in CEC 1.4 Specification : Operand Descriptions
+ * (Section 17)
+ */
+ private class TimerClearedStatusValidator implements ParameterValidator {
+ @Override
+ public int isValid(byte[] params) {
+ if (params.length < 1) {
+ return ERROR_PARAMETER_SHORT;
+ }
+ return toErrorCode(isWithinRange(params[0], 0x00, 0x02) || (params[0] & 0xFF) == 0x80);
+ }
+ }
+
+ /**
+ * Check if the given timer status data parameter is valid. A valid parameter should lie within
+ * the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
+ */
+ private class TimerStatusValidator implements ParameterValidator {
+ @Override
+ public int isValid(byte[] params) {
+ if (params.length < 1) {
+ return ERROR_PARAMETER_SHORT;
+ }
+ return toErrorCode(isValidTimerStatusData(params, 0));
+ }
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index da4c6f1..cc0b882 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -2242,9 +2242,15 @@
List<String> allSettings = hdmiCecConfig.getAllSettings();
Set<String> userSettings = new HashSet<>(hdmiCecConfig.getUserSettings());
for (String setting : allSettings) {
- pw.println(setting + ": " + hdmiCecConfig.getValue(setting)
- + " (default: " + hdmiCecConfig.getDefaultValue(setting) + ")"
- + (userSettings.contains(setting) ? " [modifiable]" : ""));
+ if (hdmiCecConfig.isStringValueType(setting)) {
+ pw.println(setting + " (string): " + hdmiCecConfig.getStringValue(setting)
+ + " (default: " + hdmiCecConfig.getDefaultStringValue(setting) + ")"
+ + (userSettings.contains(setting) ? " [modifiable]" : ""));
+ } else if (hdmiCecConfig.isIntValueType(setting)) {
+ pw.println(setting + " (int): " + hdmiCecConfig.getIntValue(setting)
+ + " (default: " + hdmiCecConfig.getDefaultIntValue(setting) + ")"
+ + (userSettings.contains(setting) ? " [modifiable]" : ""));
+ }
}
pw.decreaseIndent();
@@ -2273,33 +2279,68 @@
}
@Override
- public List<String> getAllowedCecSettingValues(String name) {
+ public List<String> getAllowedCecSettingStringValues(String name) {
enforceAccessPermission();
long token = Binder.clearCallingIdentity();
try {
- return HdmiControlService.this.getHdmiCecConfig().getAllowedValues(name);
+ return HdmiControlService.this.getHdmiCecConfig().getAllowedStringValues(name);
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
- public String getCecSettingValue(String name) {
+ public int[] getAllowedCecSettingIntValues(String name) {
enforceAccessPermission();
long token = Binder.clearCallingIdentity();
try {
- return HdmiControlService.this.getHdmiCecConfig().getValue(name);
+ List<Integer> allowedValues =
+ HdmiControlService.this.getHdmiCecConfig().getAllowedIntValues(name);
+ return allowedValues.stream().mapToInt(i->i).toArray();
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
- public void setCecSettingValue(String name, String value) {
+ public String getCecSettingStringValue(String name) {
enforceAccessPermission();
long token = Binder.clearCallingIdentity();
try {
- HdmiControlService.this.getHdmiCecConfig().setValue(name, value);
+ return HdmiControlService.this.getHdmiCecConfig().getStringValue(name);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void setCecSettingStringValue(String name, String value) {
+ enforceAccessPermission();
+ long token = Binder.clearCallingIdentity();
+ try {
+ HdmiControlService.this.getHdmiCecConfig().setStringValue(name, value);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public int getCecSettingIntValue(String name) {
+ enforceAccessPermission();
+ long token = Binder.clearCallingIdentity();
+ try {
+ return HdmiControlService.this.getHdmiCecConfig().getIntValue(name);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void setCecSettingIntValue(String name, int value) {
+ enforceAccessPermission();
+ long token = Binder.clearCallingIdentity();
+ try {
+ HdmiControlService.this.getHdmiCecConfig().setIntValue(name, value);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 3f4ddea..9658800 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -2095,7 +2095,7 @@
DisplayThread.getHandler().post(() ->
Toast.makeText(mContext,
"Touch obscured by " + packageName
- + " will be blocked. Check go/s-untrusted-touches",
+ + " will be blocked. Check go/untrusted-touches",
Toast.LENGTH_SHORT).show());
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index b532fa1..6dd91e5 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -15,6 +15,7 @@
package com.android.server.inputmethod;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.server.inputmethod.InputMethodManagerServiceProto.ACCESSIBILITY_REQUESTING_NO_SOFT_KEYBOARD;
import static android.server.inputmethod.InputMethodManagerServiceProto.BACK_DISPOSITION;
import static android.server.inputmethod.InputMethodManagerServiceProto.BOUND_TO_METHOD;
@@ -110,6 +111,7 @@
import android.os.ShellCommand;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
@@ -936,7 +938,7 @@
* <p>TODO: Consider to follow what other system services have been doing to manage
* constants (e.g. {@link android.provider.Settings.Global#ACTIVITY_MANAGER_CONSTANTS}).</p>
*/
- private final static int ENTRY_SIZE_FOR_HIGH_RAM_DEVICE = 16;
+ private final static int ENTRY_SIZE_FOR_HIGH_RAM_DEVICE = 32;
/**
* Entry size for non low-RAM devices.
@@ -3106,6 +3108,7 @@
@Override
public boolean showSoftInput(IInputMethodClient client, IBinder windowToken, int flags,
ResultReceiver resultReceiver) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showSoftInput");
int uid = Binder.getCallingUid();
synchronized (mMethodMap) {
if (!calledFromValidUserLocked()) {
@@ -3133,6 +3136,7 @@
SoftInputShowHideReason.SHOW_SOFT_INPUT);
} finally {
Binder.restoreCallingIdentity(ident);
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
}
@@ -3225,6 +3229,7 @@
}
final long ident = Binder.clearCallingIdentity();
try {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.hideSoftInput");
if (mCurClient == null || client == null
|| mCurClient.client.asBinder() != client.asBinder()) {
// We need to check if this is the current client with
@@ -3248,15 +3253,13 @@
SoftInputShowHideReason.HIDE_SOFT_INPUT);
} finally {
Binder.restoreCallingIdentity(ident);
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
}
boolean hideCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver,
@SoftInputShowHideReason int reason) {
- if (mCurClient == null || mCurClient.curSession == null) {
- return false;
- }
if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
&& (mShowExplicitlyRequested || mShowForced)) {
if (DEBUG) Slog.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide");
@@ -3313,43 +3316,52 @@
Slog.e(TAG, "windowToken cannot be null.");
return InputBindResult.NULL;
}
- final int callingUserId = UserHandle.getCallingUserId();
- final int userId;
- if (attribute != null && attribute.targetInputMethodUser != null
- && attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
- mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- "Using EditorInfo.targetInputMethodUser requires INTERACT_ACROSS_USERS_FULL.");
- userId = attribute.targetInputMethodUser.getIdentifier();
- if (!mUserManagerInternal.isUserRunning(userId)) {
- // There is a chance that we hit here because of race condition. Let's just return
- // an error code instead of crashing the caller process, which at least has
- // INTERACT_ACROSS_USERS_FULL permission thus is likely to be an important process.
- Slog.e(TAG, "User #" + userId + " is not running.");
- return InputBindResult.INVALID_USER;
+ try {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
+ "IMMS.startInputOrWindowGainedFocus");
+ final int callingUserId = UserHandle.getCallingUserId();
+ final int userId;
+ if (attribute != null && attribute.targetInputMethodUser != null
+ && attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
+ mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "Using EditorInfo.targetInputMethodUser requires"
+ + " INTERACT_ACROSS_USERS_FULL.");
+ userId = attribute.targetInputMethodUser.getIdentifier();
+ if (!mUserManagerInternal.isUserRunning(userId)) {
+ // There is a chance that we hit here because of race condition. Let's just
+ // return an error code instead of crashing the caller process, which at least
+ // has INTERACT_ACROSS_USERS_FULL permission thus is likely to be an important
+ // process.
+ Slog.e(TAG, "User #" + userId + " is not running.");
+ return InputBindResult.INVALID_USER;
+ }
+ } else {
+ userId = callingUserId;
}
- } else {
- userId = callingUserId;
- }
- final InputBindResult result;
- synchronized (mMethodMap) {
- final long ident = Binder.clearCallingIdentity();
- try {
- result = startInputOrWindowGainedFocusInternalLocked(startInputReason, client,
- windowToken, startInputFlags, softInputMode, windowFlags, attribute,
- inputContext, missingMethods, unverifiedTargetSdkVersion, userId);
- } finally {
- Binder.restoreCallingIdentity(ident);
+ final InputBindResult result;
+ synchronized (mMethodMap) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ result = startInputOrWindowGainedFocusInternalLocked(startInputReason, client,
+ windowToken, startInputFlags, softInputMode, windowFlags, attribute,
+ inputContext, missingMethods, unverifiedTargetSdkVersion, userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
+ if (result == null) {
+ // This must never happen, but just in case.
+ Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
+ + InputMethodDebug.startInputReasonToString(startInputReason)
+ + " windowFlags=#" + Integer.toHexString(windowFlags)
+ + " editorInfo=" + attribute);
+ return InputBindResult.NULL;
+ }
+
+ return result;
+ } finally {
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
- if (result == null) {
- // This must never happen, but just in case.
- Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
- + InputMethodDebug.startInputReasonToString(startInputReason)
- + " windowFlags=#" + Integer.toHexString(windowFlags)
- + " editorInfo=" + attribute);
- return InputBindResult.NULL;
- }
- return result;
}
@NonNull
@@ -4127,6 +4139,7 @@
@BinderThread
private void applyImeVisibility(IBinder token, IBinder windowToken, boolean setVisible) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.applyImeVisibility");
synchronized (mMethodMap) {
if (!calledWithValidTokenLocked(token)) {
return;
@@ -4148,6 +4161,7 @@
mWindowManagerInternal.showImePostLayout(mShowRequestWindowMap.get(windowToken));
}
}
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
private void setInputMethodWithSubtypeIdLocked(IBinder token, String id, int subtypeId) {
@@ -4175,6 +4189,7 @@
@BinderThread
private void hideMySoftInput(@NonNull IBinder token, int flags) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.hideMySoftInput");
synchronized (mMethodMap) {
if (!calledWithValidTokenLocked(token)) {
return;
@@ -4189,10 +4204,12 @@
Binder.restoreCallingIdentity(ident);
}
}
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
@BinderThread
private void showMySoftInput(@NonNull IBinder token, int flags) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showMySoftInput");
synchronized (mMethodMap) {
if (!calledWithValidTokenLocked(token)) {
return;
@@ -4205,6 +4222,7 @@
Binder.restoreCallingIdentity(ident);
}
}
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
void setEnabledSessionInMainThread(SessionState session) {
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 9c48d23..18185ae 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -21,10 +21,10 @@
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.location.LocationManager.BLOCK_PENDING_INTENT_SYSTEM_API_USAGE;
import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationManager.NETWORK_PROVIDER;
-import static android.location.LocationManager.PREVENT_PENDING_INTENT_SYSTEM_API_USAGE;
import static android.location.LocationRequest.LOW_POWER_EXCEPTIONS;
import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
@@ -597,14 +597,15 @@
// simplest to ensure these apis are simply never set for pending intent requests. the same
// does not apply for listener requests since those will have the process (including the
// listener) killed on permission removal
- boolean usesSystemApi = request.isLowPower()
- || request.isHiddenFromAppOps()
- || request.isLocationSettingsIgnored()
- || !request.getWorkSource().isEmpty();
- if (usesSystemApi
- && isChangeEnabled(PREVENT_PENDING_INTENT_SYSTEM_API_USAGE, identity.getUid())) {
- throw new SecurityException(
- "PendingIntent location requests may not use system APIs: " + request);
+ if (isChangeEnabled(BLOCK_PENDING_INTENT_SYSTEM_API_USAGE, identity.getUid())) {
+ boolean usesSystemApi = request.isLowPower()
+ || request.isHiddenFromAppOps()
+ || request.isLocationSettingsIgnored()
+ || !request.getWorkSource().isEmpty();
+ if (usesSystemApi) {
+ throw new SecurityException(
+ "PendingIntent location requests may not use system APIs: " + request);
+ }
}
request = validateLocationRequest(request, identity);
@@ -987,9 +988,13 @@
@Override
public void getFromLocation(double latitude, double longitude, int maxResults,
GeocoderParams params, IGeocodeListener listener) {
+ // validate identity
+ CallerIdentity identity = CallerIdentity.fromBinder(mContext, params.getClientPackage(),
+ params.getClientAttributionTag());
+ Preconditions.checkArgument(identity.getUid() == params.getClientUid());
+
if (mGeocodeProvider != null) {
- mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
- params, listener);
+ mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, params, listener);
} else {
try {
listener.onResults(null, Collections.emptyList());
@@ -1004,6 +1009,11 @@
double lowerLeftLatitude, double lowerLeftLongitude,
double upperRightLatitude, double upperRightLongitude, int maxResults,
GeocoderParams params, IGeocodeListener listener) {
+ // validate identity
+ CallerIdentity identity = CallerIdentity.fromBinder(mContext, params.getClientPackage(),
+ params.getClientAttributionTag());
+ Preconditions.checkArgument(identity.getUid() == params.getClientUid());
+
if (mGeocodeProvider != null) {
mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
diff --git a/services/core/java/com/android/server/location/geofence/GeofenceManager.java b/services/core/java/com/android/server/location/geofence/GeofenceManager.java
index 7a59cba..c23bd85 100644
--- a/services/core/java/com/android/server/location/geofence/GeofenceManager.java
+++ b/services/core/java/com/android/server/location/geofence/GeofenceManager.java
@@ -296,15 +296,15 @@
@Nullable String attributionTag) {
LocationPermissions.enforceCallingOrSelfLocationPermission(mContext, PERMISSION_FINE);
- CallerIdentity callerIdentity = CallerIdentity.fromBinder(mContext, packageName,
+ CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName,
attributionTag, AppOpsManager.toReceiverId(pendingIntent));
- final long identity = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
putRegistration(new GeofenceKey(pendingIntent, geofence),
- new GeofenceRegistration(geofence, callerIdentity, pendingIntent));
+ new GeofenceRegistration(geofence, identity, pendingIntent));
} finally {
- Binder.restoreCallingIdentity(identity);
+ Binder.restoreCallingIdentity(ident);
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationChannelLogger.java b/services/core/java/com/android/server/notification/NotificationChannelLogger.java
index 51faac7..36eec26 100644
--- a/services/core/java/com/android/server/notification/NotificationChannelLogger.java
+++ b/services/core/java/com/android/server/notification/NotificationChannelLogger.java
@@ -215,6 +215,13 @@
}
/**
+ * @return Small hash of the conversation ID, if present, or 0 otherwise.
+ */
+ static int getConversationIdHash(@NonNull NotificationChannel channel) {
+ return SmallHash.hash(channel.getConversationId());
+ }
+
+ /**
* @return Small hash of the channel ID, if present, or 0 otherwise.
*/
static int getIdHash(@NonNull NotificationChannelGroup group) {
diff --git a/services/core/java/com/android/server/notification/NotificationChannelLoggerImpl.java b/services/core/java/com/android/server/notification/NotificationChannelLoggerImpl.java
index fd3dd56..5a7bc48 100644
--- a/services/core/java/com/android/server/notification/NotificationChannelLoggerImpl.java
+++ b/services/core/java/com/android/server/notification/NotificationChannelLoggerImpl.java
@@ -41,7 +41,12 @@
/* String package_name */ pkg,
/* int32 channel_id_hash */ NotificationChannelLogger.getIdHash(channel),
/* int old_importance*/ oldImportance,
- /* int importance*/ newImportance);
+ /* int importance*/ newImportance,
+ /* bool is_conversation */ channel.isConversation(),
+ /* int32 conversation_id_hash */
+ NotificationChannelLogger.getConversationIdHash(channel),
+ /* bool is_conversation_demoted */ channel.isDemoted(),
+ /* bool is_conversation_priority */ channel.isImportantConversation());
}
@Override
@@ -53,7 +58,11 @@
/* String package_name */ pkg,
/* int32 channel_id_hash */ NotificationChannelLogger.getIdHash(channelGroup),
/* int old_importance*/ NotificationChannelLogger.getImportance(wasBlocked),
- /* int importance*/ NotificationChannelLogger.getImportance(channelGroup));
+ /* int importance*/ NotificationChannelLogger.getImportance(channelGroup),
+ /* bool is_conversation */ false,
+ /* int32 conversation_id_hash */ 0,
+ /* bool is_conversation_demoted */ false,
+ /* bool is_conversation_priority */ false);
}
@Override
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 4f4f3c6..1516cde 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3526,6 +3526,20 @@
}
@Override
+ public void unlockNotificationChannel(String pkg, int uid, String channelId) {
+ checkCallerIsSystemOrSystemUiOrShell("Caller not system or sysui or shell");
+ mPreferencesHelper.unlockNotificationChannelImportance(pkg, uid, channelId);
+ handleSavePolicyFile();
+ }
+
+ @Override
+ public void unlockAllNotificationChannels() {
+ checkCallerIsSystem();
+ mPreferencesHelper.unlockAllNotificationChannels();
+ handleSavePolicyFile();
+ }
+
+ @Override
public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
int uid, boolean includeDeleted) {
enforceSystemOrSystemUI("getNotificationChannelsForPackage");
@@ -5498,6 +5512,8 @@
pw.println(" mCallState=" + callStateToString(mCallState));
pw.println(" mSystemReady=" + mSystemReady);
pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
+ pw.println(" hideSilentStatusBar="
+ + mPreferencesHelper.shouldHideSilentStatusIcons());
}
pw.println(" mArchive=" + mArchive.toString());
Iterator<Pair<StatusBarNotification, Integer>> iter = mArchive.descendingIterator();
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 77713a6..2f990c6 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -18,6 +18,7 @@
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
import static android.app.NotificationChannel.PLACEHOLDER_CONVERSATION_ID;
+import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
import static android.app.NotificationManager.IMPORTANCE_NONE;
@@ -955,6 +956,23 @@
channel.unlockFields(channel.getUserLockedFields());
}
+ void unlockNotificationChannelImportance(String pkg, int uid, String updatedChannelId) {
+ Objects.requireNonNull(updatedChannelId);
+ synchronized (mPackagePreferences) {
+ PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
+ if (r == null) {
+ throw new IllegalArgumentException("Invalid package");
+ }
+
+ NotificationChannel channel = r.channels.get(updatedChannelId);
+ if (channel == null || channel.isDeleted()) {
+ throw new IllegalArgumentException("Channel does not exist");
+ }
+ channel.unlockFields(USER_LOCKED_IMPORTANCE);
+ }
+ }
+
+
@Override
public void updateNotificationChannel(String pkg, int uid, NotificationChannel updatedChannel,
boolean fromUser) {
@@ -2389,6 +2407,18 @@
return mBadgingEnabled.get(userId, DEFAULT_SHOW_BADGE);
}
+ public void unlockAllNotificationChannels() {
+ synchronized (mPackagePreferences) {
+ final int numPackagePreferences = mPackagePreferences.size();
+ for (int i = 0; i < numPackagePreferences; i++) {
+ final PackagePreferences r = mPackagePreferences.valueAt(i);
+ for (NotificationChannel channel : r.channels.values()) {
+ channel.unlockFields(USER_LOCKED_IMPORTANCE);
+ }
+ }
+ }
+ }
+
private void updateConfig() {
mRankingHandler.requestSort();
}
diff --git a/services/core/java/com/android/server/pm/IncrementalStates.java b/services/core/java/com/android/server/pm/IncrementalStates.java
index 72803ac..780c522 100644
--- a/services/core/java/com/android/server/pm/IncrementalStates.java
+++ b/services/core/java/com/android/server/pm/IncrementalStates.java
@@ -101,21 +101,18 @@
if (DEBUG) {
Slog.i(TAG, "received package commit event");
}
+ final boolean startableStateChanged;
synchronized (mLock) {
- if (!mStartableState.isStartable()) {
- mStartableState.adoptNewStartableStateLocked(true);
- }
+ startableStateChanged = mStartableState.adoptNewStartableStateLocked(true);
if (!isIncremental) {
updateProgressLocked(1);
}
}
- mHandler.post(PooledLambda.obtainRunnable(
- IncrementalStates::reportStartableState,
- IncrementalStates.this).recycleOnUse());
+ if (startableStateChanged) {
+ onStartableStateChanged();
+ }
if (!isIncremental) {
- mHandler.post(PooledLambda.obtainRunnable(
- IncrementalStates::reportFullyLoaded,
- IncrementalStates.this).recycleOnUse());
+ onLoadingStateChanged();
}
}
@@ -131,8 +128,7 @@
synchronized (mLock) {
if (mStartableState.isStartable() && mLoadingState.isLoading()) {
// Changing from startable -> unstartable only if app is still loading.
- mStartableState.adoptNewStartableStateLocked(false);
- startableStateChanged = true;
+ startableStateChanged = mStartableState.adoptNewStartableStateLocked(false);
} else {
// If the app is fully loaded, the crash or ANR is caused by the app itself, so
// we do not change the startable state.
@@ -140,12 +136,15 @@
}
}
if (startableStateChanged) {
- mHandler.post(PooledLambda.obtainRunnable(
- IncrementalStates::reportStartableState,
- IncrementalStates.this).recycleOnUse());
+ onStartableStateChanged();
}
}
+ private void onStartableStateChanged() {
+ // Disable startable state broadcasts
+ // TODO(b/171920377): completely remove unstartable state.
+ }
+
private void reportStartableState() {
final Callback callback;
final boolean startable;
@@ -165,6 +164,12 @@
}
}
+ private void onLoadingStateChanged() {
+ mHandler.post(PooledLambda.obtainRunnable(
+ IncrementalStates::reportFullyLoaded,
+ IncrementalStates.this).recycleOnUse());
+ }
+
private void reportFullyLoaded() {
final Callback callback;
synchronized (mLock) {
@@ -178,23 +183,20 @@
private class StatusConsumer implements Consumer<Integer> {
@Override
public void accept(Integer storageStatus) {
- final boolean oldState, newState;
+ final boolean startableStateChanged;
synchronized (mLock) {
if (!mLoadingState.isLoading()) {
// Do nothing if the package is already fully loaded
return;
}
- oldState = mStartableState.isStartable();
mStorageHealthStatus = storageStatus;
- updateStartableStateLocked();
- newState = mStartableState.isStartable();
+ startableStateChanged = updateStartableStateLocked();
}
- if (oldState != newState) {
- mHandler.post(PooledLambda.obtainRunnable(IncrementalStates::reportStartableState,
- IncrementalStates.this).recycleOnUse());
+ if (startableStateChanged) {
+ onStartableStateChanged();
}
}
- };
+ }
/**
* By calling this method, the caller indicates that there issues with the Incremental
@@ -239,14 +241,10 @@
newStartableState = mStartableState.isStartable();
}
if (!newLoadingState) {
- mHandler.post(PooledLambda.obtainRunnable(
- IncrementalStates::reportFullyLoaded,
- IncrementalStates.this).recycleOnUse());
+ onLoadingStateChanged();
}
if (newStartableState != oldStartableState) {
- mHandler.post(PooledLambda.obtainRunnable(
- IncrementalStates::reportStartableState,
- IncrementalStates.this).recycleOnUse());
+ onStartableStateChanged();
}
}
@@ -284,8 +282,9 @@
* health
* status. If the next state is different from the current state, proceed with state
* change.
+ * @return True if the new startable state is different from the old one.
*/
- private void updateStartableStateLocked() {
+ private boolean updateStartableStateLocked() {
final boolean currentState = mStartableState.isStartable();
boolean nextState = currentState;
if (!currentState) {
@@ -302,9 +301,9 @@
}
}
if (nextState == currentState) {
- return;
+ return false;
}
- mStartableState.adoptNewStartableStateLocked(nextState);
+ return mStartableState.adoptNewStartableStateLocked(nextState);
}
private void updateProgressLocked(float progress) {
@@ -343,12 +342,30 @@
return mUnstartableReason;
}
- public void adoptNewStartableStateLocked(boolean nextState) {
+ /**
+ * Adopt new startable state if it is different from the current state.
+ * @param nextState True if startable, false if unstartable.
+ * @return True if the state has changed, false otherwise.
+ */
+ public boolean adoptNewStartableStateLocked(boolean nextState) {
+ if (mIsStartable == nextState) {
+ return false;
+ }
+ if (!nextState) {
+ // Do nothing if the next state is "unstartable"; keep package always startable.
+ // TODO(b/171920377): completely remove unstartable state.
+ if (DEBUG) {
+ Slog.i(TAG, "Attempting to set startable state to false. Abort.");
+ }
+ return false;
+ }
if (DEBUG) {
- Slog.i(TAG, "startable state changed from " + mIsStartable + " to " + nextState);
+ Slog.i(TAG,
+ "startable state changed from " + mIsStartable + " to " + nextState);
}
mIsStartable = nextState;
mUnstartableReason = getUnstartableReasonLocked();
+ return true;
}
private int getUnstartableReasonLocked() {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 5d2928e..57b80ea 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -3058,6 +3058,31 @@
}
}
+ /**
+ * Cleans up the relevant stored files and information of all child sessions.
+ * <p>Cleaning up the stored files and session information is necessary for
+ * preventing the orphan children sessions.
+ * <ol>
+ * <li>To call {@link #destroyInternal()} cleans up the stored files.</li>
+ * <li>To call {@link #dispatchSessionFinished(int, String, Bundle)} to trigger the
+ * procedure to clean up the information in PackageInstallerService.</li>
+ * </ol></p>
+ */
+ private void maybeCleanUpChildSessions() {
+ if (!isMultiPackage()) {
+ return;
+ }
+
+ final List<PackageInstallerSession> childSessions = getChildSessions();
+ final int size = childSessions.size();
+ for (int i = 0; i < size; ++i) {
+ final PackageInstallerSession session = childSessions.get(i);
+ session.destroyInternal();
+ session.dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned"
+ + " because the parent session is abandoned", null);
+ }
+ }
+
private void abandonNonStaged() {
synchronized (mLock) {
assertCallerIsOwnerOrRootLocked();
@@ -3068,6 +3093,7 @@
destroyInternal();
}
dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
+ maybeCleanUpChildSessions();
}
private void abandonStaged() {
@@ -3092,6 +3118,7 @@
cleanStageDir(childSessions);
destroyInternal();
dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
+ maybeCleanUpChildSessions();
};
if (mInPreRebootVerification) {
// Pre-reboot verification is ongoing. It is not safe to clean up the session yet.
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 925d3cc..203321e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -545,7 +545,6 @@
static final int SCAN_AS_SYSTEM_EXT = 1 << 21;
static final int SCAN_AS_ODM = 1 << 22;
static final int SCAN_AS_APK_IN_APEX = 1 << 23;
- static final int SCAN_EXPECTED_BETTER = 1 << 24;
@IntDef(flag = true, prefix = { "SCAN_" }, value = {
SCAN_NO_DEX,
@@ -805,12 +804,11 @@
final SparseIntArray mIsolatedOwners = new SparseIntArray();
/**
- * Tracks packages that we expect to find updated versions of on disk.
- * Keys are package name, values are package location and package version code.
- *
- * @see #expectBetter(String, File, long)
+ * Tracks new system packages [received in an OTA] that we expect to
+ * find updated user-installed versions. Keys are package name, values
+ * are package location.
*/
- private final ArrayMap<String, List<Pair<File, Long>>> mExpectingBetter = new ArrayMap<>();
+ final private ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
/**
* Tracks existing packages prior to receiving an OTA. Keys are package name.
@@ -3351,7 +3349,7 @@
+ ", versionCode=" + ps.versionCode
+ "; scanned versionCode=" + scannedPkg.getLongVersionCode());
removePackageLI(scannedPkg, true);
- expectBetter(ps.name, ps.getPath(), ps.versionCode);
+ mExpectingBetter.put(ps.name, ps.getPath());
}
continue;
@@ -3381,8 +3379,7 @@
// We're expecting that the system app should remain disabled, but add
// it to expecting better to recover in case the data version cannot
// be scanned.
- expectBetter(disabledPs.name, disabledPs.getPath(),
- disabledPs.versionCode);
+ mExpectingBetter.put(disabledPs.name, disabledPs.getPath());
}
}
}
@@ -3483,48 +3480,38 @@
for (int i = 0; i < mExpectingBetter.size(); i++) {
final String packageName = mExpectingBetter.keyAt(i);
if (!mPackages.containsKey(packageName)) {
+ final File scanFile = mExpectingBetter.valueAt(i);
+
logCriticalInfo(Log.WARN, "Expected better " + packageName
+ " but never showed up; reverting to system");
- final List<Pair<File, Long>> scanFiles = mExpectingBetter.valueAt(i);
- // Sort ascending and iterate backwards to take highest version code
- Collections.sort(scanFiles,
- (first, second) -> Long.compare(first.second, second.second));
- for (int index = scanFiles.size() - 1; index >= 0; index--) {
- File scanFile = scanFiles.get(index).first;
-
- @ParseFlags int reparseFlags = 0;
- @ScanFlags int rescanFlags = 0;
- for (int i1 = mDirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
- final ScanPartition partition = mDirsToScanAsSystem.get(i1);
- if (partition.containsPrivApp(scanFile)) {
- reparseFlags = systemParseFlags;
- rescanFlags = systemScanFlags | SCAN_AS_PRIVILEGED
- | partition.scanFlag;
- break;
- }
- if (partition.containsApp(scanFile)) {
- reparseFlags = systemParseFlags;
- rescanFlags = systemScanFlags | partition.scanFlag;
- break;
- }
- }
- if (rescanFlags == 0) {
- Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
- continue;
- }
- mSettings.enableSystemPackageLPw(packageName);
-
- rescanFlags |= SCAN_EXPECTED_BETTER;
-
- try {
- scanPackageTracedLI(scanFile, reparseFlags, rescanFlags, 0, null);
- // Take first success and break out of for loop
+ @ParseFlags int reparseFlags = 0;
+ @ScanFlags int rescanFlags = 0;
+ for (int i1 = mDirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
+ final ScanPartition partition = mDirsToScanAsSystem.get(i1);
+ if (partition.containsPrivApp(scanFile)) {
+ reparseFlags = systemParseFlags;
+ rescanFlags = systemScanFlags | SCAN_AS_PRIVILEGED
+ | partition.scanFlag;
break;
- } catch (PackageManagerException e) {
- Slog.e(TAG, "Failed to parse original system package: "
- + e.getMessage());
}
+ if (partition.containsApp(scanFile)) {
+ reparseFlags = systemParseFlags;
+ rescanFlags = systemScanFlags | partition.scanFlag;
+ break;
+ }
+ }
+ if (rescanFlags == 0) {
+ Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
+ continue;
+ }
+ mSettings.enableSystemPackageLPw(packageName);
+
+ try {
+ scanPackageTracedLI(scanFile, reparseFlags, rescanFlags, 0, null);
+ } catch (PackageManagerException e) {
+ Slog.e(TAG, "Failed to parse original system package: "
+ + e.getMessage());
}
}
}
@@ -3914,33 +3901,6 @@
}
/**
- * Mark a package as skipped during initial scan, expecting a more up to date version to be
- * available on the scan of a higher priority partition. This can be either a system partition
- * or the data partition.
- *
- * If for some reason that newer version cannot be scanned successfully, the data structure
- * created here will be used to backtrack in the scanning process to try and take the highest
- * version code of the package left on disk that scans successfully.
- *
- * This can occur if an OTA adds a new system package which the user has already installed an
- * update on data for. Or if the device image includes multiple versions of the same package,
- * for cases where the maintainer of a higher priority partition wants to update an app on
- * a lower priority partition before shipping a device to users.
- *
- * @param pkgName the package name identifier to queue under
- * @param codePath the path to re-scan if needed
- * @param knownVersionCode the version of the package so that the set of files can be sorted
- */
- private void expectBetter(String pkgName, File codePath, long knownVersionCode) {
- List<Pair<File, Long>> pairs = mExpectingBetter.get(pkgName);
- if (pairs == null) {
- pairs = new ArrayList<>(0);
- mExpectingBetter.put(pkgName, pairs);
- }
- pairs.add(Pair.create(codePath, knownVersionCode));
- }
-
- /**
* Extract, install and enable a stub package.
* <p>If the compressed file can not be extracted / installed for any reason, the stub
* APK will be installed and the package will be disabled. To recover from this situation,
@@ -11311,23 +11271,7 @@
isUpdatedSystemApp = disabledPkgSetting != null;
}
applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage, isUpdatedSystemApp);
- try {
- assertPackageIsValid(parsedPackage, pkgSetting, parseFlags, scanFlags);
- } catch (PackageManagerException e) {
- if (e.error == INSTALL_FAILED_VERSION_DOWNGRADE
- && ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0)
- && ((scanFlags & SCAN_BOOTING) != 0)) {
- if (pkgSetting != null && pkgSetting.getPkg() == null) {
- // If a package for the pkgSetting hasn't already been found, this is
- // skipping a downgrade on a lower priority partition, and so a later scan
- // is expected to fill the package.
- expectBetter(pkgSetting.name, new File(parsedPackage.getPath()),
- parsedPackage.getLongVersionCode());
- }
- }
-
- throw e;
- }
+ assertPackageIsValid(parsedPackage, parseFlags, scanFlags);
SharedUserSetting sharedUserSetting = null;
if (parsedPackage.getSharedUserId() != null) {
@@ -12179,9 +12123,9 @@
*
* @throws PackageManagerException If the package fails any of the validation checks
*/
- private void assertPackageIsValid(AndroidPackage pkg,
- @Nullable PackageSetting existingPkgSetting, final @ParseFlags int parseFlags,
- final @ScanFlags int scanFlags) throws PackageManagerException {
+ private void assertPackageIsValid(AndroidPackage pkg, final @ParseFlags int parseFlags,
+ final @ScanFlags int scanFlags)
+ throws PackageManagerException {
if ((parseFlags & PackageParser.PARSE_ENFORCE_CODE) != 0) {
assertCodePolicy(pkg);
}
@@ -12196,11 +12140,11 @@
// after OTA.
final boolean isUserInstall = (scanFlags & SCAN_BOOTING) == 0;
final boolean isFirstBootOrUpgrade = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0;
- String pkgName = pkg.getPackageName();
if ((isUserInstall || isFirstBootOrUpgrade)
- && mApexManager.isApexPackage(pkgName)) {
+ && mApexManager.isApexPackage(pkg.getPackageName())) {
throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
- pkgName + " is an APEX package and can't be installed as an APK.");
+ pkg.getPackageName()
+ + " is an APEX package and can't be installed as an APK.");
}
// Make sure we're not adding any bogus keyset info
@@ -12209,7 +12153,7 @@
synchronized (mLock) {
// The special "android" package can only be defined once
- if (pkgName.equals("android")) {
+ if (pkg.getPackageName().equals("android")) {
if (mAndroidApplication != null) {
Slog.w(TAG, "*************************************************");
Slog.w(TAG, "Core android package being redefined. Skipping.");
@@ -12220,46 +12164,12 @@
}
}
- final long newLongVersionCode = pkg.getLongVersionCode();
- if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
- boolean runDuplicateCheck = false;
-
- // It's possible to re-scan a package if an updated system app was expected, but
- // no update on /data could be found. To avoid infinitely looping, a flag is passed
- // in when re-scanning and this first branch is skipped if the flag is set.
- if ((scanFlags & SCAN_EXPECTED_BETTER) == 0 && existingPkgSetting != null) {
- long existingLongVersionCode = existingPkgSetting.versionCode;
- if (newLongVersionCode <= existingLongVersionCode) {
- // Must check that real name is equivalent, as it's possible to downgrade
- // version code if the package is actually a different package taking over
- // a package name through <original-package/>. It is assumed that this
- // migration is one time, one way, and that there is no failsafe if this
- // doesn't hold true.
- if (Objects.equals(existingPkgSetting.realName, pkg.getRealPackage())) {
- if (newLongVersionCode != existingLongVersionCode) {
- throw new PackageManagerException(
- INSTALL_FAILED_VERSION_DOWNGRADE,
- "Ignoring lower version " + newLongVersionCode
- + " for package " + pkgName
- + " with expected version "
- + existingLongVersionCode);
- }
- }
- } else if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0
- && (scanFlags & SCAN_BOOTING) != 0) {
- // During system boot scan, if there's already a package known, but this
- // package is higher version, use it instead, ignoring the duplicate check.
- // This will store the higher version in the setting object, and the above
- // branch/exception will cause future scans to skip the lower versions.
- runDuplicateCheck = false;
- }
- }
-
- if (runDuplicateCheck && mPackages.containsKey(pkgName)) {
- throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
- "Application package " + pkgName
- + " already installed. Skipping duplicate.");
- }
+ // A package name must be unique; don't allow duplicates
+ if ((scanFlags & SCAN_NEW_INSTALL) == 0
+ && mPackages.containsKey(pkg.getPackageName())) {
+ throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
+ "Application package " + pkg.getPackageName()
+ + " already installed. Skipping duplicate.");
}
if (pkg.isStaticSharedLibrary()) {
@@ -12379,8 +12289,8 @@
}
}
}
- if (newLongVersionCode < minVersionCode
- || newLongVersionCode > maxVersionCode) {
+ if (pkg.getLongVersionCode() < minVersionCode
+ || pkg.getLongVersionCode() > maxVersionCode) {
throw new PackageManagerException("Static shared"
+ " lib version codes must be ordered as lib versions");
}
@@ -12395,10 +12305,11 @@
// to the user-installed location. If we don't allow this change, any newer,
// user-installed version of the application will be ignored.
if ((scanFlags & SCAN_REQUIRE_KNOWN) != 0) {
- if (mExpectingBetter.containsKey(pkgName)) {
- Slog.w(TAG, "Relax SCAN_REQUIRE_KNOWN requirement for package " + pkgName);
+ if (mExpectingBetter.containsKey(pkg.getPackageName())) {
+ Slog.w(TAG, "Relax SCAN_REQUIRE_KNOWN requirement for package "
+ + pkg.getPackageName());
} else {
- PackageSetting known = mSettings.getPackageLPr(pkgName);
+ PackageSetting known = mSettings.getPackageLPr(pkg.getPackageName());
if (known != null) {
if (DEBUG_PACKAGE_SCANNING) {
Log.d(TAG, "Examining " + pkg.getPath()
@@ -12406,14 +12317,14 @@
}
if (!pkg.getPath().equals(known.getPathString())) {
throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
- "Application package " + pkgName
+ "Application package " + pkg.getPackageName()
+ " found at " + pkg.getPath()
+ " but expected at " + known.getPathString()
+ "; ignoring.");
}
} else {
throw new PackageManagerException(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
- "Application package " + pkgName
+ "Application package " + pkg.getPackageName()
+ " not found; ignoring.");
}
}
@@ -12436,7 +12347,7 @@
INSTALL_FAILED_PROCESS_NOT_DEFINED,
"Can't install because application tag's process attribute "
+ pkg.getProcessName()
- + " (in package " + pkgName
+ + " (in package " + pkg.getPackageName()
+ ") is not included in the <processes> list");
}
assertPackageProcesses(pkg, pkg.getActivities(), procs, "activity");
@@ -12460,7 +12371,7 @@
pkg.getSigningDetails().signatures)) {
throw new PackageManagerException("Apps that share a user with a " +
"privileged app must themselves be marked as privileged. " +
- pkgName + " shares privileged user " +
+ pkg.getPackageName() + " shares privileged user " +
pkg.getSharedUserId() + ".");
}
}
@@ -12477,21 +12388,21 @@
// upgraded.
Objects.requireNonNull(mOverlayConfig,
"Parsing non-system dir before overlay configs are initialized");
- if (!mOverlayConfig.isMutable(pkgName)) {
+ if (!mOverlayConfig.isMutable(pkg.getPackageName())) {
throw new PackageManagerException("Overlay "
- + pkgName
+ + pkg.getPackageName()
+ " is static and cannot be upgraded.");
}
} else {
if ((scanFlags & SCAN_AS_VENDOR) != 0) {
if (pkg.getTargetSdkVersion() < getVendorPartitionVersion()) {
- Slog.w(TAG, "System overlay " + pkgName
+ Slog.w(TAG, "System overlay " + pkg.getPackageName()
+ " targets an SDK below the required SDK level of vendor"
+ " overlays (" + getVendorPartitionVersion() + ")."
+ " This will become an install error in a future release");
}
} else if (pkg.getTargetSdkVersion() < Build.VERSION.SDK_INT) {
- Slog.w(TAG, "System overlay " + pkgName
+ Slog.w(TAG, "System overlay " + pkg.getPackageName()
+ " targets an SDK below the required SDK level of system"
+ " overlays (" + Build.VERSION.SDK_INT + ")."
+ " This will become an install error in a future release");
@@ -12507,7 +12418,7 @@
if (!comparePackageSignatures(platformPkgSetting,
pkg.getSigningDetails().signatures)) {
throw new PackageManagerException("Overlay "
- + pkgName
+ + pkg.getPackageName()
+ " must target Q or later, "
+ "or be signed with the platform certificate");
}
@@ -12529,7 +12440,7 @@
// check reference signature
if (mOverlayConfigSignaturePackage == null) {
throw new PackageManagerException("Overlay "
- + pkgName + " and target "
+ + pkg.getPackageName() + " and target "
+ pkg.getOverlayTarget() + " signed with"
+ " different certificates, and the overlay lacks"
+ " <overlay android:targetName>");
@@ -12539,7 +12450,7 @@
if (!comparePackageSignatures(refPkgSetting,
pkg.getSigningDetails().signatures)) {
throw new PackageManagerException("Overlay "
- + pkgName + " signed with a different "
+ + pkg.getPackageName() + " signed with a different "
+ "certificate than both the reference package and "
+ "target " + pkg.getOverlayTarget() + ", and the "
+ "overlay lacks <overlay android:targetName>");
@@ -12559,7 +12470,7 @@
if (pkg.getSigningDetails().signatureSchemeVersion < minSignatureSchemeVersion) {
throw new PackageManagerException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No signature found in package of version " + minSignatureSchemeVersion
- + " or newer for package " + pkgName);
+ + " or newer for package " + pkg.getPackageName());
}
}
}
@@ -16567,8 +16478,8 @@
healthCheckParams.unhealthyTimeoutMs = INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS;
healthCheckParams.unhealthyMonitoringMs =
INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS;
- mIncrementalManager.registerHealthListener(codePath,
- new StorageHealthCheckParams(), incrementalHealthListener);
+ mIncrementalManager.registerHealthListener(codePath, healthCheckParams,
+ incrementalHealthListener);
}
// Ensure that the uninstall reason is UNKNOWN for users with the package installed.
@@ -19694,8 +19605,6 @@
if (installed) {
ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, userId);
}
-
- writeRuntimePermissionsForUserLPrTEMP(userId, false);
}
// Regardless of writeSettings we need to ensure that this restriction
// state propagation is persisted
@@ -25840,8 +25749,9 @@
@Override
public void writePermissionSettings(int[] userIds, boolean async) {
synchronized (mLock) {
+ mPermissionManager.writeLegacyPermissionStateTEMP();
for (int userId : userIds) {
- writeRuntimePermissionsForUserLPrTEMP(userId, !async);
+ mSettings.writeRuntimePermissionsForUserLPr(userId, !async);
}
}
}
@@ -26490,17 +26400,6 @@
mSettings.writeLPr();
}
- /**
- * Temporary method that wraps mSettings.writeRuntimePermissionsForUserLPr() and calls
- * mPermissionManager.writeLegacyPermissionStateTEMP() beforehand.
- *
- * TODO(zhanghai): This should be removed once we finish migration of permission storage.
- */
- private void writeRuntimePermissionsForUserLPrTEMP(@UserIdInt int userId, boolean async) {
- mPermissionManager.writeLegacyPermissionStateTEMP();
- mSettings.writeRuntimePermissionsForUserLPr(userId, async);
- }
-
@Override
public IBinder getHoldLockToken() {
if (!Build.IS_DEBUGGABLE) {
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index e99e301..3fcf02c 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -674,20 +674,6 @@
return;
}
- if ((session.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
- // If rollback is available for this session, notify the rollback
- // manager of the apk session so it can properly enable rollback.
- final RollbackManagerInternal rm =
- LocalServices.getService(RollbackManagerInternal.class);
- try {
- // TODO(b/136257624): extra apk session id in rollback is now redundant.
- rm.notifyStagedApkSession(session.sessionId, session.sessionId);
- } catch (RuntimeException re) {
- Slog.e(TAG, "Failed to notifyStagedApkSession for session: "
- + session.sessionId, re);
- }
- }
-
final LocalIntentReceiverSync receiver = new LocalIntentReceiverSync();
session.installStagedSession(receiver.getIntentSender());
final Intent result = receiver.getResult();
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 7f29cd9..24082b8 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -3993,7 +3993,7 @@
@Override
public @UserManager.RemoveResult int removeUserOrSetEphemeral(@UserIdInt int userId) {
Slog.i(LOG_TAG, "removeUserOrSetEphemeral u" + userId);
- checkManageUsersPermission("Only the system can remove users");
+ checkManageOrCreateUsersPermission("Only the system can remove users");
final String restriction = getUserRemovalRestriction(userId);
if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(restriction, false)) {
Slog.w(LOG_TAG, "Cannot remove user. " + restriction + " is enabled.");
diff --git a/services/core/java/com/android/server/pm/parsing/PackageCacher.java b/services/core/java/com/android/server/pm/parsing/PackageCacher.java
index 3463daf..74ec161 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageCacher.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageCacher.java
@@ -57,16 +57,7 @@
* Returns the cache key for a specified {@code packageFile} and {@code flags}.
*/
private String getCacheKey(File packageFile, int flags) {
- StringBuilder sb = new StringBuilder();
-
- // To support packages with the same file name across partitions, use the partition name
- // as a prefix. The cache should only be used for cases where the file paths have been
- // established using the unique partition names, without canonicalization, so any links
- // which would point to the same partition name should be handled separately.
- String cachePrefix = packageFile.toPath().getName(0).toString();
- sb.append(cachePrefix);
- sb.append('-');
- sb.append(packageFile.getName());
+ StringBuilder sb = new StringBuilder(packageFile.getName());
sb.append('-');
sb.append(flags);
diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
index 46d31d9..851ddd1 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -135,7 +135,7 @@
}
/**
- * TODO(b/155493909): Document new package parsing
+ * TODO(b/135203078): Document new package parsing
*/
@AnyThread
public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 1ae430a..bf5a50e 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -1272,7 +1272,12 @@
newFlags |= (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT);
// If we are allowlisting the permission, update the exempt flag before grant.
- if (whitelistRestrictedPermissions && pm.isPermissionRestricted(permission)) {
+ // If the permission can't be allowlisted by an installer, skip it here because
+ // this is where the platform takes the role of the installer for exempting
+ // preinstalled apps.
+ if (whitelistRestrictedPermissions && pm.isPermissionRestricted(permission)
+ && !pm.getPermissionInfo(permission).isInstallerExemptIgnored()) {
+
pm.updatePermissionFlags(permission, pkg,
PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT,
PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT, user);
diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java
index 4e8ddac..0245b28 100644
--- a/services/core/java/com/android/server/pm/permission/Permission.java
+++ b/services/core/java/com/android/server/pm/permission/Permission.java
@@ -425,7 +425,7 @@
permission = new Permission(permissionInfo.name, permissionInfo.packageName,
TYPE_MANIFEST);
}
- boolean wasNormal = permission.isNormal();
+ boolean wasNonRuntime = !permission.isRuntime();
StringBuilder r = null;
if (!permission.mReconciled) {
if (permission.mPermissionInfo.packageName == null
@@ -465,8 +465,8 @@
r.append("DUP:");
r.append(permissionInfo.name);
}
- if (permission.isRuntime() && (ownerChanged || wasNormal)) {
- // If this is a runtime permission and the owner has changed, or this was a normal
+ if (permission.isRuntime() && (ownerChanged || wasNonRuntime)) {
+ // If this is a runtime permission and the owner has changed, or this wasn't a runtime
// permission, then permission state should be cleaned up
permission.mDefinitionChanged = true;
}
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 84f9823..ff661a8 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -70,11 +70,16 @@
import android.app.IActivityManager;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
+import android.app.role.RoleManager;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.PermissionChecker;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.PermissionGroupInfoFlags;
import android.content.pm.PackageManager.PermissionInfoFlags;
@@ -84,6 +89,7 @@
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
+import android.content.pm.UserInfo;
import android.content.pm.parsing.component.ParsedPermission;
import android.content.pm.parsing.component.ParsedPermissionGroup;
import android.content.pm.permission.SplitPermissionInfoParcelable;
@@ -177,6 +183,7 @@
*/
public class PermissionManagerService extends IPermissionManager.Stub {
private static final String TAG = "PackageManager";
+ private static final String LOG_TAG = PermissionManagerService.class.getSimpleName();
private static final long BACKUP_TIMEOUT_MILLIS = SECONDS.toMillis(60);
@@ -417,6 +424,105 @@
new PermissionManagerServiceInternalImpl();
LocalServices.addService(PermissionManagerServiceInternal.class, localService);
LocalServices.addService(PermissionManagerInternal.class, localService);
+
+ context.getMainThreadHandler().post(() -> context.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
+ return;
+ }
+
+ try {
+ fixBgMicCamera(context);
+ } catch (Throwable t) {
+ // Don't crash the system if this fails for any reason. Any intermediate state
+ // this can leave the permissions in is okay and in the worst case the state is
+ // the same as before the user rebooted.
+ Log.e(LOG_TAG, "Unable to fix background permissions", t);
+ }
+ }
+
+
+ private void fixBgMicCamera(Context context) {
+ PackageManager pm = context.getPackageManager();
+ for (UserInfo userInfo : context.getSystemService(UserManager.class).getUsers()) {
+ UserHandle user = userInfo.getUserHandle();
+ List<String> assistants = context.getSystemService(RoleManager.class)
+ .getRoleHoldersAsUser(RoleManager.ROLE_ASSISTANT, user);
+ List<PackageInfo> packages =
+ pm.getInstalledPackagesAsUser(PackageManager.MATCH_SYSTEM_ONLY
+ | PackageManager.GET_PERMISSIONS, user.getIdentifier());
+ for (PackageInfo packageInfo : packages) {
+ String[] requestedPermissions = packageInfo.requestedPermissions;
+ if (requestedPermissions == null) {
+ continue;
+ }
+ for (String permName : requestedPermissions) {
+ String pkg = packageInfo.packageName;
+ switch (permName) {
+ case Manifest.permission.BACKGROUND_CAMERA:
+ removeFromAllowlistsAndRevoke(pm, pkg, permName, user);
+ break;
+ case Manifest.permission.RECORD_BACKGROUND_AUDIO:
+ if (assistants.contains(pkg)) {
+ removeFromAllowlistsAndRevokeForAssistant(pm, pkg, permName,
+ user);
+ } else {
+ removeFromAllowlistsAndRevoke(pm, pkg, permName, user);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ private void removeFromAllowlistsAndRevoke(PackageManager pm, String pkg,
+ String permName, UserHandle user) {
+ if ((pm.getPermissionFlags(permName, pkg, user)
+ & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0) {
+ Slog.i(LOG_TAG, "removing " + pkg + " " + permName + " from all allowlists");
+ pm.removeWhitelistedRestrictedPermission(pkg, permName,
+ FLAG_PERMISSION_WHITELIST_UPGRADE);
+ pm.removeWhitelistedRestrictedPermission(pkg, permName,
+ FLAG_PERMISSION_WHITELIST_SYSTEM);
+ pm.removeWhitelistedRestrictedPermission(pkg, permName,
+ FLAG_PERMISSION_WHITELIST_INSTALLER);
+ pm.removeWhitelistedRestrictedPermission(pkg, permName,
+ FLAG_PERMISSION_ALLOWLIST_ROLE);
+ }
+ if (pm.checkPermission(permName, pkg) == PackageManager.PERMISSION_GRANTED) {
+ Slog.i(LOG_TAG, "revoking " + pkg + " " + permName);
+ pm.revokeRuntimePermission(pkg, permName, user);
+ }
+ }
+
+ private void removeFromAllowlistsAndRevokeForAssistant(PackageManager pm, String pkg,
+ String permName, UserHandle user) {
+ int anyNonRoleExempt =
+ FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT
+ | FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT
+ | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+
+ if ((pm.getPermissionFlags(permName, pkg, user) & anyNonRoleExempt) != 0) {
+ Slog.i(LOG_TAG, "removing " + pkg + " " + permName
+ + " from all allowlists except role");
+ pm.removeWhitelistedRestrictedPermission(pkg, permName,
+ FLAG_PERMISSION_WHITELIST_UPGRADE);
+ pm.removeWhitelistedRestrictedPermission(pkg, permName,
+ FLAG_PERMISSION_WHITELIST_SYSTEM);
+ pm.removeWhitelistedRestrictedPermission(pkg, permName,
+ FLAG_PERMISSION_WHITELIST_INSTALLER);
+ }
+ if ((pm.getPermissionFlags(permName, pkg, user)
+ & FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT) == 0) {
+ Slog.i(LOG_TAG, "adding " + pkg + " " + permName
+ + " to role allowlist");
+ pm.addWhitelistedRestrictedPermission(pkg, permName,
+ FLAG_PERMISSION_ALLOWLIST_ROLE);
+ }
+ }
+ }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)));
}
@Override
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 8b677a9..fcba5ce 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2429,6 +2429,15 @@
wm = (WindowManager) context.getSystemService(WINDOW_SERVICE);
view = win.getDecorView();
+ // Ignore to show splash screen if the decorView is not opaque.
+ if (!view.isOpaque()) {
+ if (DEBUG_SPLASH_SCREEN) {
+ Slog.d(TAG, "addSplashScreen: the view of " + packageName
+ + " is not opaque, cancel it");
+ }
+ return null;
+ }
+
if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "Adding splash screen window for "
+ packageName + " / " + appToken + ": " + (view.getParent() != null ? view : null));
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index 2db6043..2d51cf9 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -146,11 +146,6 @@
private @RollbackState int mState;
/**
- * The id of the post-reboot apk session for a staged install, if any.
- */
- private int mApkSessionId = -1;
-
- /**
* True if we are expecting the package manager to call restoreUserData
* for this rollback because it has just been committed but the rollback
* has not yet been fully applied.
@@ -236,7 +231,7 @@
* Constructs a pre-populated Rollback instance.
*/
Rollback(RollbackInfo info, File backupDir, Instant timestamp, int stagedSessionId,
- @RollbackState int state, int apkSessionId, boolean restoreUserDataInProgress,
+ @RollbackState int state, boolean restoreUserDataInProgress,
int userId, String installerPackageName, SparseIntArray extensionVersions) {
this.info = info;
mUserId = userId;
@@ -245,7 +240,6 @@
mTimestamp = timestamp;
mStagedSessionId = stagedSessionId;
mState = state;
- mApkSessionId = apkSessionId;
mRestoreUserDataInProgress = restoreUserDataInProgress;
mExtensionVersions = Objects.requireNonNull(extensionVersions);
// TODO(b/120200473): Include this field during persistence. This field will be used to
@@ -727,25 +721,6 @@
}
/**
- * Returns the id of the post-reboot apk session for a staged install, if any.
- */
- @WorkerThread
- int getApkSessionId() {
- assertInWorkerThread();
- return mApkSessionId;
- }
-
- /**
- * Sets the id of the post-reboot apk session for a staged install.
- */
- @WorkerThread
- void setApkSessionId(int apkSessionId) {
- assertInWorkerThread();
- mApkSessionId = apkSessionId;
- RollbackStore.saveRollback(this);
- }
-
- /**
* Returns true if we are expecting the package manager to call restoreUserData for this
* rollback because it has just been committed but the rollback has not yet been fully applied.
*/
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerInternal.java b/services/core/java/com/android/server/rollback/RollbackManagerInternal.java
index b473b8c..dbda4a8 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerInternal.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerInternal.java
@@ -53,13 +53,4 @@
* @return The rollback id if rollback was enabled successfully, or -1 if not.
*/
int notifyStagedSession(int sessionId);
-
- /**
- * Used by the staging manager to notify the RollbackManager of the apk
- * session for a staged session.
- *
- * @param originalSessionId The original session ID where this apk session belongs
- * @param apkSessionId The ID of this apk session
- */
- void notifyStagedApkSession(int originalSessionId, int apkSessionId);
}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 1e89e06..b34d46f 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -28,6 +28,7 @@
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ModuleInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
@@ -53,7 +54,6 @@
import android.os.UserManager;
import android.os.ext.SdkExtensions;
import android.provider.DeviceConfig;
-import android.util.IntArray;
import android.util.Log;
import android.util.LongArrayQueue;
import android.util.Slog;
@@ -151,10 +151,6 @@
// Accessed on the handler thread only.
private final List<Rollback> mRollbacks = new ArrayList<>();
- // Apk sessions from a staged session with no matching rollback.
- // Accessed on the handler thread only.
- private final IntArray mOrphanedApkSessionIds = new IntArray();
-
private final RollbackStore mRollbackStore;
private final Context mContext;
@@ -646,8 +642,6 @@
onPackageReplaced(apexPackageName);
}
- mOrphanedApkSessionIds.clear();
-
mPackageHealthObserver.onBootCompletedAsync();
});
}
@@ -782,25 +776,6 @@
return false;
}
- // Check to see if this is the apk session for a staged session with
- // rollback enabled.
- for (int i = 0; i < mRollbacks.size(); ++i) {
- Rollback rollback = mRollbacks.get(i);
- if (rollback.getApkSessionId() == parentSession.getSessionId()) {
- // This is the apk session for a staged session with rollback enabled. We do
- // not need to create a new rollback for this session.
- return true;
- }
- }
-
- // Check to see if this is the apk session for a staged session for which rollback was
- // cancelled.
- if (mOrphanedApkSessionIds.indexOf(parentSession.getSessionId()) != -1) {
- Slog.w(TAG, "Not enabling rollback for apk as no matching staged session "
- + "rollback exists");
- return false;
- }
-
// See if we already have a Rollback that contains this package
// session. If not, create a new Rollback for the parent session
// that we will use for all the packages in the session.
@@ -1038,37 +1013,6 @@
});
}
- @ExtThread
- @Override
- public void notifyStagedApkSession(int originalSessionId, int apkSessionId) {
- assertNotInWorkerThread();
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("notifyStagedApkSession may only be called by the system.");
- }
- getHandler().post(() -> {
- assertInWorkerThread();
- Rollback rollback = null;
- for (int i = 0; i < mRollbacks.size(); ++i) {
- Rollback candidate = mRollbacks.get(i);
- if (candidate.getStagedSessionId() == originalSessionId) {
- rollback = candidate;
- break;
- }
- }
- if (rollback == null) {
- // Did not find rollback matching originalSessionId.
- Slog.e(TAG, "notifyStagedApkSession did not find rollback for session "
- + originalSessionId
- + ". Adding orphaned apk session " + apkSessionId);
- mOrphanedApkSessionIds.add(apkSessionId);
- }
-
- if (rollback != null) {
- rollback.setApkSessionId(apkSessionId);
- }
- });
- }
-
/**
* Returns true if the installer is allowed to enable rollback for the
* given named package, false otherwise.
@@ -1088,8 +1032,8 @@
Manifest.permission.TEST_MANAGE_ROLLBACKS,
installerPackageName) == PackageManager.PERMISSION_GRANTED;
- // For now only allow rollbacks for allowlisted packages or for testing.
- return (isRollbackAllowlisted(packageName) && manageRollbacksGranted)
+ // For now only allow rollbacks for modules, allowlisted packages, or for testing.
+ return (isRollbackAllowed(packageName) && manageRollbacksGranted)
|| testManageRollbacksGranted;
}
@@ -1097,8 +1041,24 @@
* Returns true is this package is eligible for enabling rollback.
*/
@AnyThread
- private boolean isRollbackAllowlisted(String packageName) {
- return SystemConfig.getInstance().getRollbackWhitelistedPackages().contains(packageName);
+ private boolean isRollbackAllowed(String packageName) {
+ return SystemConfig.getInstance().getRollbackWhitelistedPackages().contains(packageName)
+ || isModule(packageName);
+ }
+ /**
+ * Returns true if the package name is the name of a module.
+ */
+ @AnyThread
+ private boolean isModule(String packageName) {
+ PackageManager pm = mContext.getPackageManager();
+ final ModuleInfo moduleInfo;
+ try {
+ moduleInfo = pm.getModuleInfo(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+
+ return moduleInfo != null;
}
/**
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index 44a6336..2ee87e6 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -267,7 +267,6 @@
dataJson.put("timestamp", rollback.getTimestamp().toString());
dataJson.put("stagedSessionId", rollback.getStagedSessionId());
dataJson.put("state", rollback.getStateAsString());
- dataJson.put("apkSessionId", rollback.getApkSessionId());
dataJson.put("restoreUserDataInProgress", rollback.isRestoreUserDataInProgress());
dataJson.put("userId", rollback.getUserId());
dataJson.putOpt("installerPackageName", rollback.getInstallerPackageName());
@@ -319,7 +318,6 @@
Instant.parse(dataJson.getString("timestamp")),
dataJson.getInt("stagedSessionId"),
rollbackStateFromString(dataJson.getString("state")),
- dataJson.getInt("apkSessionId"),
dataJson.getBoolean("restoreUserDataInProgress"),
dataJson.optInt("userId", UserHandle.SYSTEM.getIdentifier()),
dataJson.optString("installerPackageName", ""),
diff --git a/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java b/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java
index e72c185..f9ef994 100644
--- a/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java
+++ b/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java
@@ -36,6 +36,7 @@
import android.content.pm.VersionedPackage;
import android.content.rollback.PackageRollbackInfo;
import android.content.rollback.RollbackInfo;
+import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Slog;
@@ -216,6 +217,34 @@
failingPackageName,
new byte[]{});
}
+
+ logTestProperties(logPackage, type, rollbackReason, failingPackageName);
+ }
+
+ /**
+ * Writes properties which will be used by rollback tests to check if particular rollback
+ * events have occurred.
+ *
+ * persist.sys.rollbacktest.enabled: true if rollback tests are running
+ * persist.sys.rollbacktest.EVENT_TYPE: true if a particular rollback event has occurred
+ * ex: persist.sys.rollbacktest.ROLLBACK_INITIATE is true if ROLLBACK_INITIATE has happened
+ * persist.sys.rollbacktest.EVENT_TYPE.logPackage: the package to associate the rollback with
+ * persist.sys.rollbacktest.EVENT_TYPE.rollbackReason: the reason Watchdog triggered a rollback
+ * persist.sys.rollbacktest.EVENT_TYPE.failedPackageName: the failing package or process which
+ * triggered the rollback
+ */
+ private static void logTestProperties(@Nullable VersionedPackage logPackage, int type,
+ int rollbackReason, @NonNull String failingPackageName) {
+ // This property should be on only during the tests
+ final String prefix = "persist.sys.rollbacktest.";
+ if (!SystemProperties.getBoolean(prefix + "enabled", false)) {
+ return;
+ }
+ String key = prefix + rollbackTypeToString(type);
+ SystemProperties.set(key, String.valueOf(true));
+ SystemProperties.set(key + ".logPackage", logPackage != null ? logPackage.toString() : "");
+ SystemProperties.set(key + ".rollbackReason", rollbackReasonToString(rollbackReason));
+ SystemProperties.set(key + ".failedPackageName", failingPackageName);
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/utils/Watchable.java b/services/core/java/com/android/server/utils/Watchable.java
new file mode 100644
index 0000000..7c99274
--- /dev/null
+++ b/services/core/java/com/android/server/utils/Watchable.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.utils;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/**
+ * Notify registered {@link Watcher}s when the content changes.
+ */
+public interface Watchable {
+
+ /**
+ * Ensures an observer is in the list, exactly once. The observer cannot be null. The
+ * function quietly returns if the observer is already in the list.
+ *
+ * @param observer The {@link Watcher} to be notified when the {@link Watchable} changes.
+ */
+ public void registerObserver(@NonNull Watcher observer);
+
+ /**
+ * Ensures an observer is not in the list. The observer must not be null. The function
+ * quietly returns if the objserver is not in the list.
+ *
+ * @param observer The {@link Watcher} that should not be in the notification list.
+ */
+ public void unregisterObserver(@NonNull Watcher observer);
+
+ /**
+ * Invokes {@link Watcher#onChange} on each registered observer. The method can be called
+ * with the {@link Watchable} that generated the event. In a tree of {@link Watchable}s, this
+ * is generally the first (deepest) {@link Watchable} to detect a change.
+ *
+ * @param what The {@link Watchable} that generated the event.
+ */
+ public void dispatchChange(@Nullable Watchable what);
+}
diff --git a/services/core/java/com/android/server/utils/WatchableImpl.java b/services/core/java/com/android/server/utils/WatchableImpl.java
new file mode 100644
index 0000000..94ab1d4
--- /dev/null
+++ b/services/core/java/com/android/server/utils/WatchableImpl.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.utils;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+/**
+ * A concrete implementation of {@link Watchable}
+ */
+public class WatchableImpl implements Watchable {
+ /**
+ * The list of observers.
+ */
+ protected final ArrayList<Watcher> mObservers = new ArrayList<>();
+
+ /**
+ * Ensure the observer is the list. The observer cannot be null but it is okay if it
+ * is already in the list.
+ *
+ * @param observer The {@link} Watcher to be added to the notification list.
+ */
+ @Override
+ public void registerObserver(@NonNull Watcher observer) {
+ Objects.requireNonNull(observer, "observer may not be null");
+ synchronized (mObservers) {
+ if (!mObservers.contains(observer)) {
+ mObservers.add(observer);
+ }
+ }
+ }
+
+ /**
+ * Removes a previously registered observer. The observer must not be null and it
+ * must already have been registered.
+ *
+ * @param observer The {@link} Watcher to be removed from the notification list.
+ */
+ @Override
+ public void unregisterObserver(@NonNull Watcher observer) {
+ Objects.requireNonNull(observer, "observer may not be null");
+ synchronized (mObservers) {
+ mObservers.remove(observer);
+ }
+ }
+
+ /**
+ * Return the number of registered observers.
+ *
+ * @return The number of registered observers.
+ */
+ public int registeredObserverCount() {
+ return mObservers.size();
+ }
+
+ /**
+ * Invokes {@link Watcher#onChange} on each observer.
+ *
+ * @param what The {@link Watchable} that generated the event
+ */
+ @Override
+ public void dispatchChange(@Nullable Watchable what) {
+ synchronized (mObservers) {
+ final int end = mObservers.size();
+ for (int i = 0; i < end; i++) {
+ mObservers.get(i).onChange(what);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/utils/WatchedArrayMap.java b/services/core/java/com/android/server/utils/WatchedArrayMap.java
new file mode 100644
index 0000000..7b32980
--- /dev/null
+++ b/services/core/java/com/android/server/utils/WatchedArrayMap.java
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.utils;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import android.util.ArrayMap;
+import android.util.Log;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * WatchedArrayMap is an {@link android.util.ArrayMap} that can report changes to itself. If its
+ * values are {@link Watchable} then the WatchedArrayMap will also report changes to the values.
+ * A {@link Watchable} is notified only once, no matter how many times it is stored in the array.
+ */
+public class WatchedArrayMap<K, V> extends WatchableImpl implements Map<K, V> {
+
+ // The storage
+ private final ArrayMap<K, V> mStorage;
+
+ // If true, the array is watching its children
+ private boolean mWatching = false;
+
+ // The local observer
+ private final Watcher mObserver = new Watcher() {
+ @Override
+ public void onChange(@Nullable Watchable what) {
+ WatchedArrayMap.this.dispatchChange(what);
+ }
+ };
+
+ /**
+ * A convenience function called when the elements are added to or removed from the storage.
+ * The watchable is always {@link this}.
+ */
+ private void onChanged() {
+ dispatchChange(this);
+ }
+
+ /**
+ * A convenience function. Register the object if it is {@link Watchable} and if the
+ * array is currently watching. Note that the watching flag must be true if this
+ * function is to succeed. Also note that if this is called with the same object
+ * twice, <this> is only registered once.
+ */
+ private void registerChild(Object o) {
+ if (mWatching && o instanceof Watchable) {
+ ((Watchable) o).registerObserver(mObserver);
+ }
+ }
+
+ /**
+ * A convenience function. Unregister the object if it is {@link Watchable} and if the
+ * array is currently watching. This unconditionally removes the object from the
+ * registered list.
+ */
+ private void unregisterChild(Object o) {
+ if (mWatching && o instanceof Watchable) {
+ ((Watchable) o).unregisterObserver(mObserver);
+ }
+ }
+
+ /**
+ * A convenience function. Unregister the object if it is {@link Watchable}, if the
+ * array is currently watching, and if there are no other instances of this object in
+ * the storage. Note that the watching flag must be true if this function is to
+ * succeed. The object must already have been removed from the storage before this
+ * method is called.
+ */
+ private void unregisterChildIf(Object o) {
+ if (mWatching && o instanceof Watchable) {
+ if (!mStorage.containsValue(o)) {
+ ((Watchable) o).unregisterObserver(mObserver);
+ }
+ }
+ }
+
+ /**
+ * Register a {@link Watcher} with the array. If this is the first Watcher than any
+ * array values that are {@link Watchable} are registered to the array itself.
+ */
+ @Override
+ public void registerObserver(@NonNull Watcher observer) {
+ super.registerObserver(observer);
+ if (registeredObserverCount() == 1) {
+ // The watching flag must be set true before any children are registered.
+ mWatching = true;
+ final int end = mStorage.size();
+ for (int i = 0; i < end; i++) {
+ registerChild(mStorage.valueAt(i));
+ }
+ }
+ }
+
+ /**
+ * Unregister a {@link Watcher} from the array. If this is the last Watcher than any
+ * array values that are {@link Watchable} are unregistered to the array itself.
+ */
+ @Override
+ public void unregisterObserver(@NonNull Watcher observer) {
+ super.unregisterObserver(observer);
+ if (registeredObserverCount() == 0) {
+ final int end = mStorage.size();
+ for (int i = 0; i < end; i++) {
+ unregisterChild(mStorage.valueAt(i));
+ }
+ // The watching flag must be true while children are unregistered.
+ mWatching = false;
+ }
+ }
+
+ /**
+ * Create a new empty {@link WatchedArrayMap}. The default capacity of an array map
+ * is 0, and will grow once items are added to it.
+ */
+ public WatchedArrayMap() {
+ this(0, false);
+ }
+
+ /**
+ * Create a new {@link WatchedArrayMap} with a given initial capacity.
+ */
+ public WatchedArrayMap(int capacity) {
+ this(capacity, false);
+ }
+
+ /** {@hide} */
+ public WatchedArrayMap(int capacity, boolean identityHashCode) {
+ mStorage = new ArrayMap<K, V>(capacity, identityHashCode);
+ }
+
+ /**
+ * Create a new {@link WatchedArrayMap} with the mappings from the given {@link Map}.
+ */
+ public WatchedArrayMap(@Nullable Map<? extends K, ? extends V> map) {
+ mStorage = new ArrayMap<K, V>();
+ if (map != null) {
+ putAll(map);
+ }
+ }
+
+ /**
+ * Return the underlying storage. This breaks the wrapper but is necessary when
+ * passing the array to distant methods.
+ */
+ public ArrayMap untrackedMap() {
+ return mStorage;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void clear() {
+ // The storage cannot be simply cleared. Each element in the storage must be
+ // unregistered. Deregistration is only needed if the array is actually
+ // watching.
+ if (mWatching) {
+ final int end = mStorage.size();
+ for (int i = 0; i < end; i++) {
+ unregisterChild(mStorage.valueAt(i));
+ }
+ }
+ mStorage.clear();
+ onChanged();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean containsKey(Object key) {
+ return mStorage.containsKey(key);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean containsValue(Object value) {
+ return mStorage.containsValue(value);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Set<Map.Entry<K, V>> entrySet() {
+ return Collections.unmodifiableSet(mStorage.entrySet());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof WatchedArrayMap) {
+ WatchedArrayMap w = (WatchedArrayMap) o;
+ return mStorage.equals(w.mStorage);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public V get(Object key) {
+ return mStorage.get(key);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return mStorage.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isEmpty() {
+ return mStorage.isEmpty();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Set<K> keySet() {
+ return Collections.unmodifiableSet(mStorage.keySet());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public V put(K key, V value) {
+ final V result = mStorage.put(key, value);
+ registerChild(value);
+ onChanged();
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void putAll(@NonNull Map<? extends K, ? extends V> map) {
+ for (Map.Entry<? extends K, ? extends V> element : map.entrySet()) {
+ put(element.getKey(), element.getValue());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public V remove(@NonNull Object key) {
+ final V result = mStorage.remove(key);
+ unregisterChildIf(result);
+ onChanged();
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int size() {
+ return mStorage.size();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<V> values() {
+ return Collections.unmodifiableCollection(mStorage.values());
+ }
+
+ // Methods supported by ArrayMap that are not part of Map
+
+ /**
+ * Return the key at the given index in the array.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, an
+ * {@link ArrayIndexOutOfBoundsException} is thrown.</p>
+ *
+ * @param index The desired index, must be between 0 and {@link #size()}-1.
+ * @return Returns the key stored at the given index.
+ */
+ public K keyAt(int index) {
+ return mStorage.keyAt(index);
+ }
+
+ /**
+ * Return the value at the given index in the array.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, an
+ * {@link ArrayIndexOutOfBoundsException} is thrown.</p>
+ *
+ * @param index The desired index, must be between 0 and {@link #size()}-1.
+ * @return Returns the value stored at the given index.
+ */
+ public V valueAt(int index) {
+ return mStorage.valueAt(index);
+ }
+
+ /**
+ * Remove an existing key from the array map.
+ * @param key The key of the mapping to remove.
+ * @return Returns the value that was stored under the key, or null if there
+ * was no such key.
+ */
+ public int indexOfKey(K key) {
+ return mStorage.indexOfKey(key);
+ }
+
+ /**
+ * Returns an index for which {@link #valueAt} would return the
+ * specified value, or a negative number if no keys map to the
+ * specified value.
+ * Beware that this is a linear search, unlike lookups by key,
+ * and that multiple keys can map to the same value and this will
+ * find only one of them.
+ */
+ public int indexOfValue(V value) {
+ return mStorage.indexOfValue(value);
+ }
+
+ /**
+ * Set the value at a given index in the array.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, an
+ * {@link ArrayIndexOutOfBoundsException} is thrown.</p>
+ *
+ * @param index The desired index, must be between 0 and {@link #size()}-1.
+ * @param value The new value to store at this index.
+ * @return Returns the previous value at the given index.
+ */
+ public V setValueAt(int index, V value) {
+ final V result = mStorage.setValueAt(index, value);
+ if (value != result) {
+ unregisterChildIf(result);
+ registerChild(value);
+ onChanged();
+ }
+ return result;
+ }
+
+ /**
+ * Remove the key/value mapping at the given index.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, an
+ * {@link ArrayIndexOutOfBoundsException} is thrown.</p>
+ *
+ * @param index The desired index, must be between 0 and {@link #size()}-1.
+ * @return Returns the value that was stored at this index.
+ */
+ public V removeAt(int index) {
+ final V result = mStorage.removeAt(index);
+ unregisterChildIf(result);
+ onChanged();
+ return result;
+ }
+}
diff --git a/services/core/java/com/android/server/utils/WatchedSparseArray.java b/services/core/java/com/android/server/utils/WatchedSparseArray.java
new file mode 100644
index 0000000..4d43b68
--- /dev/null
+++ b/services/core/java/com/android/server/utils/WatchedSparseArray.java
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.utils;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import android.util.SparseArray;
+
+import java.util.ArrayList;
+
+/**
+ * A watched variant of SparseArray. If a {@link Watchable} is stored in the array, the
+ * array registers with the {@link Watchable}. The array registers only once with each
+ * {@link Watchable} no matter how many times the {@link Watchable} is stored in the
+ * array.
+ */
+public class WatchedSparseArray<E> extends WatchableImpl {
+
+ // The storage
+ private final SparseArray<E> mStorage;
+
+ // If true, the array is watching its children
+ private boolean mWatching = false;
+
+ // The local observer
+ private final Watcher mObserver = new Watcher() {
+ @Override
+ public void onChange(@Nullable Watchable o) {
+ WatchedSparseArray.this.dispatchChange(o);
+ }
+ };
+
+ /**
+ * A private convenience function that notifies registered listeners that an element
+ * has been added to or removed from the array. The what parameter is the array itself.
+ */
+ private void onChanged() {
+ dispatchChange(this);
+ }
+
+ /**
+ * A convenience function. Register the object if it is {@link Watchable} and if the
+ * array is currently watching. Note that the watching flag must be true if this
+ * function is to succeed.
+ */
+ private void registerChild(Object o) {
+ if (mWatching && o instanceof Watchable) {
+ ((Watchable) o).registerObserver(mObserver);
+ }
+ }
+
+ /**
+ * A convenience function. Unregister the object if it is {@link Watchable} and if
+ * the array is currently watching. Note that the watching flag must be true if this
+ * function is to succeed.
+ */
+ private void unregisterChild(Object o) {
+ if (mWatching && o instanceof Watchable) {
+ ((Watchable) o).unregisterObserver(mObserver);
+ }
+ }
+
+ /**
+ * A convenience function. Unregister the object if it is {@link Watchable}, if the array is
+ * currently watching, and if the storage does not contain the object. Note that the watching
+ * flag must be true if this function is to succeed. This must be called after an object has
+ * been removed from the storage.
+ */
+ private void unregisterChildIf(Object o) {
+ if (mWatching && o instanceof Watchable) {
+ if (mStorage.indexOfValue((E) o) == -1) {
+ ((Watchable) o).unregisterObserver(mObserver);
+ }
+ }
+ }
+
+ /**
+ * Register a {@link Watcher} with the array. If this is the first Watcher than any
+ * array values that are {@link Watchable} are registered to the array itself.
+ */
+ @Override
+ public void registerObserver(@NonNull Watcher observer) {
+ super.registerObserver(observer);
+ if (registeredObserverCount() == 1) {
+ // The watching flag must be set true before any children are registered.
+ mWatching = true;
+ final int end = mStorage.size();
+ for (int i = 0; i < end; i++) {
+ registerChild(mStorage.valueAt(i));
+ }
+ }
+ }
+
+ /**
+ * Unregister a {@link Watcher} from the array. If this is the last Watcher than any
+ * array values that are {@link Watchable} are unregistered to the array itself.
+ */
+ @Override
+ public void unregisterObserver(@NonNull Watcher observer) {
+ super.unregisterObserver(observer);
+ if (registeredObserverCount() == 0) {
+ final int end = mStorage.size();
+ for (int i = 0; i < end; i++) {
+ unregisterChild(mStorage.valueAt(i));
+ }
+ // The watching flag must be true while children are unregistered.
+ mWatching = false;
+ }
+ }
+
+ /**
+ * Creates a new WatchedSparseArray containing no mappings.
+ */
+ public WatchedSparseArray() {
+ mStorage = new SparseArray();
+ }
+
+ /**
+ * Creates a new WatchedSparseArray containing no mappings that
+ * will not require any additional memory allocation to store the
+ * specified number of mappings. If you supply an initial capacity of
+ * 0, the sparse array will be initialized with a light-weight
+ * representation not requiring any additional array allocations.
+ */
+ public WatchedSparseArray(int initialCapacity) {
+ mStorage = new SparseArray(initialCapacity);
+ }
+
+ /**
+ * The copy constructor does not copy the watcher data.
+ */
+ public WatchedSparseArray(@NonNull WatchedSparseArray<E> r) {
+ mStorage = r.mStorage.clone();
+ }
+
+ /**
+ * Returns true if the key exists in the array. This is equivalent to
+ * {@link #indexOfKey(int)} >= 0.
+ *
+ * @param key Potential key in the mapping
+ * @return true if the key is defined in the mapping
+ */
+ public boolean contains(int key) {
+ return mStorage.contains(key);
+ }
+
+ /**
+ * Gets the Object mapped from the specified key, or <code>null</code>
+ * if no such mapping has been made.
+ */
+ public E get(int key) {
+ return mStorage.get(key);
+ }
+
+ /**
+ * Gets the Object mapped from the specified key, or the specified Object
+ * if no such mapping has been made.
+ */
+ public E get(int key, E valueIfKeyNotFound) {
+ return mStorage.get(key, valueIfKeyNotFound);
+ }
+
+ /**
+ * Removes the mapping from the specified key, if there was any.
+ */
+ public void delete(int key) {
+ final E child = mStorage.get(key);
+ mStorage.delete(key);
+ unregisterChildIf(child);
+ onChanged();
+ }
+
+ /**
+ * @hide
+ * Removes the mapping from the specified key, if there was any, returning the old value.
+ */
+ public E removeReturnOld(int key) {
+ final E result = mStorage.removeReturnOld(key);
+ unregisterChildIf(result);
+ return result;
+ }
+
+ /**
+ * Alias for {@link #delete(int)}.
+ */
+ public void remove(int key) {
+ delete(key);
+ }
+
+ /**
+ * Removes the mapping at the specified index.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, an
+ * {@link ArrayIndexOutOfBoundsException} is thrown.</p>
+ */
+ public void removeAt(int index) {
+ final E child = mStorage.valueAt(index);
+ mStorage.removeAt(index);
+ unregisterChildIf(child);
+ onChanged();
+ }
+
+ /**
+ * Remove a range of mappings as a batch.
+ *
+ * @param index Index to begin at
+ * @param size Number of mappings to remove
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>,
+ * the behavior is undefined.</p>
+ */
+ public void removeAtRange(int index, int size) {
+ final ArrayList<E> children = new ArrayList<>();
+ try {
+ for (int i = 0; i < size; i++) {
+ children.add(mStorage.valueAt(i + index));
+ }
+ } catch (Exception e) {
+ // Ignore any exception and proceed with removal.
+ }
+ try {
+ mStorage.removeAtRange(index, size);
+ } finally {
+ // Even on exception, make sure to deregister children that have been
+ // removed.
+ for (int i = 0; i < size; i++) {
+ unregisterChildIf(children.get(i));
+ }
+ }
+ onChanged();
+ }
+
+ /**
+ * Adds a mapping from the specified key to the specified value,
+ * replacing the previous mapping from the specified key if there
+ * was one.
+ */
+ public void put(int key, E value) {
+ final E old = mStorage.get(key);
+ mStorage.put(key, value);
+ unregisterChildIf(old);
+ registerChild(value);
+ onChanged();
+ }
+
+ /**
+ * Returns the number of key-value mappings that this SparseArray
+ * currently stores.
+ */
+ public int size() {
+ return mStorage.size();
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the key from the <code>index</code>th key-value mapping that this
+ * SparseArray stores.
+ *
+ * <p>The keys corresponding to indices in ascending order are guaranteed to
+ * be in ascending order, e.g., <code>keyAt(0)</code> will return the
+ * smallest key and <code>keyAt(size()-1)</code> will return the largest
+ * key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>,
+ * the behavior is undefined for apps targeting {@link android.os.Build.VERSION_CODES#P} and
+ * earlier, and an {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ */
+ public int keyAt(int index) {
+ return mStorage.keyAt(index);
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the value from the <code>index</code>th key-value mapping that this
+ * SparseArray stores.
+ *
+ * <p>The values corresponding to indices in ascending order are guaranteed
+ * to be associated with keys in ascending order, e.g.,
+ * <code>valueAt(0)</code> will return the value associated with the
+ * smallest key and <code>valueAt(size()-1)</code> will return the value
+ * associated with the largest key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>,
+ * the behavior is undefined for apps targeting {@link android.os.Build.VERSION_CODES#P} and
+ * earlier, and an {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ */
+ public E valueAt(int index) {
+ return mStorage.valueAt(index);
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, sets a new
+ * value for the <code>index</code>th key-value mapping that this
+ * SparseArray stores.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ */
+ public void setValueAt(int index, E value) {
+ final E old = mStorage.valueAt(index);
+ mStorage.setValueAt(index, value);
+ if (value != old) {
+ unregisterChildIf(old);
+ registerChild(value);
+ onChanged();
+ }
+ }
+
+ /**
+ * Returns the index for which {@link #keyAt} would return the
+ * specified key, or a negative number if the specified
+ * key is not mapped.
+ */
+ public int indexOfKey(int key) {
+ return mStorage.indexOfKey(key);
+ }
+
+ /**
+ * Returns an index for which {@link #valueAt} would return the
+ * specified value, or a negative number if no keys map to the
+ * specified value.
+ * <p>Beware that this is a linear search, unlike lookups by key,
+ * and that multiple keys can map to the same value and this will
+ * find only one of them.
+ * <p>Note also that unlike most collections' {@code indexOf} methods,
+ * this method compares values using {@code ==} rather than {@code equals}.
+ */
+ public int indexOfValue(E value) {
+ return mStorage.indexOfValue(value);
+ }
+
+ /**
+ * Returns an index for which {@link #valueAt} would return the
+ * specified value, or a negative number if no keys map to the
+ * specified value.
+ * <p>Beware that this is a linear search, unlike lookups by key,
+ * and that multiple keys can map to the same value and this will
+ * find only one of them.
+ * <p>Note also that this method uses {@code equals} unlike {@code indexOfValue}.
+ * @hide
+ */
+ public int indexOfValueByValue(E value) {
+ return mStorage.indexOfValueByValue(value);
+ }
+
+ /**
+ * Removes all key-value mappings from this SparseArray.
+ */
+ public void clear() {
+ // The storage cannot be simply cleared. Each element in the storage must be
+ // unregistered. Deregistration is only needed if the array is actually
+ // watching.
+ if (mWatching) {
+ final int end = mStorage.size();
+ for (int i = 0; i < end; i++) {
+ unregisterChild(mStorage.valueAt(i));
+ }
+ }
+ mStorage.clear();
+ onChanged();
+ }
+
+ /**
+ * Puts a key/value pair into the array, optimizing for the case where
+ * the key is greater than all existing keys in the array.
+ */
+ public void append(int key, E value) {
+ mStorage.append(key, value);
+ registerChild(value);
+ onChanged();
+ }
+
+ /**
+ * <p>This implementation composes a string by iterating over its mappings. If
+ * this map contains itself as a value, the string "(this Map)"
+ * will appear in its place.
+ */
+ @Override
+ public String toString() {
+ return mStorage.toString();
+ }
+}
diff --git a/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java b/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java
new file mode 100644
index 0000000..edf7d27
--- /dev/null
+++ b/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.utils;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import android.util.SparseBooleanArray;
+
+/**
+ * A watched variant of SparseBooleanArray. Changes to the array are notified to
+ * registered {@link Watcher}s.
+ */
+public class WatchedSparseBooleanArray extends WatchableImpl {
+
+ // The storage
+ private final SparseBooleanArray mStorage;
+
+ // A private convenience function
+ private void dispatchChange() {
+ dispatchChange(this);
+ }
+
+ /**
+ * Creates a new WatchedSparseBooleanArray containing no mappings.
+ */
+ public WatchedSparseBooleanArray() {
+ mStorage = new SparseBooleanArray();
+ }
+
+ /**
+ * Creates a new WatchedSparseBooleanArray containing no mappings that
+ * will not require any additional memory allocation to store the
+ * specified number of mappings. If you supply an initial capacity of
+ * 0, the sparse array will be initialized with a light-weight
+ * representation not requiring any additional array allocations.
+ */
+ public WatchedSparseBooleanArray(int initialCapacity) {
+ mStorage = new SparseBooleanArray(initialCapacity);
+ }
+
+ /**
+ * The copy constructor does not copy the watcher data.
+ */
+ public WatchedSparseBooleanArray(@NonNull WatchedSparseBooleanArray r) {
+ mStorage = r.mStorage.clone();
+ }
+
+ /**
+ * Gets the boolean mapped from the specified key, or <code>false</code>
+ * if no such mapping has been made.
+ */
+ public boolean get(int key) {
+ return mStorage.get(key);
+ }
+
+ /**
+ * Gets the boolean mapped from the specified key, or the specified value
+ * if no such mapping has been made.
+ */
+ public boolean get(int key, boolean valueIfKeyNotFound) {
+ return mStorage.get(key, valueIfKeyNotFound);
+ }
+
+ /**
+ * Removes the mapping from the specified key, if there was any.
+ */
+ public void delete(int key) {
+ mStorage.delete(key);
+ dispatchChange();
+ }
+
+ /**
+ * Removes the mapping at the specified index.
+ * <p>
+ * For indices outside of the range {@code 0...size()-1}, the behavior is undefined.
+ */
+ public void removeAt(int index) {
+ mStorage.removeAt(index);
+ dispatchChange();
+ }
+
+ /**
+ * Adds a mapping from the specified key to the specified value,
+ * replacing the previous mapping from the specified key if there
+ * was one.
+ */
+ public void put(int key, boolean value) {
+ if (mStorage.get(key) != value) {
+ mStorage.put(key, value);
+ dispatchChange();
+ }
+ }
+
+ /**
+ * Returns the number of key-value mappings that this SparseBooleanArray
+ * currently stores.
+ */
+ public int size() {
+ return mStorage.size();
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the key from the <code>index</code>th key-value mapping that this
+ * SparseBooleanArray stores.
+ *
+ * <p>The keys corresponding to indices in ascending order are guaranteed to
+ * be in ascending order, e.g., <code>keyAt(0)</code> will return the
+ * smallest key and <code>keyAt(size()-1)</code> will return the largest
+ * key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ */
+ public int keyAt(int index) {
+ return mStorage.keyAt(index);
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the value from the <code>index</code>th key-value mapping that this
+ * SparseBooleanArray stores.
+ *
+ * <p>The values corresponding to indices in ascending order are guaranteed
+ * to be associated with keys in ascending order, e.g.,
+ * <code>valueAt(0)</code> will return the value associated with the
+ * smallest key and <code>valueAt(size()-1)</code> will return the value
+ * associated with the largest key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ */
+ public boolean valueAt(int index) {
+ return mStorage.valueAt(index);
+ }
+
+ /**
+ * Directly set the value at a particular index.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ */
+ public void setValueAt(int index, boolean value) {
+ if (mStorage.valueAt(index) != value) {
+ mStorage.setValueAt(index, value);
+ dispatchChange();
+ }
+ }
+
+ /** @hide */
+ public void setKeyAt(int index, int key) {
+ if (mStorage.keyAt(index) != key) {
+ mStorage.setKeyAt(index, key);
+ dispatchChange();
+ }
+ }
+
+ /**
+ * Returns the index for which {@link #keyAt} would return the
+ * specified key, or a negative number if the specified
+ * key is not mapped.
+ */
+ public int indexOfKey(int key) {
+ return mStorage.indexOfKey(key);
+ }
+
+ /**
+ * Returns an index for which {@link #valueAt} would return the
+ * specified key, or a negative number if no keys map to the
+ * specified value.
+ * Beware that this is a linear search, unlike lookups by key,
+ * and that multiple keys can map to the same value and this will
+ * find only one of them.
+ */
+ public int indexOfValue(boolean value) {
+ return mStorage.indexOfValue(value);
+ }
+
+ /**
+ * Removes all key-value mappings from this SparseBooleanArray.
+ */
+ public void clear() {
+ mStorage.clear();
+ dispatchChange();
+ }
+
+ /**
+ * Puts a key/value pair into the array, optimizing for the case where
+ * the key is greater than all existing keys in the array.
+ */
+ public void append(int key, boolean value) {
+ mStorage.append(key, value);
+ dispatchChange();
+ }
+
+ @Override
+ public int hashCode() {
+ return mStorage.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object that) {
+ return this == that || mStorage.equals(that);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation composes a string by iterating over its mappings.
+ */
+ @Override
+ public String toString() {
+ return mStorage.toString();
+ }
+}
diff --git a/services/core/java/com/android/server/utils/Watcher.java b/services/core/java/com/android/server/utils/Watcher.java
new file mode 100644
index 0000000..a9bfbfa
--- /dev/null
+++ b/services/core/java/com/android/server/utils/Watcher.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.utils;
+
+import android.annotation.Nullable;
+
+/**
+ * This class receives notifications when watched objects detect changes.
+ * Must be implemented by objects which are registered to a {@link Watchable}.
+ */
+public abstract class Watcher {
+
+ /**
+ * This method is called when {@link Watchable} detects a change. The <what>
+ * parameter indicates what changed, but it may be null. The parameter is intended
+ * for debugging.
+ *
+ * @param what The {@link Watchable} that changed.
+ */
+ public abstract void onChange(@Nullable Watchable what);
+}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 0a7f08b..19b13c1 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -194,7 +194,7 @@
import static com.android.server.wm.Task.ActivityState.STARTED;
import static com.android.server.wm.Task.ActivityState.STOPPED;
import static com.android.server.wm.Task.ActivityState.STOPPING;
-import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE;
+import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE;
import static com.android.server.wm.TaskPersister.DEBUG;
import static com.android.server.wm.TaskPersister.IMAGE_EXTENSION;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
@@ -417,7 +417,7 @@
// mOccludesParent field.
final boolean hasWallpaper;
// Input application handle used by the input dispatcher.
- final InputApplicationHandle mInputApplicationHandle;
+ private InputApplicationHandle mInputApplicationHandle;
final int launchedFromPid; // always the pid who started the activity.
final int launchedFromUid; // always the uid who started the activity.
@@ -1506,7 +1506,6 @@
info = aInfo;
mUserId = UserHandle.getUserId(info.applicationInfo.uid);
packageName = info.applicationInfo.packageName;
- mInputApplicationHandle = new InputApplicationHandle(appToken);
intent = _intent;
// If the class name in the intent doesn't match that of the target, this is probably an
@@ -1693,6 +1692,21 @@
return lockTaskLaunchMode;
}
+ @NonNull InputApplicationHandle getInputApplicationHandle(boolean update) {
+ if (mInputApplicationHandle == null) {
+ mInputApplicationHandle = new InputApplicationHandle(appToken, toString(),
+ mInputDispatchingTimeoutMillis);
+ } else if (update) {
+ final String name = toString();
+ if (mInputDispatchingTimeoutMillis != mInputApplicationHandle.dispatchingTimeoutMillis
+ || !name.equals(mInputApplicationHandle.name)) {
+ mInputApplicationHandle = new InputApplicationHandle(appToken, name,
+ mInputDispatchingTimeoutMillis);
+ }
+ }
+ return mInputApplicationHandle;
+ }
+
@Override
ActivityRecord asActivityRecord() {
// I am an activity record!
@@ -4489,7 +4503,7 @@
detachChildren();
}
if (app != null) {
- app.invalidateOomScoreReferenceState(false /* computeNow */);
+ app.computeProcessActivityState();
}
switch (state) {
@@ -4881,7 +4895,7 @@
*/
private boolean shouldBeResumed(ActivityRecord activeActivity) {
return shouldMakeActive(activeActivity) && isFocusable()
- && getTask().getVisibility(activeActivity) == STACK_VISIBILITY_VISIBLE
+ && getTask().getVisibility(activeActivity) == TASK_VISIBILITY_VISIBLE
&& canResumeByCompat();
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index a068d2b..17209eb 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -50,12 +50,12 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IDLE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_IDLE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ROOT_TASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
@@ -63,17 +63,17 @@
import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_SUPERVISOR_STACK_MSG;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
-import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
-import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_ALLOWLISTED;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
+import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
+import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.Task.ActivityState.PAUSED;
import static com.android.server.wm.Task.ActivityState.PAUSING;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_ALLOWLISTED;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
-import static com.android.server.wm.Task.REPARENT_KEEP_STACK_AT_FRONT;
+import static com.android.server.wm.Task.REPARENT_KEEP_ROOT_TASK_AT_FRONT;
import static com.android.server.wm.Task.TAG_CLEANUP;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
@@ -158,7 +158,7 @@
private static final String TAG_IDLE = TAG + POSTFIX_IDLE;
private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
- private static final String TAG_STACK = TAG + POSTFIX_STACK;
+ private static final String TAG_ROOT_TASK = TAG + POSTFIX_ROOT_TASK;
private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
static final String TAG_TASKS = TAG + POSTFIX_TASKS;
@@ -526,7 +526,7 @@
int candidateTaskId = nextTaskIdForUser(currentTaskId, userId);
while (mRecentTasks.containsTaskId(candidateTaskId, userId)
|| mRootWindowContainer.anyTaskForId(
- candidateTaskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS) != null) {
+ candidateTaskId, MATCH_ATTACHED_TASK_OR_RECENT_TASKS) != null) {
candidateTaskId = nextTaskIdForUser(candidateTaskId, userId);
if (candidateTaskId == currentTaskId) {
// Something wrong!
@@ -1360,8 +1360,8 @@
if (stack != currentStack) {
moveHomeStackToFrontIfNeeded(flags, stack.getDisplayArea(), reason);
- task.reparent(stack, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE, DEFER_RESUME,
- reason);
+ task.reparent(stack, ON_TOP, REPARENT_KEEP_ROOT_TASK_AT_FRONT, !ANIMATE,
+ DEFER_RESUME, reason);
currentStack = stack;
reparented = true;
// task.reparent() should already placed the task on top,
@@ -1385,7 +1385,7 @@
currentStack.moveTaskToFront(task, false /* noAnimation */, options,
r == null ? null : r.appTimeTracker, reason);
- if (DEBUG_STACK) Slog.d(TAG_STACK,
+ if (DEBUG_ROOT_TASK) Slog.d(TAG_ROOT_TASK,
"findTaskToMoveToFront: moved to front of stack=" + currentStack);
handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED,
@@ -1502,7 +1502,7 @@
boolean removeTaskById(int taskId, boolean killProcess, boolean removeFromRecents,
String reason) {
final Task task =
- mRootWindowContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
+ mRootWindowContainer.anyTaskForId(taskId, MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
if (task != null) {
removeTask(task, killProcess, removeFromRecents, reason);
return true;
@@ -2478,7 +2478,7 @@
mService.deferWindowLayout();
try {
task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, activityOptions, ON_TOP);
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, activityOptions, ON_TOP);
if (task == null) {
mWindowManager.executeAppTransition();
throw new IllegalArgumentException(
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 910a1a2..33819a9 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -75,7 +75,7 @@
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY;
import static com.android.server.wm.Task.ActivityState.RESUMED;
-import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
+import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import android.annotation.NonNull;
@@ -1665,11 +1665,6 @@
final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
? mSourceRecord.getTask() : null;
setNewTask(taskToAffiliate);
- if (mService.getLockTaskController().isLockTaskModeViolation(
- mStartActivity.getTask())) {
- Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
- return START_RETURN_LOCK_TASK_MODE_VIOLATION;
- }
} else if (mAddingToTask) {
addOrReparentStartingActivity(targetTask, "adding to task");
}
@@ -1848,10 +1843,17 @@
final boolean isNewClearTask =
(mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
- if (!newTask && mService.getLockTaskController().isLockTaskModeViolation(targetTask,
- isNewClearTask)) {
- Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
- return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+ if (!newTask) {
+ if (mService.getLockTaskController().isLockTaskModeViolation(targetTask,
+ isNewClearTask)) {
+ Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
+ return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+ }
+ } else {
+ if (mService.getLockTaskController().isNewTaskLockTaskModeViolation(mStartActivity)) {
+ Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
+ return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+ }
}
return START_SUCCESS;
@@ -2530,8 +2532,8 @@
"bringingFoundTaskToFront");
mMovedToFront = !isSplitScreenTopStack;
} else {
- intentTask.reparent(launchStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE,
- DEFER_RESUME, "reparentToTargetStack");
+ intentTask.reparent(launchStack, ON_TOP, REPARENT_MOVE_ROOT_TASK_TO_FRONT,
+ ANIMATE, DEFER_RESUME, "reparentToTargetStack");
mMovedToFront = true;
}
mOptions = null;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java b/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
index b5675a9..33d1b44 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
@@ -45,7 +45,7 @@
static final boolean DEBUG_RECENTS = DEBUG_ALL || false;
static final boolean DEBUG_RECENTS_TRIM_TASKS = DEBUG_RECENTS || false;
- static final boolean DEBUG_STACK = DEBUG_ALL || false;
+ static final boolean DEBUG_ROOT_TASK = DEBUG_ALL || false;
public static final boolean DEBUG_SWITCH = DEBUG_ALL || false;
static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
static final boolean DEBUG_VISIBILITY = DEBUG_ALL || false;
@@ -73,7 +73,7 @@
static final String POSTFIX_PAUSE = APPEND_CATEGORY_NAME ? "_Pause" : "";
static final String POSTFIX_RECENTS = APPEND_CATEGORY_NAME ? "_Recents" : "";
static final String POSTFIX_SAVED_STATE = APPEND_CATEGORY_NAME ? "_SavedState" : "";
- static final String POSTFIX_STACK = APPEND_CATEGORY_NAME ? "_Stack" : "";
+ static final String POSTFIX_ROOT_TASK = APPEND_CATEGORY_NAME ? "_RootTask" : "";
static final String POSTFIX_STATES = APPEND_CATEGORY_NAME ? "_States" : "";
public static final String POSTFIX_SWITCH = APPEND_CATEGORY_NAME ? "_Switch" : "";
static final String POSTFIX_TASKS = APPEND_CATEGORY_NAME ? "_Tasks" : "";
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index eb86d37..f649a2f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -533,9 +533,6 @@
/** Flush recent tasks to disk. */
public abstract void flushRecentTasks();
- public abstract WindowProcessController getHomeProcess();
- public abstract WindowProcessController getPreviousProcess();
-
public abstract void clearLockedTasks(String reason);
public abstract void updateUserConfiguration();
public abstract boolean canShowErrorDialogs();
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 608d373..73c4713 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -106,7 +106,7 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_FOCUS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_IMMERSIVE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ROOT_TASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
@@ -117,14 +117,14 @@
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
import static com.android.server.wm.ActivityTaskManagerService.H.REPORT_TIME_TRACKER_MSG;
import static com.android.server.wm.ActivityTaskManagerService.UiHandler.DISMISS_DIALOG_UI_MSG;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_DONT_LOCK;
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
-import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_ONLY;
-import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
+import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_ONLY;
+import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
import static com.android.server.wm.Task.ActivityState.DESTROYED;
import static com.android.server.wm.Task.ActivityState.DESTROYING;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_DONT_LOCK;
-import static com.android.server.wm.Task.REPARENT_KEEP_STACK_AT_FRONT;
+import static com.android.server.wm.Task.REPARENT_KEEP_ROOT_TASK_AT_FRONT;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
@@ -306,7 +306,7 @@
*/
public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityTaskManagerService" : TAG_ATM;
- static final String TAG_STACK = TAG + POSTFIX_STACK;
+ static final String TAG_ROOT_TASK = TAG + POSTFIX_ROOT_TASK;
static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
private static final String TAG_IMMERSIVE = TAG + POSTFIX_IMMERSIVE;
private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
@@ -2228,7 +2228,7 @@
try {
synchronized (mGlobalLock) {
final Task task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_ONLY);
+ MATCH_ATTACHED_TASK_ONLY);
if (task == null) {
return;
}
@@ -2266,7 +2266,7 @@
final long ident = Binder.clearCallingIdentity();
try {
final Task task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
if (task == null) {
Slog.w(TAG, "removeTask: No task remove with id=" + taskId);
return false;
@@ -2374,7 +2374,7 @@
try {
synchronized (mGlobalLock) {
final Task task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
if (task == null) {
Slog.w(TAG, "getTaskBounds: taskId=" + taskId + " not found");
return rect;
@@ -2397,7 +2397,7 @@
enforceCallerIsRecentsOrHasPermission(
MANAGE_ACTIVITY_TASKS, "getTaskDescription()");
final Task tr = mRootWindowContainer.anyTaskForId(id,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
if (tr != null) {
return tr.getTaskDescription();
}
@@ -2418,7 +2418,7 @@
return setTaskWindowingModeSplitScreen(taskId, windowingMode, toTop);
}
final Task task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_ONLY);
+ MATCH_ATTACHED_TASK_ONLY);
if (task == null) {
Slog.w(TAG, "setTaskWindowingMode: No task for id=" + taskId);
return false;
@@ -2789,8 +2789,8 @@
throw new IllegalArgumentException("moveTaskToRootTask: Attempt to move task "
+ taskId + " to rootTask " + rootTaskId);
}
- task.reparent(rootTask, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME,
- "moveTaskToRootTask");
+ task.reparent(rootTask, toTop, REPARENT_KEEP_ROOT_TASK_AT_FRONT, ANIMATE,
+ !DEFER_RESUME, "moveTaskToRootTask");
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -2834,7 +2834,7 @@
}
final Task task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_ONLY);
+ MATCH_ATTACHED_TASK_ONLY);
if (task == null) {
Slog.w(TAG, "setTaskWindowingModeSplitScreenPrimary: No task for id=" + taskId);
return false;
@@ -3013,7 +3013,7 @@
try {
synchronized (mGlobalLock) {
final Task task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_ONLY);
+ MATCH_ATTACHED_TASK_ONLY);
if (task == null) {
return;
}
@@ -3361,7 +3361,7 @@
public void setTaskResizeable(int taskId, int resizeableMode) {
synchronized (mGlobalLock) {
final Task task = mRootWindowContainer.anyTaskForId(
- taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
+ taskId, MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
if (task == null) {
Slog.w(TAG, "setTaskResizeable: taskId=" + taskId + " not found");
return;
@@ -3377,7 +3377,7 @@
try {
synchronized (mGlobalLock) {
final Task task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_ONLY);
+ MATCH_ATTACHED_TASK_ONLY);
if (task == null) {
Slog.w(TAG, "resizeTask: taskId=" + taskId + " not found");
return false;
@@ -4395,7 +4395,7 @@
try {
synchronized (mGlobalLock) {
final Task task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_ONLY);
+ MATCH_ATTACHED_TASK_ONLY);
if (task == null) {
Slog.w(TAG, "cancelTaskWindowTransition: taskId=" + taskId + " not found");
return;
@@ -4423,7 +4423,7 @@
final Task task;
synchronized (mGlobalLock) {
task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
if (task == null) {
Slog.w(TAG, "getTaskSnapshot: taskId=" + taskId + " not found");
return null;
@@ -7324,20 +7324,6 @@
}
@Override
- public WindowProcessController getHomeProcess() {
- synchronized (mGlobalLock) {
- return mHomeProcess;
- }
- }
-
- @Override
- public WindowProcessController getPreviousProcess() {
- synchronized (mGlobalLock) {
- return mPreviousProcess;
- }
- }
-
- @Override
public void clearLockedTasks(String reason) {
synchronized (mGlobalLock) {
getLockTaskController().clearLockedTasks(reason);
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 3e79879..fbbda59 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -17,7 +17,7 @@
package com.android.server.wm;
import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
-import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
+import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
import android.app.ActivityManager;
import android.app.IAppTask;
@@ -79,7 +79,7 @@
final long origId = Binder.clearCallingIdentity();
try {
Task task = mService.mRootWindowContainer.anyTaskForId(mTaskId,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
if (task == null) {
throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
}
@@ -136,7 +136,7 @@
IApplicationThread appThread;
synchronized (mService.mGlobalLock) {
task = mService.mRootWindowContainer.anyTaskForId(mTaskId,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
if (task == null) {
throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
}
@@ -165,7 +165,7 @@
final long origId = Binder.clearCallingIdentity();
try {
Task task = mService.mRootWindowContainer.anyTaskForId(mTaskId,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
if (task == null) {
throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 6453ddf..3a4eb09 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -88,7 +88,6 @@
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
import static com.android.server.wm.DisplayContentProto.APP_TRANSITION;
import static com.android.server.wm.DisplayContentProto.CAN_SHOW_IME;
import static com.android.server.wm.DisplayContentProto.CLOSING_APPS;
@@ -238,7 +237,6 @@
*/
class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.DisplayContentInfo {
private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayContent" : TAG_WM;
- private static final String TAG_STACK = TAG + POSTFIX_STACK;
/** The default scaling mode that scales content automatically. */
static final int FORCE_SCALING_MODE_AUTO = 0;
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index f647bea..472678c 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -22,184 +22,41 @@
import static com.android.server.wm.DisplayContent.FORCE_SCALING_MODE_AUTO;
import static com.android.server.wm.DisplayContent.FORCE_SCALING_MODE_DISABLED;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WindowConfiguration;
-import android.os.Environment;
-import android.os.FileUtils;
import android.provider.Settings;
-import android.util.AtomicFile;
-import android.util.Slog;
-import android.util.Xml;
import android.view.Display;
-import android.view.DisplayAddress;
import android.view.DisplayInfo;
import android.view.IWindowManager;
import android.view.Surface;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.XmlUtils;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.DisplayContent.ForceScalingMode;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
+import java.util.Objects;
/**
- * Current persistent settings about a display
+ * Current persistent settings about a display. Provides policies for display settings and
+ * delegates the persistence and lookup of settings values to the supplied {@link SettingsProvider}.
*/
class DisplayWindowSettings {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayWindowSettings" : TAG_WM;
-
- private static final String SYSTEM_DIRECTORY = "system";
- private static final String DISPLAY_SETTINGS_FILE_NAME = "display_settings.xml";
- private static final String VENDOR_DISPLAY_SETTINGS_PATH = "etc/" + DISPLAY_SETTINGS_FILE_NAME;
- private static final String WM_DISPLAY_COMMIT_TAG = "wm-displays";
-
- private static final int IDENTIFIER_UNIQUE_ID = 0;
- private static final int IDENTIFIER_PORT = 1;
- @IntDef(prefix = { "IDENTIFIER_" }, value = {
- IDENTIFIER_UNIQUE_ID,
- IDENTIFIER_PORT,
- })
- @interface DisplayIdentifierType {}
-
private final WindowManagerService mService;
- private final HashMap<String, Entry> mEntries = new HashMap<>();
- private final SettingPersister mStorage;
+ private final SettingsProvider mSettingsProvider;
- /**
- * The preferred type of a display identifier to use when storing and retrieving entries.
- * {@link #getIdentifier(DisplayInfo)} must be used to get current preferred identifier for each
- * display. It will fall back to using {@link #IDENTIFIER_UNIQUE_ID} if the currently selected
- * one is not applicable to a particular display.
- */
- @DisplayIdentifierType
- private int mIdentifier = IDENTIFIER_UNIQUE_ID;
-
- /** Interface for persisting the display window settings. */
- interface SettingPersister {
- InputStream openRead() throws IOException;
- OutputStream startWrite() throws IOException;
- void finishWrite(OutputStream os, boolean success);
- }
-
- private static class Entry {
- private final String mName;
- private int mWindowingMode = WindowConfiguration.WINDOWING_MODE_UNDEFINED;
- private int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
- private int mUserRotation = Surface.ROTATION_0;
- private int mForcedWidth;
- private int mForcedHeight;
- private int mForcedDensity;
- private int mForcedScalingMode = FORCE_SCALING_MODE_AUTO;
- private int mRemoveContentMode = REMOVE_CONTENT_MODE_UNDEFINED;
- private boolean mShouldShowWithInsecureKeyguard = false;
- private boolean mShouldShowSystemDecors = false;
- private boolean mShouldShowIme = false;
- private int mFixedToUserRotation = IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT;
- private boolean mIgnoreOrientationRequest = false;
-
- private Entry(String name) {
- mName = name;
- }
-
- private Entry(String name, Entry copyFrom) {
- this(name);
- mWindowingMode = copyFrom.mWindowingMode;
- mUserRotationMode = copyFrom.mUserRotationMode;
- mUserRotation = copyFrom.mUserRotation;
- mForcedWidth = copyFrom.mForcedWidth;
- mForcedHeight = copyFrom.mForcedHeight;
- mForcedDensity = copyFrom.mForcedDensity;
- mForcedScalingMode = copyFrom.mForcedScalingMode;
- mRemoveContentMode = copyFrom.mRemoveContentMode;
- mShouldShowWithInsecureKeyguard = copyFrom.mShouldShowWithInsecureKeyguard;
- mShouldShowSystemDecors = copyFrom.mShouldShowSystemDecors;
- mShouldShowIme = copyFrom.mShouldShowIme;
- mFixedToUserRotation = copyFrom.mFixedToUserRotation;
- mIgnoreOrientationRequest = copyFrom.mIgnoreOrientationRequest;
- }
-
- /** @return {@code true} if all values are default. */
- private boolean isEmpty() {
- return mWindowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED
- && mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE
- && mUserRotation == Surface.ROTATION_0
- && mForcedWidth == 0 && mForcedHeight == 0 && mForcedDensity == 0
- && mForcedScalingMode == FORCE_SCALING_MODE_AUTO
- && mRemoveContentMode == REMOVE_CONTENT_MODE_UNDEFINED
- && !mShouldShowWithInsecureKeyguard
- && !mShouldShowSystemDecors
- && !mShouldShowIme
- && mFixedToUserRotation == IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT
- && !mIgnoreOrientationRequest;
- }
- }
-
- DisplayWindowSettings(WindowManagerService service) {
- this(service, new AtomicFileStorage());
- }
-
- @VisibleForTesting
- DisplayWindowSettings(WindowManagerService service, SettingPersister storageImpl) {
+ DisplayWindowSettings(WindowManagerService service, SettingsProvider settingsProvider) {
mService = service;
- mStorage = storageImpl;
- readSettings();
- }
-
- private @Nullable Entry getEntry(DisplayInfo displayInfo) {
- final String identifier = getIdentifier(displayInfo);
- Entry entry;
- // Try to get corresponding entry using preferred identifier for the current config.
- if ((entry = mEntries.get(identifier)) != null) {
- return entry;
- }
- // Else, fall back to the display name.
- if ((entry = mEntries.get(displayInfo.name)) != null) {
- // Found an entry stored with old identifier - upgrade to the new type now.
- return updateIdentifierForEntry(entry, displayInfo);
- }
- return null;
- }
-
- private Entry getOrCreateEntry(DisplayInfo displayInfo) {
- final Entry entry = getEntry(displayInfo);
- return entry != null ? entry : new Entry(getIdentifier(displayInfo));
- }
-
- /**
- * Upgrades the identifier of a legacy entry. Does it by copying the data from the old record
- * and clearing the old key in memory. The entry will be written to storage next time when a
- * setting changes.
- */
- private Entry updateIdentifierForEntry(Entry entry, DisplayInfo displayInfo) {
- final Entry newEntry = new Entry(getIdentifier(displayInfo), entry);
- removeEntry(displayInfo);
- mEntries.put(newEntry.mName, newEntry);
- return newEntry;
+ mSettingsProvider = settingsProvider;
}
void setUserRotation(DisplayContent displayContent, int rotationMode, int rotation) {
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- entry.mUserRotationMode = rotationMode;
- entry.mUserRotation = rotation;
- writeSettingsIfNeeded(entry, displayInfo);
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mUserRotationMode = rotationMode;
+ overrideSettings.mUserRotation = rotation;
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
void setForcedSize(DisplayContent displayContent, int width, int height) {
@@ -207,14 +64,14 @@
final String sizeString = (width == 0 || height == 0) ? "" : (width + "," + height);
Settings.Global.putString(mService.mContext.getContentResolver(),
Settings.Global.DISPLAY_SIZE_FORCED, sizeString);
- return;
}
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- entry.mForcedWidth = width;
- entry.mForcedHeight = height;
- writeSettingsIfNeeded(entry, displayInfo);
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mForcedWidth = width;
+ overrideSettings.mForcedHeight = height;
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
void setForcedDensity(DisplayContent displayContent, int density, int userId) {
@@ -222,47 +79,47 @@
final String densityString = density == 0 ? "" : Integer.toString(density);
Settings.Secure.putStringForUser(mService.mContext.getContentResolver(),
Settings.Secure.DISPLAY_DENSITY_FORCED, densityString, userId);
- return;
}
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- entry.mForcedDensity = density;
- writeSettingsIfNeeded(entry, displayInfo);
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mForcedDensity = density;
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
void setForcedScalingMode(DisplayContent displayContent, @ForceScalingMode int mode) {
if (displayContent.isDefaultDisplay) {
Settings.Global.putInt(mService.mContext.getContentResolver(),
Settings.Global.DISPLAY_SCALING_FORCE, mode);
- return;
}
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- entry.mForcedScalingMode = mode;
- writeSettingsIfNeeded(entry, displayInfo);
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mForcedScalingMode = mode;
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
void setFixedToUserRotation(DisplayContent displayContent, int fixedToUserRotation) {
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- entry.mFixedToUserRotation = fixedToUserRotation;
- writeSettingsIfNeeded(entry, displayInfo);
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mFixedToUserRotation = fixedToUserRotation;
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
void setIgnoreOrientationRequest(
DisplayContent displayContent, boolean ignoreOrientationRequest) {
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- if (entry.mIgnoreOrientationRequest == ignoreOrientationRequest) return;
- entry.mIgnoreOrientationRequest = ignoreOrientationRequest;
- writeSettingsIfNeeded(entry, displayInfo);
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mIgnoreOrientationRequest = ignoreOrientationRequest;
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
- private int getWindowingModeLocked(Entry entry, DisplayContent dc) {
- int windowingMode = entry != null ? entry.mWindowingMode
- : WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+ private int getWindowingModeLocked(SettingsProvider.SettingsEntry settings, DisplayContent dc) {
+ int windowingMode = settings.mWindowingMode;
// This display used to be in freeform, but we don't support freeform anymore, so fall
// back to fullscreen.
if (windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM
@@ -281,22 +138,23 @@
int getWindowingModeLocked(DisplayContent dc) {
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getEntry(displayInfo);
- return getWindowingModeLocked(entry, dc);
+ final SettingsProvider.SettingsEntry settings = mSettingsProvider.getSettings(displayInfo);
+ return getWindowingModeLocked(settings, dc);
}
void setWindowingModeLocked(DisplayContent dc, int mode) {
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- entry.mWindowingMode = mode;
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mWindowingMode = mode;
dc.setWindowingMode(mode);
- writeSettingsIfNeeded(entry, displayInfo);
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
int getRemoveContentModeLocked(DisplayContent dc) {
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getEntry(displayInfo);
- if (entry == null || entry.mRemoveContentMode == REMOVE_CONTENT_MODE_UNDEFINED) {
+ final SettingsProvider.SettingsEntry settings = mSettingsProvider.getSettings(displayInfo);
+ if (settings.mRemoveContentMode == REMOVE_CONTENT_MODE_UNDEFINED) {
if (dc.isPrivate()) {
// For private displays by default content is destroyed on removal.
return REMOVE_CONTENT_MODE_DESTROY;
@@ -304,111 +162,110 @@
// For other displays by default content is moved to primary on removal.
return REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY;
}
- return entry.mRemoveContentMode;
+ return settings.mRemoveContentMode;
}
void setRemoveContentModeLocked(DisplayContent dc, int mode) {
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- entry.mRemoveContentMode = mode;
- writeSettingsIfNeeded(entry, displayInfo);
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mRemoveContentMode = mode;
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
boolean shouldShowWithInsecureKeyguardLocked(DisplayContent dc) {
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getEntry(displayInfo);
- if (entry == null) {
- return false;
- }
- return entry.mShouldShowWithInsecureKeyguard;
+ final SettingsProvider.SettingsEntry settings = mSettingsProvider.getSettings(displayInfo);
+ return settings.mShouldShowWithInsecureKeyguard != null
+ ? settings.mShouldShowWithInsecureKeyguard : false;
}
void setShouldShowWithInsecureKeyguardLocked(DisplayContent dc, boolean shouldShow) {
if (!dc.isPrivate() && shouldShow) {
- Slog.e(TAG, "Public display can't be allowed to show content when locked");
- return;
+ throw new IllegalArgumentException("Public display can't be allowed to show content"
+ + " when locked");
}
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- entry.mShouldShowWithInsecureKeyguard = shouldShow;
- writeSettingsIfNeeded(entry, displayInfo);
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mShouldShowWithInsecureKeyguard = shouldShow;
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
boolean shouldShowSystemDecorsLocked(DisplayContent dc) {
if (dc.getDisplayId() == Display.DEFAULT_DISPLAY) {
- // For default display should show system decors.
+ // Default display should show system decors.
return true;
}
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getEntry(displayInfo);
- if (entry == null) {
- return false;
- }
- return entry.mShouldShowSystemDecors;
+ final SettingsProvider.SettingsEntry settings = mSettingsProvider.getSettings(displayInfo);
+ return settings.mShouldShowSystemDecors != null ? settings.mShouldShowSystemDecors : false;
}
void setShouldShowSystemDecorsLocked(DisplayContent dc, boolean shouldShow) {
- if (dc.getDisplayId() == Display.DEFAULT_DISPLAY && !shouldShow) {
- Slog.e(TAG, "Default display should show system decors");
- return;
- }
-
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- entry.mShouldShowSystemDecors = shouldShow;
- writeSettingsIfNeeded(entry, displayInfo);
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mShouldShowSystemDecors = shouldShow;
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
boolean shouldShowImeLocked(DisplayContent dc) {
if (dc.getDisplayId() == Display.DEFAULT_DISPLAY) {
- // For default display should shows IME.
+ // Default display should show IME.
return true;
}
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getEntry(displayInfo);
- if (entry == null) {
- return false;
- }
- return entry.mShouldShowIme;
+ final SettingsProvider.SettingsEntry settings = mSettingsProvider.getSettings(displayInfo);
+ return settings.mShouldShowIme != null ? settings.mShouldShowIme : false;
}
void setShouldShowImeLocked(DisplayContent dc, boolean shouldShow) {
- if (dc.getDisplayId() == Display.DEFAULT_DISPLAY && !shouldShow) {
- Slog.e(TAG, "Default display should show IME");
- return;
- }
-
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- entry.mShouldShowIme = shouldShow;
- writeSettingsIfNeeded(entry, displayInfo);
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mShouldShowIme = shouldShow;
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
void applySettingsToDisplayLocked(DisplayContent dc) {
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
+ final SettingsProvider.SettingsEntry settings = mSettingsProvider.getSettings(displayInfo);
// Setting windowing mode first, because it may override overscan values later.
- dc.setWindowingMode(getWindowingModeLocked(entry, dc));
+ final int windowingMode = getWindowingModeLocked(settings, dc);
+ dc.setWindowingMode(windowingMode);
- dc.getDisplayRotation().restoreSettings(entry.mUserRotationMode,
- entry.mUserRotation, entry.mFixedToUserRotation);
+ final int userRotationMode = settings.mUserRotationMode != null
+ ? settings.mUserRotationMode : WindowManagerPolicy.USER_ROTATION_FREE;
+ final int userRotation = settings.mUserRotation != null
+ ? settings.mUserRotation : Surface.ROTATION_0;
+ final int mFixedToUserRotation = settings.mFixedToUserRotation != null
+ ? settings.mFixedToUserRotation : IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT;
+ dc.getDisplayRotation().restoreSettings(userRotationMode, userRotation,
+ mFixedToUserRotation);
- final boolean hasDensityOverride = entry.mForcedDensity != 0;
- final boolean hasSizeOverride = entry.mForcedWidth != 0 && entry.mForcedHeight != 0;
+ final boolean hasDensityOverride = settings.mForcedDensity != 0;
+ final boolean hasSizeOverride = settings.mForcedWidth != 0 && settings.mForcedHeight != 0;
dc.mIsDensityForced = hasDensityOverride;
dc.mIsSizeForced = hasSizeOverride;
- dc.setIgnoreOrientationRequest(entry.mIgnoreOrientationRequest);
- final int width = hasSizeOverride ? entry.mForcedWidth : dc.mBaseDisplayWidth;
- final int height = hasSizeOverride ? entry.mForcedHeight : dc.mBaseDisplayHeight;
- final int density = hasDensityOverride ? entry.mForcedDensity : dc.mBaseDisplayDensity;
+ final boolean ignoreOrientationRequest = settings.mIgnoreOrientationRequest != null
+ ? settings.mIgnoreOrientationRequest : false;
+ dc.setIgnoreOrientationRequest(ignoreOrientationRequest);
+
+ final int width = hasSizeOverride ? settings.mForcedWidth : dc.mInitialDisplayWidth;
+ final int height = hasSizeOverride ? settings.mForcedHeight : dc.mInitialDisplayHeight;
+ final int density = hasDensityOverride ? settings.mForcedDensity
+ : dc.mInitialDisplayDensity;
dc.updateBaseDisplayMetrics(width, height, density);
- dc.mDisplayScalingDisabled = entry.mForcedScalingMode == FORCE_SCALING_MODE_DISABLED;
+ final int forcedScalingMode = settings.mForcedScalingMode != null
+ ? settings.mForcedScalingMode : FORCE_SCALING_MODE_AUTO;
+ dc.mDisplayScalingDisabled = forcedScalingMode == FORCE_SCALING_MODE_DISABLED;
}
/**
@@ -429,291 +286,281 @@
return false;
}
- private void readSettings() {
- InputStream stream;
- try {
- stream = mStorage.openRead();
- } catch (IOException e) {
- Slog.i(TAG, "No existing display settings, starting empty");
- return;
- }
- boolean success = false;
- try {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(stream, StandardCharsets.UTF_8.name());
- int type;
- while ((type = parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {
- // Do nothing.
- }
-
- if (type != XmlPullParser.START_TAG) {
- throw new IllegalStateException("no start tag found");
- }
-
- int outerDepth = parser.getDepth();
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals("display")) {
- readDisplay(parser);
- } else if (tagName.equals("config")) {
- readConfig(parser);
- } else {
- Slog.w(TAG, "Unknown element under <display-settings>: "
- + parser.getName());
- XmlUtils.skipCurrentTag(parser);
- }
- }
- success = true;
- } catch (IllegalStateException e) {
- Slog.w(TAG, "Failed parsing " + e);
- } catch (NullPointerException e) {
- Slog.w(TAG, "Failed parsing " + e);
- } catch (NumberFormatException e) {
- Slog.w(TAG, "Failed parsing " + e);
- } catch (XmlPullParserException e) {
- Slog.w(TAG, "Failed parsing " + e);
- } catch (IOException e) {
- Slog.w(TAG, "Failed parsing " + e);
- } catch (IndexOutOfBoundsException e) {
- Slog.w(TAG, "Failed parsing " + e);
- } finally {
- if (!success) {
- mEntries.clear();
- }
- try {
- stream.close();
- } catch (IOException e) {
- }
- }
- }
-
- private int getIntAttribute(XmlPullParser parser, String name) {
- return getIntAttribute(parser, name, 0 /* defaultValue */);
- }
-
- private int getIntAttribute(XmlPullParser parser, String name, int defaultValue) {
- try {
- final String str = parser.getAttributeValue(null, name);
- return str != null ? Integer.parseInt(str) : defaultValue;
- } catch (NumberFormatException e) {
- return defaultValue;
- }
- }
-
- private boolean getBooleanAttribute(XmlPullParser parser, String name) {
- return getBooleanAttribute(parser, name, false /* defaultValue */);
- }
-
- private boolean getBooleanAttribute(XmlPullParser parser, String name, boolean defaultValue) {
- try {
- final String str = parser.getAttributeValue(null, name);
- return str != null ? Boolean.parseBoolean(str) : defaultValue;
- } catch (NumberFormatException e) {
- return defaultValue;
- }
- }
-
- private void readDisplay(XmlPullParser parser) throws NumberFormatException,
- XmlPullParserException, IOException {
- String name = parser.getAttributeValue(null, "name");
- if (name != null) {
- Entry entry = new Entry(name);
- entry.mWindowingMode = getIntAttribute(parser, "windowingMode",
- WindowConfiguration.WINDOWING_MODE_UNDEFINED);
- entry.mUserRotationMode = getIntAttribute(parser, "userRotationMode",
- WindowManagerPolicy.USER_ROTATION_FREE);
- entry.mUserRotation = getIntAttribute(parser, "userRotation",
- Surface.ROTATION_0);
- entry.mForcedWidth = getIntAttribute(parser, "forcedWidth");
- entry.mForcedHeight = getIntAttribute(parser, "forcedHeight");
- entry.mForcedDensity = getIntAttribute(parser, "forcedDensity");
- entry.mForcedScalingMode = getIntAttribute(parser, "forcedScalingMode",
- FORCE_SCALING_MODE_AUTO);
- entry.mRemoveContentMode = getIntAttribute(parser, "removeContentMode",
- REMOVE_CONTENT_MODE_UNDEFINED);
- entry.mShouldShowWithInsecureKeyguard = getBooleanAttribute(parser,
- "shouldShowWithInsecureKeyguard");
- entry.mShouldShowSystemDecors = getBooleanAttribute(parser, "shouldShowSystemDecors");
- entry.mShouldShowIme = getBooleanAttribute(parser, "shouldShowIme");
- entry.mFixedToUserRotation = getIntAttribute(parser, "fixedToUserRotation");
- entry.mIgnoreOrientationRequest
- = getBooleanAttribute(parser, "ignoreOrientationRequest");
- mEntries.put(name, entry);
- }
- XmlUtils.skipCurrentTag(parser);
- }
-
- private void readConfig(XmlPullParser parser) throws NumberFormatException,
- XmlPullParserException, IOException {
- mIdentifier = getIntAttribute(parser, "identifier");
- XmlUtils.skipCurrentTag(parser);
- }
-
- private void writeSettingsIfNeeded(Entry changedEntry, DisplayInfo displayInfo) {
- if (changedEntry.isEmpty() && !removeEntry(displayInfo)) {
- // The entry didn't exist so nothing is changed and no need to update the file.
- return;
- }
-
- mEntries.put(getIdentifier(displayInfo), changedEntry);
- writeSettings();
- }
-
- private void writeSettings() {
- OutputStream stream;
- try {
- stream = mStorage.startWrite();
- } catch (IOException e) {
- Slog.w(TAG, "Failed to write display settings: " + e);
- return;
- }
-
- try {
- XmlSerializer out = new FastXmlSerializer();
- out.setOutput(stream, StandardCharsets.UTF_8.name());
- out.startDocument(null, true);
-
- out.startTag(null, "display-settings");
-
- out.startTag(null, "config");
- out.attribute(null, "identifier", Integer.toString(mIdentifier));
- out.endTag(null, "config");
-
- for (Entry entry : mEntries.values()) {
- out.startTag(null, "display");
- out.attribute(null, "name", entry.mName);
- if (entry.mWindowingMode != WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
- out.attribute(null, "windowingMode", Integer.toString(entry.mWindowingMode));
- }
- if (entry.mUserRotationMode != WindowManagerPolicy.USER_ROTATION_FREE) {
- out.attribute(null, "userRotationMode",
- Integer.toString(entry.mUserRotationMode));
- }
- if (entry.mUserRotation != Surface.ROTATION_0) {
- out.attribute(null, "userRotation", Integer.toString(entry.mUserRotation));
- }
- if (entry.mForcedWidth != 0 && entry.mForcedHeight != 0) {
- out.attribute(null, "forcedWidth", Integer.toString(entry.mForcedWidth));
- out.attribute(null, "forcedHeight", Integer.toString(entry.mForcedHeight));
- }
- if (entry.mForcedDensity != 0) {
- out.attribute(null, "forcedDensity", Integer.toString(entry.mForcedDensity));
- }
- if (entry.mForcedScalingMode != FORCE_SCALING_MODE_AUTO) {
- out.attribute(null, "forcedScalingMode",
- Integer.toString(entry.mForcedScalingMode));
- }
- if (entry.mRemoveContentMode != REMOVE_CONTENT_MODE_UNDEFINED) {
- out.attribute(null, "removeContentMode",
- Integer.toString(entry.mRemoveContentMode));
- }
- if (entry.mShouldShowWithInsecureKeyguard) {
- out.attribute(null, "shouldShowWithInsecureKeyguard",
- Boolean.toString(entry.mShouldShowWithInsecureKeyguard));
- }
- if (entry.mShouldShowSystemDecors) {
- out.attribute(null, "shouldShowSystemDecors",
- Boolean.toString(entry.mShouldShowSystemDecors));
- }
- if (entry.mShouldShowIme) {
- out.attribute(null, "shouldShowIme", Boolean.toString(entry.mShouldShowIme));
- }
- if (entry.mFixedToUserRotation != IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT) {
- out.attribute(null, "fixedToUserRotation",
- Integer.toString(entry.mFixedToUserRotation));
- }
- if (entry.mIgnoreOrientationRequest) {
- out.attribute(null, "ignoreOrientationRequest",
- Boolean.toString(entry.mIgnoreOrientationRequest));
- }
- out.endTag(null, "display");
- }
-
- out.endTag(null, "display-settings");
- out.endDocument();
- mStorage.finishWrite(stream, true /* success */);
- } catch (IOException e) {
- Slog.w(TAG, "Failed to write display window settings.", e);
- mStorage.finishWrite(stream, false /* success */);
- }
- }
-
/**
- * Removes an entry from {@link #mEntries} cache. Looks up by new and previously used
- * identifiers.
+ * Provides the functionality to lookup the {@link SettingsEntry settings} for a given
+ * {@link DisplayInfo}.
+ * <p>
+ * NOTE: All interactions with implementations of this provider <b>must</b> be thread-safe
+ * externally.
*/
- private boolean removeEntry(DisplayInfo displayInfo) {
- // Remove entry based on primary identifier.
- boolean removed = mEntries.remove(getIdentifier(displayInfo)) != null;
- // Ensure that legacy entries are cleared as well.
- removed |= mEntries.remove(displayInfo.uniqueId) != null;
- removed |= mEntries.remove(displayInfo.name) != null;
- return removed;
- }
+ interface SettingsProvider {
+ /**
+ * Returns the {@link SettingsEntry} for a given {@link DisplayInfo}. The values for the
+ * returned settings are guaranteed to match those previously set with
+ * {@link #updateOverrideSettings(DisplayInfo, SettingsEntry)} with all other values left
+ * to the implementation to determine.
+ */
+ @NonNull
+ SettingsEntry getSettings(@NonNull DisplayInfo info);
- /** Gets the identifier of choice for the current config. */
- private String getIdentifier(DisplayInfo displayInfo) {
- if (mIdentifier == IDENTIFIER_PORT && displayInfo.address != null) {
- // Config suggests using port as identifier for physical displays.
- if (displayInfo.address instanceof DisplayAddress.Physical) {
- return "port:" + ((DisplayAddress.Physical) displayInfo.address).getPort();
+ /**
+ * Returns the existing override settings for the given {@link DisplayInfo}. All calls to
+ * {@link #getSettings(DisplayInfo)} for the provided {@code info} are required to have
+ * their values overridden with all set values from the returned {@link SettingsEntry}.
+ *
+ * @see #getSettings(DisplayInfo)
+ * @see #updateOverrideSettings(DisplayInfo, SettingsEntry)
+ */
+ @NonNull
+ SettingsEntry getOverrideSettings(@NonNull DisplayInfo info);
+
+ /**
+ * Updates the override settings for a given {@link DisplayInfo}. All subsequent calls to
+ * {@link #getSettings(DisplayInfo)} for the provided {@link DisplayInfo} are required to
+ * have their values match all set values in {@code overrides}.
+ *
+ * @see #getSettings(DisplayInfo)
+ */
+ void updateOverrideSettings(@NonNull DisplayInfo info, @NonNull SettingsEntry overrides);
+
+ /**
+ * Settings for a display.
+ */
+ class SettingsEntry {
+ int mWindowingMode = WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+ @Nullable
+ Integer mUserRotationMode;
+ @Nullable
+ Integer mUserRotation;
+ int mForcedWidth;
+ int mForcedHeight;
+ int mForcedDensity;
+ @Nullable
+ Integer mForcedScalingMode;
+ int mRemoveContentMode = REMOVE_CONTENT_MODE_UNDEFINED;
+ @Nullable
+ Boolean mShouldShowWithInsecureKeyguard;
+ @Nullable
+ Boolean mShouldShowSystemDecors;
+ @Nullable
+ Boolean mShouldShowIme;
+ @Nullable
+ Integer mFixedToUserRotation;
+ @Nullable
+ Boolean mIgnoreOrientationRequest;
+
+ SettingsEntry() {}
+
+ SettingsEntry(SettingsEntry copyFrom) {
+ setTo(copyFrom);
}
- }
- return displayInfo.uniqueId;
- }
- private static class AtomicFileStorage implements SettingPersister {
- private final AtomicFile mAtomicFile;
-
- AtomicFileStorage() {
- final File folder = new File(Environment.getDataDirectory(), SYSTEM_DIRECTORY);
- final File settingsFile = new File(folder, DISPLAY_SETTINGS_FILE_NAME);
- // If display_settings.xml doesn't exist, try to copy the vendor's one instead
- // in order to provide the vendor specific initialization.
- if (!settingsFile.exists()) {
- copyVendorSettings(settingsFile);
- }
- mAtomicFile = new AtomicFile(settingsFile, WM_DISPLAY_COMMIT_TAG);
- }
-
- private static void copyVendorSettings(File target) {
- final File vendorFile = new File(Environment.getVendorDirectory(),
- VENDOR_DISPLAY_SETTINGS_PATH);
- if (vendorFile.canRead()) {
- try {
- FileUtils.copy(vendorFile, target);
- } catch (IOException e) {
- Slog.e(TAG, "Failed to copy vendor display_settings.xml");
+ /**
+ * Copies all fields from {@code delta} into this {@link SettingsEntry} object, keeping
+ * track of whether a change has occurred.
+ *
+ * @return {@code true} if this settings have changed as a result of the copy,
+ * {@code false} otherwise.
+ *
+ * @see #updateFrom(SettingsEntry)
+ */
+ boolean setTo(@NonNull SettingsEntry other) {
+ boolean changed = false;
+ if (other.mWindowingMode != mWindowingMode) {
+ mWindowingMode = other.mWindowingMode;
+ changed = true;
}
+ if (!Objects.equals(other.mUserRotationMode, mUserRotationMode)) {
+ mUserRotationMode = other.mUserRotationMode;
+ changed = true;
+ }
+ if (!Objects.equals(other.mUserRotation, mUserRotation)) {
+ mUserRotation = other.mUserRotation;
+ changed = true;
+ }
+ if (other.mForcedWidth != mForcedWidth) {
+ mForcedWidth = other.mForcedWidth;
+ changed = true;
+ }
+ if (other.mForcedHeight != mForcedHeight) {
+ mForcedHeight = other.mForcedHeight;
+ changed = true;
+ }
+ if (other.mForcedDensity != mForcedDensity) {
+ mForcedDensity = other.mForcedDensity;
+ changed = true;
+ }
+ if (!Objects.equals(other.mForcedScalingMode, mForcedScalingMode)) {
+ mForcedScalingMode = other.mForcedScalingMode;
+ changed = true;
+ }
+ if (other.mRemoveContentMode != mRemoveContentMode) {
+ mRemoveContentMode = other.mRemoveContentMode;
+ changed = true;
+ }
+ if (other.mShouldShowWithInsecureKeyguard != mShouldShowWithInsecureKeyguard) {
+ mShouldShowWithInsecureKeyguard = other.mShouldShowWithInsecureKeyguard;
+ changed = true;
+ }
+ if (other.mShouldShowSystemDecors != mShouldShowSystemDecors) {
+ mShouldShowSystemDecors = other.mShouldShowSystemDecors;
+ changed = true;
+ }
+ if (other.mShouldShowIme != mShouldShowIme) {
+ mShouldShowIme = other.mShouldShowIme;
+ changed = true;
+ }
+ if (!Objects.equals(other.mFixedToUserRotation, mFixedToUserRotation)) {
+ mFixedToUserRotation = other.mFixedToUserRotation;
+ changed = true;
+ }
+ if (other.mIgnoreOrientationRequest != mIgnoreOrientationRequest) {
+ mIgnoreOrientationRequest = other.mIgnoreOrientationRequest;
+ changed = true;
+ }
+ return changed;
}
- }
- @Override
- public InputStream openRead() throws FileNotFoundException {
- return mAtomicFile.openRead();
- }
-
- @Override
- public OutputStream startWrite() throws IOException {
- return mAtomicFile.startWrite();
- }
-
- @Override
- public void finishWrite(OutputStream os, boolean success) {
- if (!(os instanceof FileOutputStream)) {
- throw new IllegalArgumentException("Unexpected OutputStream as argument: " + os);
+ /**
+ * Copies the fields from {@code delta} into this {@link SettingsEntry} object, keeping
+ * track of whether a change has occurred. Any undefined fields in {@code delta} are
+ * ignored and not copied into the current {@link SettingsEntry}.
+ *
+ * @return {@code true} if this settings have changed as a result of the copy,
+ * {@code false} otherwise.
+ *
+ * @see #setTo(SettingsEntry)
+ */
+ boolean updateFrom(@NonNull SettingsEntry delta) {
+ boolean changed = false;
+ if (delta.mWindowingMode != WindowConfiguration.WINDOWING_MODE_UNDEFINED
+ && delta.mWindowingMode != mWindowingMode) {
+ mWindowingMode = delta.mWindowingMode;
+ changed = true;
+ }
+ if (delta.mUserRotationMode != null
+ && !Objects.equals(delta.mUserRotationMode, mUserRotationMode)) {
+ mUserRotationMode = delta.mUserRotationMode;
+ changed = true;
+ }
+ if (delta.mUserRotation != null
+ && !Objects.equals(delta.mUserRotation, mUserRotation)) {
+ mUserRotation = delta.mUserRotation;
+ changed = true;
+ }
+ if (delta.mForcedWidth != 0 && delta.mForcedWidth != mForcedWidth) {
+ mForcedWidth = delta.mForcedWidth;
+ changed = true;
+ }
+ if (delta.mForcedHeight != 0 && delta.mForcedHeight != mForcedHeight) {
+ mForcedHeight = delta.mForcedHeight;
+ changed = true;
+ }
+ if (delta.mForcedDensity != 0 && delta.mForcedDensity != mForcedDensity) {
+ mForcedDensity = delta.mForcedDensity;
+ changed = true;
+ }
+ if (delta.mForcedScalingMode != null
+ && !Objects.equals(delta.mForcedScalingMode, mForcedScalingMode)) {
+ mForcedScalingMode = delta.mForcedScalingMode;
+ changed = true;
+ }
+ if (delta.mRemoveContentMode != REMOVE_CONTENT_MODE_UNDEFINED
+ && delta.mRemoveContentMode != mRemoveContentMode) {
+ mRemoveContentMode = delta.mRemoveContentMode;
+ changed = true;
+ }
+ if (delta.mShouldShowWithInsecureKeyguard != null
+ && delta.mShouldShowWithInsecureKeyguard
+ != mShouldShowWithInsecureKeyguard) {
+ mShouldShowWithInsecureKeyguard = delta.mShouldShowWithInsecureKeyguard;
+ changed = true;
+ }
+ if (delta.mShouldShowSystemDecors != null
+ && delta.mShouldShowSystemDecors != mShouldShowSystemDecors) {
+ mShouldShowSystemDecors = delta.mShouldShowSystemDecors;
+ changed = true;
+ }
+ if (delta.mShouldShowIme != null
+ && delta.mShouldShowIme != mShouldShowIme) {
+ mShouldShowIme = delta.mShouldShowIme;
+ changed = true;
+ }
+ if (delta.mFixedToUserRotation != null
+ && !Objects.equals(delta.mFixedToUserRotation, mFixedToUserRotation)) {
+ mFixedToUserRotation = delta.mFixedToUserRotation;
+ changed = true;
+ }
+ if (delta.mIgnoreOrientationRequest != null
+ && delta.mIgnoreOrientationRequest != mIgnoreOrientationRequest) {
+ mIgnoreOrientationRequest = delta.mIgnoreOrientationRequest;
+ changed = true;
+ }
+ return changed;
}
- FileOutputStream fos = (FileOutputStream) os;
- if (success) {
- mAtomicFile.finishWrite(fos);
- } else {
- mAtomicFile.failWrite(fos);
+
+ /** @return {@code true} if all values are unset. */
+ boolean isEmpty() {
+ return mWindowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED
+ && mUserRotationMode == null
+ && mUserRotation == null
+ && mForcedWidth == 0 && mForcedHeight == 0 && mForcedDensity == 0
+ && mForcedScalingMode == null
+ && mRemoveContentMode == REMOVE_CONTENT_MODE_UNDEFINED
+ && mShouldShowWithInsecureKeyguard == null
+ && mShouldShowSystemDecors == null
+ && mShouldShowIme == null
+ && mFixedToUserRotation == null
+ && mIgnoreOrientationRequest == null;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ SettingsEntry that = (SettingsEntry) o;
+ return mWindowingMode == that.mWindowingMode
+ && mForcedWidth == that.mForcedWidth
+ && mForcedHeight == that.mForcedHeight
+ && mForcedDensity == that.mForcedDensity
+ && mRemoveContentMode == that.mRemoveContentMode
+ && Objects.equals(mUserRotationMode, that.mUserRotationMode)
+ && Objects.equals(mUserRotation, that.mUserRotation)
+ && Objects.equals(mForcedScalingMode, that.mForcedScalingMode)
+ && Objects.equals(mShouldShowWithInsecureKeyguard,
+ that.mShouldShowWithInsecureKeyguard)
+ && Objects.equals(mShouldShowSystemDecors, that.mShouldShowSystemDecors)
+ && Objects.equals(mShouldShowIme, that.mShouldShowIme)
+ && Objects.equals(mFixedToUserRotation, that.mFixedToUserRotation)
+ && Objects.equals(mIgnoreOrientationRequest,
+ that.mIgnoreOrientationRequest);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mWindowingMode, mUserRotationMode, mUserRotation, mForcedWidth,
+ mForcedHeight, mForcedDensity, mForcedScalingMode, mRemoveContentMode,
+ mShouldShowWithInsecureKeyguard, mShouldShowSystemDecors, mShouldShowIme,
+ mFixedToUserRotation, mIgnoreOrientationRequest);
+ }
+
+ @Override
+ public String toString() {
+ return "SettingsEntry{"
+ + "mWindowingMode=" + mWindowingMode
+ + ", mUserRotationMode=" + mUserRotationMode
+ + ", mUserRotation=" + mUserRotation
+ + ", mForcedWidth=" + mForcedWidth
+ + ", mForcedHeight=" + mForcedHeight
+ + ", mForcedDensity=" + mForcedDensity
+ + ", mForcedScalingMode=" + mForcedScalingMode
+ + ", mRemoveContentMode=" + mRemoveContentMode
+ + ", mShouldShowWithInsecureKeyguard=" + mShouldShowWithInsecureKeyguard
+ + ", mShouldShowSystemDecors=" + mShouldShowSystemDecors
+ + ", mShouldShowIme=" + mShouldShowIme
+ + ", mFixedToUserRotation=" + mFixedToUserRotation
+ + ", mIgnoreOrientationRequest=" + mIgnoreOrientationRequest
+ + '}';
}
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
new file mode 100644
index 0000000..a7f7c48
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
@@ -0,0 +1,549 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
+
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.WindowConfiguration;
+import android.os.Environment;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+import android.view.DisplayAddress;
+import android.view.DisplayInfo;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+import com.android.server.wm.DisplayWindowSettings.SettingsProvider;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Implementation of {@link SettingsProvider} that reads the base settings provided in a display
+ * settings file stored in /vendor/etc and then overlays those values with the settings provided in
+ * /data/system.
+ *
+ * @see DisplayWindowSettings
+ */
+class DisplayWindowSettingsProvider implements SettingsProvider {
+ private static final String TAG = TAG_WITH_CLASS_NAME
+ ? "DisplayWindowSettingsProvider" : TAG_WM;
+
+ private static final String DATA_DISPLAY_SETTINGS_FILE_PATH = "system/display_settings.xml";
+ private static final String VENDOR_DISPLAY_SETTINGS_PATH = "etc/display_settings.xml";
+ private static final String WM_DISPLAY_COMMIT_TAG = "wm-displays";
+
+ private static final int IDENTIFIER_UNIQUE_ID = 0;
+ private static final int IDENTIFIER_PORT = 1;
+ @IntDef(prefix = { "IDENTIFIER_" }, value = {
+ IDENTIFIER_UNIQUE_ID,
+ IDENTIFIER_PORT,
+ })
+ @interface DisplayIdentifierType {}
+
+ /** Interface that allows reading the display window settings. */
+ interface ReadableSettingsStorage {
+ InputStream openRead() throws IOException;
+ }
+
+ /** Interface that allows reading and writing the display window settings. */
+ interface WritableSettingsStorage extends ReadableSettingsStorage {
+ OutputStream startWrite() throws IOException;
+ void finishWrite(OutputStream os, boolean success);
+ }
+
+ private final ReadableSettingsStorage mVendorSettingsStorage;
+ /**
+ * The preferred type of a display identifier to use when storing and retrieving entries from
+ * the base (vendor) settings file.
+ *
+ * @see #getIdentifier(DisplayInfo, int)
+ */
+ @DisplayIdentifierType
+ private int mVendorIdentifierType;
+ private final Map<String, SettingsEntry> mVendorSettings = new HashMap<>();
+
+ private final WritableSettingsStorage mOverrideSettingsStorage;
+ /**
+ * The preferred type of a display identifier to use when storing and retrieving entries from
+ * the data (override) settings file.
+ *
+ * @see #getIdentifier(DisplayInfo, int)
+ */
+ @DisplayIdentifierType
+ private int mOverrideIdentifierType;
+ private final Map<String, SettingsEntry> mOverrideSettings = new HashMap<>();
+
+ /**
+ * Enables or disables settings provided from the vendor settings storage.
+ *
+ * @see #setVendorSettingsIgnored(boolean)
+ */
+ private boolean mIgnoreVendorSettings = true;
+
+ DisplayWindowSettingsProvider() {
+ this(new AtomicFileStorage(getVendorSettingsFile()),
+ new AtomicFileStorage(getOverrideSettingsFile()));
+ }
+
+ @VisibleForTesting
+ DisplayWindowSettingsProvider(@NonNull ReadableSettingsStorage vendorSettingsStorage,
+ @NonNull WritableSettingsStorage overrideSettingsStorage) {
+ mVendorSettingsStorage = vendorSettingsStorage;
+ mOverrideSettingsStorage = overrideSettingsStorage;
+ readSettings();
+ }
+
+ /**
+ * Enables or disables settings provided from the vendor settings storage. If {@code true}, the
+ * vendor settings will be ignored and only the override settings will be returned from
+ * {@link #getSettings(DisplayInfo)}. If {@code false}, settings returned from
+ * {@link #getSettings(DisplayInfo)} will be a merged result of the vendor settings and the
+ * override settings.
+ */
+ void setVendorSettingsIgnored(boolean ignored) {
+ mIgnoreVendorSettings = ignored;
+ }
+
+ /**
+ * Returns whether or not the vendor settings are being ignored.
+ *
+ * @see #setVendorSettingsIgnored(boolean)
+ */
+ @VisibleForTesting
+ boolean getVendorSettingsIgnored() {
+ return mIgnoreVendorSettings;
+ }
+
+ @Override
+ @NonNull
+ public SettingsEntry getSettings(@NonNull DisplayInfo info) {
+ SettingsEntry vendorSettings = getVendorSettingsEntry(info);
+ SettingsEntry overrideSettings = getOrCreateOverrideSettingsEntry(info);
+ if (vendorSettings == null) {
+ return new SettingsEntry(overrideSettings);
+ } else {
+ SettingsEntry mergedSettings = new SettingsEntry(vendorSettings);
+ mergedSettings.updateFrom(overrideSettings);
+ return mergedSettings;
+ }
+ }
+
+ @Override
+ @NonNull
+ public SettingsEntry getOverrideSettings(@NonNull DisplayInfo info) {
+ return new SettingsEntry(getOrCreateOverrideSettingsEntry(info));
+ }
+
+ @Override
+ public void updateOverrideSettings(@NonNull DisplayInfo info,
+ @NonNull SettingsEntry overrides) {
+ final SettingsEntry overrideSettings = getOrCreateOverrideSettingsEntry(info);
+ boolean changed = overrideSettings.setTo(overrides);
+ if (changed) {
+ writeOverrideSettings();
+ }
+ }
+
+ @Nullable
+ private SettingsEntry getVendorSettingsEntry(DisplayInfo info) {
+ if (mIgnoreVendorSettings) {
+ return null;
+ }
+
+ final String identifier = getIdentifier(info, mVendorIdentifierType);
+ SettingsEntry settings;
+ // Try to get corresponding settings using preferred identifier for the current config.
+ if ((settings = mVendorSettings.get(identifier)) != null) {
+ return settings;
+ }
+ // Else, fall back to the display name.
+ if ((settings = mVendorSettings.get(info.name)) != null) {
+ // Found an entry stored with old identifier.
+ mVendorSettings.remove(info.name);
+ mVendorSettings.put(identifier, settings);
+ return settings;
+ }
+ return null;
+ }
+
+ @NonNull
+ private SettingsEntry getOrCreateOverrideSettingsEntry(DisplayInfo info) {
+ final String identifier = getIdentifier(info, mOverrideIdentifierType);
+ SettingsEntry settings;
+ // Try to get corresponding settings using preferred identifier for the current config.
+ if ((settings = mOverrideSettings.get(identifier)) != null) {
+ return settings;
+ }
+ // Else, fall back to the display name.
+ if ((settings = mOverrideSettings.get(info.name)) != null) {
+ // Found an entry stored with old identifier.
+ mOverrideSettings.remove(info.name);
+ mOverrideSettings.put(identifier, settings);
+ writeOverrideSettings();
+ return settings;
+ }
+
+ settings = new SettingsEntry();
+ mOverrideSettings.put(identifier, settings);
+ return settings;
+ }
+
+ private void readSettings() {
+ FileData vendorFileData = readSettings(mVendorSettingsStorage);
+ if (vendorFileData != null) {
+ mVendorIdentifierType = vendorFileData.mIdentifierType;
+ mVendorSettings.putAll(vendorFileData.mSettings);
+ }
+
+ FileData overrideFileData = readSettings(mOverrideSettingsStorage);
+ if (overrideFileData != null) {
+ mOverrideIdentifierType = overrideFileData.mIdentifierType;
+ mOverrideSettings.putAll(overrideFileData.mSettings);
+ }
+ }
+
+ private void writeOverrideSettings() {
+ FileData fileData = new FileData();
+ fileData.mIdentifierType = mOverrideIdentifierType;
+ fileData.mSettings.putAll(mOverrideSettings);
+ writeSettings(mOverrideSettingsStorage, fileData);
+ }
+
+ /** Gets the identifier of choice for the current config. */
+ private static String getIdentifier(DisplayInfo displayInfo, @DisplayIdentifierType int type) {
+ if (type == IDENTIFIER_PORT && displayInfo.address != null) {
+ // Config suggests using port as identifier for physical displays.
+ if (displayInfo.address instanceof DisplayAddress.Physical) {
+ return "port:" + ((DisplayAddress.Physical) displayInfo.address).getPort();
+ }
+ }
+ return displayInfo.uniqueId;
+ }
+
+ @NonNull
+ private static AtomicFile getVendorSettingsFile() {
+ final File vendorFile = new File(Environment.getVendorDirectory(),
+ VENDOR_DISPLAY_SETTINGS_PATH);
+ return new AtomicFile(vendorFile, WM_DISPLAY_COMMIT_TAG);
+ }
+
+ @NonNull
+ private static AtomicFile getOverrideSettingsFile() {
+ final File overrideSettingsFile = new File(Environment.getDataDirectory(),
+ DATA_DISPLAY_SETTINGS_FILE_PATH);
+ return new AtomicFile(overrideSettingsFile, WM_DISPLAY_COMMIT_TAG);
+ }
+
+ @Nullable
+ private static FileData readSettings(ReadableSettingsStorage storage) {
+ InputStream stream;
+ try {
+ stream = storage.openRead();
+ } catch (IOException e) {
+ Slog.i(TAG, "No existing display settings, starting empty");
+ return null;
+ }
+ FileData fileData = new FileData();
+ boolean success = false;
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, StandardCharsets.UTF_8.name());
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ // Do nothing.
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new IllegalStateException("no start tag found");
+ }
+
+ int outerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("display")) {
+ readDisplay(parser, fileData);
+ } else if (tagName.equals("config")) {
+ readConfig(parser, fileData);
+ } else {
+ Slog.w(TAG, "Unknown element under <display-settings>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ success = true;
+ } catch (IllegalStateException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (NullPointerException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (XmlPullParserException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (IndexOutOfBoundsException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } finally {
+ try {
+ stream.close();
+ } catch (IOException ignored) {
+ }
+ }
+ if (!success) {
+ fileData.mSettings.clear();
+ }
+ return fileData;
+ }
+
+ private static int getIntAttribute(XmlPullParser parser, String name, int defaultValue) {
+ try {
+ final String str = parser.getAttributeValue(null, name);
+ return str != null ? Integer.parseInt(str) : defaultValue;
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "Failed to parse display window settings attribute: " + name, e);
+ return defaultValue;
+ }
+ }
+
+ @Nullable
+ private static Integer getIntegerAttribute(XmlPullParser parser, String name,
+ @Nullable Integer defaultValue) {
+ try {
+ final String str = parser.getAttributeValue(null, name);
+ return str != null ? Integer.valueOf(str) : defaultValue;
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "Failed to parse display window settings attribute: " + name, e);
+ return defaultValue;
+ }
+ }
+
+ @Nullable
+ private static Boolean getBooleanAttribute(XmlPullParser parser, String name,
+ @Nullable Boolean defaultValue) {
+ final String str = parser.getAttributeValue(null, name);
+ return str != null ? Boolean.valueOf(str) : defaultValue;
+ }
+
+ private static void readDisplay(XmlPullParser parser, FileData fileData)
+ throws NumberFormatException, XmlPullParserException, IOException {
+ String name = parser.getAttributeValue(null, "name");
+ if (name != null) {
+ SettingsEntry settingsEntry = new SettingsEntry();
+ settingsEntry.mWindowingMode = getIntAttribute(parser, "windowingMode",
+ WindowConfiguration.WINDOWING_MODE_UNDEFINED /* defaultValue */);
+ settingsEntry.mUserRotationMode = getIntegerAttribute(parser, "userRotationMode",
+ null /* defaultValue */);
+ settingsEntry.mUserRotation = getIntegerAttribute(parser, "userRotation",
+ null /* defaultValue */);
+ settingsEntry.mForcedWidth = getIntAttribute(parser, "forcedWidth",
+ 0 /* defaultValue */);
+ settingsEntry.mForcedHeight = getIntAttribute(parser, "forcedHeight",
+ 0 /* defaultValue */);
+ settingsEntry.mForcedDensity = getIntAttribute(parser, "forcedDensity",
+ 0 /* defaultValue */);
+ settingsEntry.mForcedScalingMode = getIntegerAttribute(parser, "forcedScalingMode",
+ null /* defaultValue */);
+ settingsEntry.mRemoveContentMode = getIntAttribute(parser, "removeContentMode",
+ REMOVE_CONTENT_MODE_UNDEFINED /* defaultValue */);
+ settingsEntry.mShouldShowWithInsecureKeyguard = getBooleanAttribute(parser,
+ "shouldShowWithInsecureKeyguard", null /* defaultValue */);
+ settingsEntry.mShouldShowSystemDecors = getBooleanAttribute(parser,
+ "shouldShowSystemDecors", null /* defaultValue */);
+ settingsEntry.mShouldShowIme = getBooleanAttribute(parser, "shouldShowIme",
+ null /* defaultValue */);
+ settingsEntry.mFixedToUserRotation = getIntegerAttribute(parser, "fixedToUserRotation",
+ null /* defaultValue */);
+ settingsEntry.mIgnoreOrientationRequest = getBooleanAttribute(parser,
+ "ignoreOrientationRequest", null /* defaultValue */);
+ fileData.mSettings.put(name, settingsEntry);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+
+ private static void readConfig(XmlPullParser parser, FileData fileData)
+ throws NumberFormatException,
+ XmlPullParserException, IOException {
+ fileData.mIdentifierType = getIntAttribute(parser, "identifier",
+ IDENTIFIER_UNIQUE_ID);
+ XmlUtils.skipCurrentTag(parser);
+ }
+
+ private static void writeSettings(WritableSettingsStorage storage, FileData data) {
+ OutputStream stream;
+ try {
+ stream = storage.startWrite();
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to write display settings: " + e);
+ return;
+ }
+
+ boolean success = false;
+ try {
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, StandardCharsets.UTF_8.name());
+ out.startDocument(null, true);
+
+ out.startTag(null, "display-settings");
+
+ out.startTag(null, "config");
+ out.attribute(null, "identifier",
+ Integer.toString(data.mIdentifierType));
+ out.endTag(null, "config");
+
+ for (Map.Entry<String, SettingsEntry> entry
+ : data.mSettings.entrySet()) {
+ String displayIdentifier = entry.getKey();
+ SettingsEntry settingsEntry = entry.getValue();
+ if (settingsEntry.isEmpty()) {
+ continue;
+ }
+
+ out.startTag(null, "display");
+ out.attribute(null, "name", displayIdentifier);
+ if (settingsEntry.mWindowingMode != WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
+ out.attribute(null, "windowingMode",
+ Integer.toString(settingsEntry.mWindowingMode));
+ }
+ if (settingsEntry.mUserRotationMode != null) {
+ out.attribute(null, "userRotationMode",
+ settingsEntry.mUserRotationMode.toString());
+ }
+ if (settingsEntry.mUserRotation != null) {
+ out.attribute(null, "userRotation",
+ settingsEntry.mUserRotation.toString());
+ }
+ if (settingsEntry.mForcedWidth != 0 && settingsEntry.mForcedHeight != 0) {
+ out.attribute(null, "forcedWidth",
+ Integer.toString(settingsEntry.mForcedWidth));
+ out.attribute(null, "forcedHeight",
+ Integer.toString(settingsEntry.mForcedHeight));
+ }
+ if (settingsEntry.mForcedDensity != 0) {
+ out.attribute(null, "forcedDensity",
+ Integer.toString(settingsEntry.mForcedDensity));
+ }
+ if (settingsEntry.mForcedScalingMode != null) {
+ out.attribute(null, "forcedScalingMode",
+ settingsEntry.mForcedScalingMode.toString());
+ }
+ if (settingsEntry.mRemoveContentMode != REMOVE_CONTENT_MODE_UNDEFINED) {
+ out.attribute(null, "removeContentMode",
+ Integer.toString(settingsEntry.mRemoveContentMode));
+ }
+ if (settingsEntry.mShouldShowWithInsecureKeyguard != null) {
+ out.attribute(null, "shouldShowWithInsecureKeyguard",
+ settingsEntry.mShouldShowWithInsecureKeyguard.toString());
+ }
+ if (settingsEntry.mShouldShowSystemDecors != null) {
+ out.attribute(null, "shouldShowSystemDecors",
+ settingsEntry.mShouldShowSystemDecors.toString());
+ }
+ if (settingsEntry.mShouldShowIme != null) {
+ out.attribute(null, "shouldShowIme",
+ settingsEntry.mShouldShowIme.toString());
+ }
+ if (settingsEntry.mFixedToUserRotation != null) {
+ out.attribute(null, "fixedToUserRotation",
+ settingsEntry.mFixedToUserRotation.toString());
+ }
+ if (settingsEntry.mIgnoreOrientationRequest != null) {
+ out.attribute(null, "ignoreOrientationRequest",
+ settingsEntry.mIgnoreOrientationRequest.toString());
+ }
+ out.endTag(null, "display");
+ }
+
+ out.endTag(null, "display-settings");
+ out.endDocument();
+ success = true;
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to write display window settings.", e);
+ } finally {
+ storage.finishWrite(stream, success);
+ }
+ }
+
+ private static final class FileData {
+ int mIdentifierType;
+ final Map<String, SettingsEntry> mSettings = new HashMap<>();
+
+ @Override
+ public String toString() {
+ return "FileData{"
+ + "mIdentifierType=" + mIdentifierType
+ + ", mSettings=" + mSettings
+ + '}';
+ }
+ }
+
+ private static final class AtomicFileStorage implements WritableSettingsStorage {
+ private final AtomicFile mAtomicFile;
+
+ AtomicFileStorage(@NonNull AtomicFile atomicFile) {
+ mAtomicFile = atomicFile;
+ }
+
+ @Override
+ public InputStream openRead() throws FileNotFoundException {
+ return mAtomicFile.openRead();
+ }
+
+ @Override
+ public OutputStream startWrite() throws IOException {
+ return mAtomicFile.startWrite();
+ }
+
+ @Override
+ public void finishWrite(OutputStream os, boolean success) {
+ if (!(os instanceof FileOutputStream)) {
+ throw new IllegalArgumentException("Unexpected OutputStream as argument: " + os);
+ }
+ FileOutputStream fos = (FileOutputStream) os;
+ if (success) {
+ mAtomicFile.finishWrite(fos);
+ } else {
+ mAtomicFile.failWrite(fos);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 2ea4b57..8c80205 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -277,9 +277,8 @@
mInputEventReceiver = new DragInputEventReceiver(mClientChannel,
mService.mH.getLooper(), mDragDropController);
- mDragApplicationHandle = new InputApplicationHandle(new Binder());
- mDragApplicationHandle.name = "drag";
- mDragApplicationHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+ mDragApplicationHandle = new InputApplicationHandle(new Binder(), "drag",
+ DEFAULT_DISPATCHING_TIMEOUT_MILLIS);
mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle,
display.getDisplayId());
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index 3b89a24..b08d6e1 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -175,11 +175,11 @@
InputApplicationHandle getApplicationHandle() {
if (mHostWindowState == null
- || mHostWindowState.mInputWindowHandle.inputApplicationHandle == null) {
+ || mHostWindowState.mInputWindowHandle.getInputApplicationHandle() == null) {
return null;
}
return new InputApplicationHandle(
- mHostWindowState.mInputWindowHandle.inputApplicationHandle);
+ mHostWindowState.mInputWindowHandle.getInputApplicationHandle());
}
InputChannel openInputChannel() {
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 0813b4f..818d96c 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -16,11 +16,14 @@
package com.android.server.wm;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;
import static com.android.server.wm.ImeInsetsSourceProviderProto.IME_TARGET_FROM_IME;
import static com.android.server.wm.ImeInsetsSourceProviderProto.INSETS_SOURCE_PROVIDER;
import static com.android.server.wm.ImeInsetsSourceProviderProto.IS_IME_LAYOUT_DRAWN;
+import android.os.Trace;
import android.util.proto.ProtoOutputStream;
import android.view.InsetsSource;
import android.view.WindowInsets;
@@ -79,6 +82,7 @@
ProtoLog.i(WM_DEBUG_IME, "call showInsets(ime) on %s",
target.getWindow() != null ? target.getWindow().getName() : "");
target.showInsets(WindowInsets.Type.ime(), true /* fromIme */);
+ Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "WMS.showImePostLayout", 0);
if (target != mImeTargetFromIme && mImeTargetFromIme != null) {
ProtoLog.w(WM_DEBUG_IME,
"showInsets(ime) was requested by different window: %s ",
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index edb5e85..e35621a 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -63,9 +63,8 @@
mClientChannel.copyTo(inputChannel);
}
- mApplicationHandle = new InputApplicationHandle(new Binder());
- mApplicationHandle.name = name;
- mApplicationHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+ mApplicationHandle = new InputApplicationHandle(new Binder(), name,
+ DEFAULT_DISPATCHING_TIMEOUT_MILLIS);
mWindowHandle = new InputWindowHandle(mApplicationHandle, displayId);
mWindowHandle.name = name;
@@ -160,9 +159,11 @@
public void binderDied() {
synchronized (mService.getWindowManagerLock()) {
// Clean up the input consumer
- final InputMonitor inputMonitor =
- mService.mRoot.getDisplayContent(mWindowHandle.displayId).getInputMonitor();
- inputMonitor.destroyInputConsumer(mName);
+ final DisplayContent dc = mService.mRoot.getDisplayContent(mWindowHandle.displayId);
+ if (dc == null) {
+ return;
+ }
+ dc.getInputMonitor().destroyInputConsumer(mName);
unlinkFromDeathRecipient();
}
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 4a54196..43c4741 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -48,6 +48,7 @@
import static com.android.server.wm.WindowManagerService.LOGTAG_INPUT_FOCUS;
import android.graphics.Rect;
+import android.graphics.Region;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -57,12 +58,12 @@
import android.util.ArrayMap;
import android.util.EventLog;
import android.util.Slog;
-import android.view.InputApplicationHandle;
import android.view.InputChannel;
import android.view.InputEventReceiver;
import android.view.InputWindowHandle;
import android.view.SurfaceControl;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import java.io.PrintWriter;
@@ -81,7 +82,7 @@
private boolean mUpdateInputWindowsImmediately;
private boolean mDisableWallpaperTouchEvents;
- private final Rect mTmpRect = new Rect();
+ private final Region mTmpRegion = new Region();
private final UpdateInputForAllWindowsConsumer mUpdateInputForAllWindowsConsumer;
private final int mDisplayId;
@@ -276,66 +277,66 @@
addInputConsumer(name, consumer);
}
-
- void populateInputWindowHandle(final InputWindowHandle inputWindowHandle,
- final WindowState child, int flags, final int type, final boolean isVisible,
- final boolean focusable, final boolean hasWallpaper) {
+ @VisibleForTesting
+ void populateInputWindowHandle(final InputWindowHandleWrapper inputWindowHandle,
+ final WindowState w) {
// Add a window to our list of input windows.
- inputWindowHandle.name = child.toString();
- flags = child.getSurfaceTouchableRegion(inputWindowHandle, flags);
- inputWindowHandle.layoutParamsFlags = flags;
- inputWindowHandle.layoutParamsType = type;
- inputWindowHandle.dispatchingTimeoutMillis = child.getInputDispatchingTimeoutMillis();
- inputWindowHandle.visible = isVisible;
- inputWindowHandle.focusable = focusable;
- inputWindowHandle.touchOcclusionMode = child.getTouchOcclusionMode();
- inputWindowHandle.hasWallpaper = hasWallpaper;
- inputWindowHandle.paused = child.mActivityRecord != null ? child.mActivityRecord.paused : false;
- inputWindowHandle.ownerPid = child.mSession.mPid;
- inputWindowHandle.ownerUid = child.mSession.mUid;
- inputWindowHandle.packageName = child.getOwningPackage();
- inputWindowHandle.inputFeatures = child.mAttrs.inputFeatures;
- inputWindowHandle.displayId = child.getDisplayId();
+ inputWindowHandle.setInputApplicationHandle(w.mActivityRecord != null
+ ? w.mActivityRecord.getInputApplicationHandle(false /* update */) : null);
+ inputWindowHandle.setToken(w.mInputChannelToken);
+ inputWindowHandle.setDispatchingTimeoutMillis(w.getInputDispatchingTimeoutMillis());
+ inputWindowHandle.setTouchOcclusionMode(w.getTouchOcclusionMode());
+ inputWindowHandle.setInputFeatures(w.mAttrs.inputFeatures);
+ inputWindowHandle.setPaused(w.mActivityRecord != null && w.mActivityRecord.paused);
+ inputWindowHandle.setVisible(w.isVisible());
- final Rect frame = child.getFrame();
- inputWindowHandle.frameLeft = frame.left;
- inputWindowHandle.frameTop = frame.top;
- inputWindowHandle.frameRight = frame.right;
- inputWindowHandle.frameBottom = frame.bottom;
+ final boolean focusable = w.canReceiveKeys()
+ && (mService.mPerDisplayFocusEnabled || mDisplayContent.isOnTop());
+ inputWindowHandle.setFocusable(focusable);
+
+ final boolean hasWallpaper = mDisplayContent.mWallpaperController.isWallpaperTarget(w)
+ && !mService.mPolicy.isKeyguardShowing()
+ && !mDisableWallpaperTouchEvents;
+ inputWindowHandle.setHasWallpaper(hasWallpaper);
+
+ final Rect frame = w.getFrame();
+ inputWindowHandle.setFrame(frame.left, frame.top, frame.right, frame.bottom);
// Surface insets are hardcoded to be the same in all directions
// and we could probably deprecate the "left/right/top/bottom" concept.
// we avoid reintroducing this concept by just choosing one of them here.
- inputWindowHandle.surfaceInset = child.getAttrs().surfaceInsets.left;
+ inputWindowHandle.setSurfaceInset(w.mAttrs.surfaceInsets.left);
- /**
- * If the window is in a TaskManaged by a TaskOrganizer then most cropping
- * will be applied using the SurfaceControl hierarchy from the Organizer.
- * This means we need to make sure that these changes in crop are reflected
- * in the input windows, and so ensure this flag is set so that
- * the input crop always reflects the surface hierarchy.
- *
- * TODO(b/168252846): we have some issues with modal-windows, so we need to
- * cross that bridge now that we organize full-screen Tasks.
- */
- if (child.getTask() != null
- && child.getTask().isOrganized()
- && child.getTask().getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
- inputWindowHandle.replaceTouchableRegionWithCrop(null /* Use this surfaces crop */);
+ // If we are scaling the window, input coordinates need to be inversely scaled to map from
+ // what is on screen to what is actually being touched in the UI.
+ inputWindowHandle.setScaleFactor(w.mGlobalScale != 1f ? (1f / w.mGlobalScale) : 1f);
+
+ final int flags = w.getSurfaceTouchableRegion(mTmpRegion, w.mAttrs.flags);
+ inputWindowHandle.setTouchableRegion(mTmpRegion);
+ inputWindowHandle.setLayoutParamsFlags(flags);
+
+ boolean useSurfaceCrop = false;
+ final Task task = w.getTask();
+ if (task != null) {
+ if (task.isOrganized() && task.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
+ // If the window is in a TaskManaged by a TaskOrganizer then most cropping will
+ // be applied using the SurfaceControl hierarchy from the Organizer. This means
+ // we need to make sure that these changes in crop are reflected in the input
+ // windows, and so ensure this flag is set so that the input crop always reflects
+ // the surface hierarchy.
+ // TODO(b/168252846): we have some issues with modal-windows, so we need to cross
+ // that bridge now that we organize full-screen Tasks.
+ inputWindowHandle.replaceTouchableRegionWithCrop(null /* Use this surfaces crop */);
+ useSurfaceCrop = true;
+ } else if (task.cropWindowsToStackBounds() && !w.inFreeformWindowingMode()) {
+ inputWindowHandle.replaceTouchableRegionWithCrop(
+ task.getRootTask().getSurfaceControl());
+ useSurfaceCrop = true;
+ }
}
-
- if (child.mGlobalScale != 1) {
- // If we are scaling the window, input coordinates need
- // to be inversely scaled to map from what is on screen
- // to what is actually being touched in the UI.
- inputWindowHandle.scaleFactor = 1.0f/child.mGlobalScale;
- } else {
- inputWindowHandle.scaleFactor = 1;
- }
-
- if (DEBUG_INPUT) {
- Slog.d(TAG_WM, "addInputWindowHandle: "
- + child + ", " + inputWindowHandle);
+ if (!useSurfaceCrop) {
+ inputWindowHandle.setReplaceTouchableRegionWithCrop(false);
+ inputWindowHandle.setTouchableRegionCrop(null);
}
}
@@ -401,15 +402,8 @@
public void setFocusedAppLw(ActivityRecord newApp) {
// Focused app has changed.
- if (newApp == null) {
- mService.mInputManager.setFocusedApplication(mDisplayId, null);
- } else {
- final InputApplicationHandle handle = newApp.mInputApplicationHandle;
- handle.name = newApp.toString();
- handle.dispatchingTimeoutMillis = newApp.mInputDispatchingTimeoutMillis;
-
- mService.mInputManager.setFocusedApplication(mDisplayId, handle);
- }
+ mService.mInputManager.setFocusedApplication(mDisplayId,
+ newApp != null ? newApp.getInputApplicationHandle(true /* update */) : null);
}
public void pauseDispatchingLw(WindowToken window) {
@@ -456,10 +450,6 @@
private boolean mAddRecentsAnimationInputConsumerHandle;
boolean mInDrag;
- WallpaperController mWallpaperController;
-
- // An invalid window handle that tells SurfaceFlinger not update the input info.
- final InputWindowHandle mInvalidInputWindow = new InputWindowHandle(null, mDisplayId);
private void updateInputWindows(boolean inDrag) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateInputWindows");
@@ -474,10 +464,8 @@
mAddWallpaperInputConsumerHandle = mWallpaperInputConsumer != null;
mAddRecentsAnimationInputConsumerHandle = mRecentsAnimationInputConsumer != null;
- mTmpRect.setEmpty();
mDisableWallpaperTouchEvents = false;
mInDrag = inDrag;
- mWallpaperController = mDisplayContent.mWallpaperController;
resetInputConsumers(mInputTransaction);
@@ -499,7 +487,7 @@
}
final WindowState focus = mDisplayContent.mCurrentFocus;
- if (focus == null || focus.mInputWindowHandle.token == null) {
+ if (focus == null || focus.mInputChannelToken == null) {
mDisplayContent.mLastRequestedFocus = focus;
return;
}
@@ -510,7 +498,7 @@
return;
}
- mInputTransaction.setFocusedWindow(focus.mInputWindowHandle.token, mDisplayId);
+ mInputTransaction.setFocusedWindow(focus.mInputChannelToken, mDisplayId);
EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
"Focus request " + focus, "reason=UpdateInputWindows");
mDisplayContent.mLastRequestedFocus = focus;
@@ -519,33 +507,26 @@
@Override
public void accept(WindowState w) {
- final InputChannel inputChannel = w.mInputChannel;
- final InputWindowHandle inputWindowHandle = w.mInputWindowHandle;
+ final InputWindowHandleWrapper inputWindowHandle = w.mInputWindowHandle;
final RecentsAnimationController recentsAnimationController =
mService.getRecentsAnimationController();
final boolean shouldApplyRecentsInputConsumer = recentsAnimationController != null
&& recentsAnimationController.shouldApplyInputConsumer(w.mActivityRecord);
- final int type = w.mAttrs.type;
- final boolean isVisible = w.isVisibleLw();
- if (inputChannel == null || inputWindowHandle == null || w.mRemoved
+ if (w.mInputChannelToken == null || w.mRemoved
|| (!w.canReceiveTouchInput() && !shouldApplyRecentsInputConsumer)) {
if (w.mWinAnimator.hasSurface()) {
// Assign an InputInfo with type to the overlay window which can't receive input
// event. This is used to omit Surfaces from occlusion detection.
- populateOverlayInputInfo(mInvalidInputWindow, w.getName(), type, isVisible);
- mInputTransaction.setInputWindowInfo(
- w.mWinAnimator.mSurfaceController.mSurfaceControl,
- mInvalidInputWindow);
+ populateOverlayInputInfo(inputWindowHandle, w.isVisible());
+ setInputWindowInfoIfNeeded(mInputTransaction,
+ w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle);
return;
}
// Skip this window because it cannot possibly receive input.
return;
}
- final int flags = w.mAttrs.flags;
final int privateFlags = w.mAttrs.privateFlags;
- final boolean focusable = w.canReceiveKeys()
- && (mService.mPerDisplayFocusEnabled || mDisplayContent.isOnTop());
if (mAddRecentsAnimationInputConsumerHandle && shouldApplyRecentsInputConsumer) {
if (recentsAnimationController.updateInputConsumerForApp(
@@ -584,47 +565,53 @@
if ((privateFlags & PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS) != 0) {
mDisableWallpaperTouchEvents = true;
}
- final boolean hasWallpaper = mWallpaperController.isWallpaperTarget(w)
- && !mService.mPolicy.isKeyguardShowing()
- && !mDisableWallpaperTouchEvents;
// If there's a drag in progress and 'child' is a potential drop target,
// make sure it's been told about the drag
- if (mInDrag && isVisible && w.getDisplayContent().isDefaultDisplay) {
+ if (mInDrag && w.isVisible() && w.getDisplayContent().isDefaultDisplay) {
mService.mDragDropController.sendDragStartedIfNeededLocked(w);
}
- populateInputWindowHandle(
- inputWindowHandle, w, flags, type, isVisible, focusable, hasWallpaper);
-
// register key interception info
- mService.mKeyInterceptionInfoForToken.put(inputWindowHandle.token,
+ mService.mKeyInterceptionInfoForToken.put(w.mInputChannelToken,
w.getKeyInterceptionInfo());
if (w.mWinAnimator.hasSurface()) {
- mInputTransaction.setInputWindowInfo(
+ populateInputWindowHandle(inputWindowHandle, w);
+ setInputWindowInfoIfNeeded(mInputTransaction,
w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle);
}
}
}
+ @VisibleForTesting
+ static void setInputWindowInfoIfNeeded(SurfaceControl.Transaction t, SurfaceControl sc,
+ InputWindowHandleWrapper inputWindowHandle) {
+ if (DEBUG_INPUT) {
+ Slog.d(TAG_WM, "Update InputWindowHandle: " + inputWindowHandle);
+ }
+ if (inputWindowHandle.isChanged()) {
+ inputWindowHandle.applyChangesToSurface(t, sc);
+ }
+ }
+
// This would reset InputWindowHandle fields to prevent it could be found by input event.
// We need to check if any new field of InputWindowHandle could impact the result.
- private static void populateOverlayInputInfo(final InputWindowHandle inputWindowHandle,
- final String name, final int type, final boolean isVisible) {
- inputWindowHandle.name = name;
- inputWindowHandle.layoutParamsType = type;
- inputWindowHandle.dispatchingTimeoutMillis = 0; // it should never receive input
- inputWindowHandle.visible = isVisible;
- inputWindowHandle.focusable = false;
- inputWindowHandle.inputFeatures = INPUT_FEATURE_NO_INPUT_CHANNEL;
- inputWindowHandle.scaleFactor = 1;
- inputWindowHandle.layoutParamsFlags =
- FLAG_NOT_TOUCH_MODAL | FLAG_NOT_TOUCHABLE | FLAG_NOT_FOCUSABLE;
- inputWindowHandle.portalToDisplayId = INVALID_DISPLAY;
- inputWindowHandle.touchableRegion.setEmpty();
+ @VisibleForTesting
+ static void populateOverlayInputInfo(InputWindowHandleWrapper inputWindowHandle,
+ boolean isVisible) {
+ inputWindowHandle.setDispatchingTimeoutMillis(0); // It should never receive input.
+ inputWindowHandle.setVisible(isVisible);
+ inputWindowHandle.setFocusable(false);
+ inputWindowHandle.setInputFeatures(INPUT_FEATURE_NO_INPUT_CHANNEL);
+ // The input window handle without input channel must not have a token.
+ inputWindowHandle.setToken(null);
+ inputWindowHandle.setScaleFactor(1f);
+ inputWindowHandle.setLayoutParamsFlags(
+ FLAG_NOT_TOUCH_MODAL | FLAG_NOT_TOUCHABLE | FLAG_NOT_FOCUSABLE);
+ inputWindowHandle.setPortalToDisplayId(INVALID_DISPLAY);
+ inputWindowHandle.clearTouchableRegion();
inputWindowHandle.setTouchableRegionCrop(null);
- inputWindowHandle.trustedOverlay = isTrustedOverlay(type);
}
/**
@@ -635,9 +622,13 @@
*/
static void setTrustedOverlayInputInfo(SurfaceControl sc, SurfaceControl.Transaction t,
int displayId, String name) {
- InputWindowHandle inputWindowHandle = new InputWindowHandle(null, displayId);
- populateOverlayInputInfo(inputWindowHandle, name, TYPE_SECURE_SYSTEM_OVERLAY, true);
- t.setInputWindowInfo(sc, inputWindowHandle);
+ final InputWindowHandleWrapper inputWindowHandle = new InputWindowHandleWrapper(
+ new InputWindowHandle(null /* inputApplicationHandle */, displayId));
+ inputWindowHandle.setName(name);
+ inputWindowHandle.setLayoutParamsType(TYPE_SECURE_SYSTEM_OVERLAY);
+ inputWindowHandle.setTrustedOverlay(true);
+ populateOverlayInputInfo(inputWindowHandle, true /* isVisible */);
+ setInputWindowInfoIfNeeded(t, sc, inputWindowHandle);
}
static boolean isTrustedOverlay(int type) {
diff --git a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
new file mode 100644
index 0000000..1fbeb1f
--- /dev/null
+++ b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Region;
+import android.os.IBinder;
+import android.view.InputApplicationHandle;
+import android.view.InputWindowHandle;
+import android.view.SurfaceControl;
+
+import java.util.Objects;
+
+/**
+ * The wrapper of {@link InputWindowHandle} with field change detection to reduce unnecessary
+ * updates to surface, e.g. if there are no changes, then skip invocation of
+ * {@link SurfaceControl.Transaction#setInputWindowInfo(SurfaceControl, InputWindowHandle)}.
+ */
+class InputWindowHandleWrapper {
+ /** The wrapped handle should not be directly exposed to avoid untracked changes. */
+ private final @NonNull InputWindowHandle mHandle;
+
+ /** Whether the {@link #mHandle} is changed. */
+ private boolean mChanged = true;
+
+ InputWindowHandleWrapper(@NonNull InputWindowHandle handle) {
+ mHandle = handle;
+ }
+
+ /**
+ * Returns {@code true} if the input window handle has changed since the last invocation of
+ * {@link #applyChangesToSurface(SurfaceControl.Transaction, SurfaceControl)}}
+ */
+ boolean isChanged() {
+ return mChanged;
+ }
+
+ void forceChange() {
+ mChanged = true;
+ }
+
+ void applyChangesToSurface(@NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl sc) {
+ t.setInputWindowInfo(sc, mHandle);
+ mChanged = false;
+ }
+
+ int getDisplayId() {
+ return mHandle.displayId;
+ }
+
+ InputApplicationHandle getInputApplicationHandle() {
+ return mHandle.inputApplicationHandle;
+ }
+
+ void setInputApplicationHandle(InputApplicationHandle handle) {
+ if (mHandle.inputApplicationHandle == handle) {
+ return;
+ }
+ mHandle.inputApplicationHandle = handle;
+ mChanged = true;
+ }
+
+ void setToken(IBinder token) {
+ if (mHandle.token == token) {
+ return;
+ }
+ mHandle.token = token;
+ mChanged = true;
+ }
+
+ void setName(String name) {
+ if (Objects.equals(mHandle.name, name)) {
+ return;
+ }
+ mHandle.name = name;
+ mChanged = true;
+ }
+
+ void setLayoutParamsFlags(int flags) {
+ if (mHandle.layoutParamsFlags == flags) {
+ return;
+ }
+ mHandle.layoutParamsFlags = flags;
+ mChanged = true;
+ }
+
+ void setLayoutParamsType(int type) {
+ if (mHandle.layoutParamsType == type) {
+ return;
+ }
+ mHandle.layoutParamsType = type;
+ mChanged = true;
+ }
+
+ void setDispatchingTimeoutMillis(long timeout) {
+ if (mHandle.dispatchingTimeoutMillis == timeout) {
+ return;
+ }
+ mHandle.dispatchingTimeoutMillis = timeout;
+ mChanged = true;
+ }
+
+ void setTouchableRegion(Region region) {
+ if (mHandle.touchableRegion.equals(region)) {
+ return;
+ }
+ mHandle.touchableRegion.set(region);
+ mChanged = true;
+ }
+
+ void clearTouchableRegion() {
+ if (mHandle.touchableRegion.isEmpty()) {
+ return;
+ }
+ mHandle.touchableRegion.setEmpty();
+ mChanged = true;
+ }
+
+ void setVisible(boolean visible) {
+ if (mHandle.visible == visible) {
+ return;
+ }
+ mHandle.visible = visible;
+ mChanged = true;
+ }
+
+ void setFocusable(boolean focusable) {
+ if (mHandle.focusable == focusable) {
+ return;
+ }
+ mHandle.focusable = focusable;
+ mChanged = true;
+ }
+
+ void setTouchOcclusionMode(int mode) {
+ if (mHandle.touchOcclusionMode == mode) {
+ return;
+ }
+ mHandle.touchOcclusionMode = mode;
+ mChanged = true;
+ }
+
+ void setHasWallpaper(boolean hasWallpaper) {
+ if (mHandle.hasWallpaper == hasWallpaper) {
+ return;
+ }
+ mHandle.hasWallpaper = hasWallpaper;
+ mChanged = true;
+ }
+
+ void setPaused(boolean paused) {
+ if (mHandle.paused == paused) {
+ return;
+ }
+ mHandle.paused = paused;
+ mChanged = true;
+ }
+
+ void setTrustedOverlay(boolean trustedOverlay) {
+ if (mHandle.trustedOverlay == trustedOverlay) {
+ return;
+ }
+ mHandle.trustedOverlay = trustedOverlay;
+ mChanged = true;
+ }
+
+ void setOwnerPid(int pid) {
+ if (mHandle.ownerPid == pid) {
+ return;
+ }
+ mHandle.ownerPid = pid;
+ mChanged = true;
+ }
+
+ void setOwnerUid(int uid) {
+ if (mHandle.ownerUid == uid) {
+ return;
+ }
+ mHandle.ownerUid = uid;
+ mChanged = true;
+ }
+
+ void setPackageName(String packageName) {
+ if (Objects.equals(mHandle.packageName, packageName)) {
+ return;
+ }
+ mHandle.packageName = packageName;
+ mChanged = true;
+ }
+
+ void setInputFeatures(int features) {
+ if (mHandle.inputFeatures == features) {
+ return;
+ }
+ mHandle.inputFeatures = features;
+ mChanged = true;
+ }
+
+ void setDisplayId(int displayId) {
+ if (mHandle.displayId == displayId) {
+ return;
+ }
+ mHandle.displayId = displayId;
+ mChanged = true;
+ }
+
+ void setPortalToDisplayId(int displayId) {
+ if (mHandle.portalToDisplayId == displayId) {
+ return;
+ }
+ mHandle.portalToDisplayId = displayId;
+ mChanged = true;
+ }
+
+ void setFrame(int left, int top, int right, int bottom) {
+ if (mHandle.frameLeft == left && mHandle.frameTop == top && mHandle.frameRight == right
+ && mHandle.frameBottom == bottom) {
+ return;
+ }
+ mHandle.frameLeft = left;
+ mHandle.frameTop = top;
+ mHandle.frameRight = right;
+ mHandle.frameBottom = bottom;
+ mChanged = true;
+ }
+
+ void setSurfaceInset(int inset) {
+ if (mHandle.surfaceInset == inset) {
+ return;
+ }
+ mHandle.surfaceInset = inset;
+ mChanged = true;
+ }
+
+ void setScaleFactor(float scale) {
+ if (mHandle.scaleFactor == scale) {
+ return;
+ }
+ mHandle.scaleFactor = scale;
+ mChanged = true;
+ }
+
+ void replaceTouchableRegionWithCrop(@Nullable SurfaceControl bounds) {
+ setTouchableRegionCrop(bounds);
+ setReplaceTouchableRegionWithCrop(true);
+ }
+
+ void setTouchableRegionCrop(@Nullable SurfaceControl bounds) {
+ if (mHandle.touchableRegionSurfaceControl.get() == bounds) {
+ return;
+ }
+ mHandle.setTouchableRegionCrop(bounds);
+ mChanged = true;
+ }
+
+ void setReplaceTouchableRegionWithCrop(boolean replace) {
+ if (mHandle.replaceTouchableRegionWithCrop == replace) {
+ return;
+ }
+ mHandle.replaceTouchableRegionWithCrop = replace;
+ mChanged = true;
+ }
+
+ @Override
+ public String toString() {
+ return mHandle + ", changed=" + mChanged;
+ }
+}
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index e7f140f..773bf54 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -18,6 +18,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
@@ -35,6 +36,7 @@
import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.app.WindowConfiguration.WindowingMode;
+import android.os.Trace;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -281,6 +283,7 @@
* Called when a layout pass has occurred.
*/
void onPostLayout() {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "ISC.onPostLayout");
for (int i = mProviders.size() - 1; i >= 0; i--) {
mProviders.valueAt(i).onPostLayout();
}
@@ -297,6 +300,7 @@
}
}
winInsetsChanged.clear();
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
void onInsetsModified(InsetsControlTarget caller) {
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 79b88d8..de2164d 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -167,7 +167,8 @@
if (keyguardChanged) {
// Irrelevant to AOD.
- dismissMultiWindowModeForTaskIfNeeded(null /* currentTaskControllsingOcclusion */);
+ dismissMultiWindowModeForTaskIfNeeded(null /* currentTaskControllsingOcclusion */,
+ false /* turningScreenOn */);
setKeyguardGoingAway(false);
if (keyguardShowing) {
mDismissalRequested = false;
@@ -369,7 +370,6 @@
mService.continueWindowLayout();
}
}
- dismissMultiWindowModeForTaskIfNeeded(currentTaskControllingOcclusion);
}
/**
@@ -398,6 +398,21 @@
}
}
+ /**
+ * Called when somebody wants to turn screen on.
+ */
+ private void handleTurnScreenOn(int displayId) {
+ if (displayId != DEFAULT_DISPLAY) {
+ return;
+ }
+
+ mStackSupervisor.wakeUp("handleTurnScreenOn");
+ if (mKeyguardShowing && canDismissKeyguard()) {
+ mWindowManager.dismissKeyguard(null /* callback */, null /* message */);
+ mDismissalRequested = true;
+ }
+ }
+
boolean isDisplayOccluded(int displayId) {
return getDisplayState(displayId).mOccluded;
}
@@ -433,14 +448,15 @@
}
private void dismissMultiWindowModeForTaskIfNeeded(
- @Nullable Task currentTaskControllingOcclusion) {
+ @Nullable Task currentTaskControllingOcclusion, boolean turningScreenOn) {
+ // If turningScreenOn is true, it means that the visibility state has changed from
+ // currentTaskControllingOcclusion and we should update windowing mode.
// TODO(b/113840485): Handle docked stack for individual display.
- if (!mKeyguardShowing || !isDisplayOccluded(DEFAULT_DISPLAY)) {
+ if (!turningScreenOn && (!mKeyguardShowing || !isDisplayOccluded(DEFAULT_DISPLAY))) {
return;
}
// Dismiss split screen
-
// The lock screen is currently showing, but is occluded by a window that can
// 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
@@ -579,17 +595,26 @@
&& controller.mWindowManager.isKeyguardSecure(
controller.mService.getCurrentUserId());
+ boolean occludingChange = false;
+ boolean turningScreenOn = false;
if (mTopTurnScreenOnActivity != lastTurnScreenOnActivity
&& mTopTurnScreenOnActivity != null
&& !mService.mWindowManager.mPowerManager.isInteractive()
- && (mRequestDismissKeyguard || occludedByActivity)) {
- controller.mStackSupervisor.wakeUp("handleTurnScreenOn");
+ && (mRequestDismissKeyguard || occludedByActivity
+ || controller.canDismissKeyguard())) {
+ turningScreenOn = true;
+ controller.handleTurnScreenOn(mDisplayId);
mTopTurnScreenOnActivity.setCurrentLaunchCanTurnScreenOn(false);
}
if (lastOccluded != mOccluded) {
+ occludingChange = true;
controller.handleOccludedChanged(mDisplayId, task);
}
+
+ if (occludingChange || turningScreenOn) {
+ controller.dismissMultiWindowModeForTaskIfNeeded(task, turningScreenOn);
+ }
}
/**
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index b33c2f2..5b7b5a1 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -24,6 +24,8 @@
import static android.content.Context.STATUS_BAR_SERVICE;
import static android.content.Intent.ACTION_CALL_EMERGENCY;
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_ALLOWLISTED;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
import static android.os.UserHandle.USER_ALL;
import static android.os.UserHandle.USER_CURRENT;
@@ -33,11 +35,6 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_ALLOWLISTED;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_DONT_LOCK;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_PINNABLE;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -129,6 +126,18 @@
/** Tag used for disabling of keyguard */
private static final String LOCK_TASK_TAG = "Lock-to-App";
+ /** Can't be put in lockTask mode. */
+ static final int LOCK_TASK_AUTH_DONT_LOCK = 0;
+ /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
+ static final int LOCK_TASK_AUTH_PINNABLE = 1;
+ /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
+ static final int LOCK_TASK_AUTH_LAUNCHABLE = 2;
+ /** Can enter lockTask without user approval. Can start over existing lockTask task. */
+ static final int LOCK_TASK_AUTH_ALLOWLISTED = 3;
+ /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
+ * lockTask task. */
+ static final int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
+
private final IBinder mToken = new LockTaskToken();
private final ActivityStackSupervisor mSupervisor;
private final Context mContext;
@@ -265,11 +274,10 @@
}
/**
- * @return whether the requested task is allowed to be locked (either allowlisted, or declares
- * lockTaskMode="always" in the manifest).
+ * @return whether the requested task auth is allowed to be locked.
*/
- boolean isTaskAllowlisted(Task task) {
- switch(task.mLockTaskAuth) {
+ static boolean isTaskAuthAllowlisted(int lockTaskAuth) {
+ switch(lockTaskAuth) {
case LOCK_TASK_AUTH_ALLOWLISTED:
case LOCK_TASK_AUTH_LAUNCHABLE:
case LOCK_TASK_AUTH_LAUNCHABLE_PRIV:
@@ -293,7 +301,30 @@
* @return whether the requested task is disallowed to be launched.
*/
boolean isLockTaskModeViolation(Task task, boolean isNewClearTask) {
- if (isLockTaskModeViolationInternal(task, isNewClearTask)) {
+ // TODO: Double check what's going on here. If the task is already in lock task mode, it's
+ // likely allowlisted, so will return false below.
+ if (isTaskLocked(task) && !isNewClearTask) {
+ // If the task is already at the top and won't be cleared, then allow the operation
+ } else if (isLockTaskModeViolationInternal(task, task.mUserId, task.intent,
+ task.mLockTaskAuth)) {
+ showLockTaskToast();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @param activity an activity that is going to be started in a new task as the root activity.
+ * @return whether the given activity is allowed to be launched.
+ */
+ boolean isNewTaskLockTaskModeViolation(ActivityRecord activity) {
+ // Use the belong task (if any) to perform the lock task checks
+ if (activity.getTask() != null) {
+ return isLockTaskModeViolation(activity.getTask());
+ }
+
+ int auth = getLockTaskAuth(activity, null /* task */);
+ if (isLockTaskModeViolationInternal(activity, activity.mUserId, activity.intent, auth)) {
showLockTaskToast();
return true;
}
@@ -310,25 +341,19 @@
return mLockTaskModeTasks.get(0);
}
- private boolean isLockTaskModeViolationInternal(Task task, boolean isNewClearTask) {
- // TODO: Double check what's going on here. If the task is already in lock task mode, it's
- // likely allowlisted, so will return false below.
- if (isTaskLocked(task) && !isNewClearTask) {
- // If the task is already at the top and won't be cleared, then allow the operation
- return false;
- }
-
+ private boolean isLockTaskModeViolationInternal(WindowContainer wc, int userId,
+ Intent intent, int taskAuth) {
// Allow recents activity if enabled by policy
- if (task.isActivityTypeRecents() && isRecentsAllowed(task.mUserId)) {
+ if (wc.isActivityTypeRecents() && isRecentsAllowed(userId)) {
return false;
}
// Allow emergency calling when the device is protected by a locked keyguard
- if (isKeyguardAllowed(task.mUserId) && isEmergencyCallTask(task)) {
+ if (isKeyguardAllowed(userId) && isEmergencyCallIntent(intent)) {
return false;
}
- return !(isTaskAllowlisted(task) || mLockTaskModeTasks.isEmpty());
+ return !(isTaskAuthAllowlisted(taskAuth) || mLockTaskModeTasks.isEmpty());
}
private boolean isRecentsAllowed(int userId) {
@@ -360,8 +385,7 @@
return isPackageAllowlisted(userId, packageName);
}
- private boolean isEmergencyCallTask(Task task) {
- final Intent intent = task.intent;
+ private boolean isEmergencyCallIntent(Intent intent) {
if (intent == null) {
return false;
}
@@ -697,6 +721,40 @@
}
}
+ int getLockTaskAuth(@Nullable ActivityRecord rootActivity, @Nullable Task task) {
+ if (rootActivity == null && task == null) {
+ return LOCK_TASK_AUTH_DONT_LOCK;
+ }
+ if (rootActivity == null) {
+ return LOCK_TASK_AUTH_PINNABLE;
+ }
+
+ final String pkg = (task == null || task.realActivity == null) ? null
+ : task.realActivity.getPackageName();
+ final int userId = task != null ? task.mUserId : rootActivity.mUserId;
+ int lockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
+ switch (rootActivity.lockTaskLaunchMode) {
+ case LOCK_TASK_LAUNCH_MODE_DEFAULT:
+ lockTaskAuth = isPackageAllowlisted(userId, pkg)
+ ? LOCK_TASK_AUTH_ALLOWLISTED : LOCK_TASK_AUTH_PINNABLE;
+ break;
+
+ case LOCK_TASK_LAUNCH_MODE_NEVER:
+ lockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
+ break;
+
+ case LOCK_TASK_LAUNCH_MODE_ALWAYS:
+ lockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
+ break;
+
+ case LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED:
+ lockTaskAuth = isPackageAllowlisted(userId, pkg)
+ ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
+ break;
+ }
+ return lockTaskAuth;
+ }
+
boolean isPackageAllowlisted(int userId, String pkg) {
if (pkg == null) {
return false;
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 0503c0d..45cd359 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -658,8 +658,8 @@
}
for (int i = mTasks.size() - 1; i >= 0; --i) {
final Task task = mTasks.get(i);
- if (task.mUserId == userId
- && !mService.getLockTaskController().isTaskAllowlisted(task)) {
+ if (task.mUserId == userId && !mService.getLockTaskController().isTaskAuthAllowlisted(
+ task.mLockTaskAuth)) {
remove(task);
}
}
@@ -1874,11 +1874,23 @@
* Creates a new RecentTaskInfo from a Task.
*/
ActivityManager.RecentTaskInfo createRecentTaskInfo(Task tr, boolean stripExtras) {
- ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
+ final ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
tr.fillTaskInfo(rti, stripExtras);
- // Fill in some deprecated values
+ // Fill in some deprecated values.
rti.id = rti.isRunning ? rti.taskId : INVALID_TASK_ID;
rti.persistentId = rti.taskId;
+
+ // Fill in organized child task info for the task created by organizer.
+ if (tr.mCreatedByOrganizer) {
+ for (int i = tr.getChildCount() - 1; i >= 0; i--) {
+ final Task childTask = tr.getChildAt(i).asTask();
+ if (childTask != null && childTask.isOrganized()) {
+ final ActivityManager.RecentTaskInfo cti = new ActivityManager.RecentTaskInfo();
+ childTask.fillTaskInfo(cti);
+ rti.childrenTaskInfos.add(cti);
+ }
+ }
+ }
return rti;
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 04b3030..2749cc9 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -59,7 +59,7 @@
import static com.android.server.wm.ActivityStackSupervisor.dumpHistoryList;
import static com.android.server.wm.ActivityStackSupervisor.printThisActivity;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATES;
@@ -76,9 +76,9 @@
import static com.android.server.wm.Task.ActivityState.RESUMED;
import static com.android.server.wm.Task.ActivityState.STOPPED;
import static com.android.server.wm.Task.ActivityState.STOPPING;
-import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
-import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
-import static com.android.server.wm.Task.STACK_VISIBILITY_INVISIBLE;
+import static com.android.server.wm.Task.REPARENT_LEAVE_ROOT_TASK_IN_PLACE;
+import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT;
+import static com.android.server.wm.Task.TASK_VISIBILITY_INVISIBLE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
@@ -232,20 +232,19 @@
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({
- MATCH_TASK_IN_STACKS_ONLY,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE
+ MATCH_ATTACHED_TASK_ONLY,
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS,
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE
})
public @interface AnyTaskForIdMatchTaskMode {
}
- // Match only tasks in the current stacks
- static final int MATCH_TASK_IN_STACKS_ONLY = 0;
- // Match either tasks in the current stacks, or in the recent tasks if not found in the stacks
- static final int MATCH_TASK_IN_STACKS_OR_RECENT_TASKS = 1;
- // Match either tasks in the current stacks, or in the recent tasks, restoring it to the
- // provided stack id
- static final int MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE = 2;
+ // Match only tasks that are attached to the hierarchy
+ static final int MATCH_ATTACHED_TASK_ONLY = 0;
+ // Match either attached tasks, or in the recent tasks if the tasks are detached
+ static final int MATCH_ATTACHED_TASK_OR_RECENT_TASKS = 1;
+ // Match either attached tasks, or in the recent tasks, restoring it to the provided task id
+ static final int MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE = 2;
ActivityTaskManagerService mService;
ActivityStackSupervisor mStackSupervisor;
@@ -1953,7 +1952,7 @@
for (int taskNdx = displayArea.getStackCount() - 1; taskNdx >= 0; --taskNdx) {
final Task rootTask = displayArea.getStackAt(taskNdx);
- if (rootTask.getVisibility(null /*starting*/) == STACK_VISIBILITY_INVISIBLE) {
+ if (rootTask.getVisibility(null /*starting*/) == TASK_VISIBILITY_INVISIBLE) {
break;
}
@@ -2556,7 +2555,7 @@
@Override
public void onDisplayAdded(int displayId) {
- if (DEBUG_STACK) Slog.v(TAG, "Display added displayId=" + displayId);
+ if (DEBUG_ROOT_TASK) Slog.v(TAG, "Display added displayId=" + displayId);
synchronized (mService.mGlobalLock) {
final DisplayContent display = getDisplayContentOrCreate(displayId);
if (display == null) {
@@ -2578,7 +2577,7 @@
@Override
public void onDisplayRemoved(int displayId) {
- if (DEBUG_STACK) Slog.v(TAG, "Display removed displayId=" + displayId);
+ if (DEBUG_ROOT_TASK) Slog.v(TAG, "Display removed displayId=" + displayId);
if (displayId == DEFAULT_DISPLAY) {
throw new IllegalArgumentException("Can't remove the primary display.");
}
@@ -2595,7 +2594,7 @@
@Override
public void onDisplayChanged(int displayId) {
- if (DEBUG_STACK) Slog.v(TAG, "Display changed displayId=" + displayId);
+ if (DEBUG_ROOT_TASK) Slog.v(TAG, "Display changed displayId=" + displayId);
synchronized (mService.mGlobalLock) {
final DisplayContent displayContent = getDisplayContent(displayId);
if (displayContent != null) {
@@ -2728,8 +2727,7 @@
}, true /* traverseTopToBottom */);
for (int i = mTmpTaskLayerChangedProcs.size() - 1; i >= 0; i--) {
- mTmpTaskLayerChangedProcs.valueAt(i).invalidateOomScoreReferenceState(
- true /* computeNow */);
+ mTmpTaskLayerChangedProcs.valueAt(i).computeProcessActivityState();
}
mTmpTaskLayerChangedProcs.clear();
}
@@ -2889,7 +2887,7 @@
// Temporarily set the task id to invalid in case in re-entry.
options.setLaunchTaskId(INVALID_TASK_ID);
final Task task = anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, options, onTop);
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, options, onTop);
options.setLaunchTaskId(taskId);
if (task != null) {
return task.getRootTask();
@@ -3445,7 +3443,7 @@
}
Task anyTaskForId(int id) {
- return anyTaskForId(id, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE);
+ return anyTaskForId(id, MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE);
}
Task anyTaskForId(int id, @RootWindowContainer.AnyTaskForIdMatchTaskMode int matchMode) {
@@ -3463,7 +3461,7 @@
Task anyTaskForId(int id, @RootWindowContainer.AnyTaskForIdMatchTaskMode int matchMode,
@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) {
+ if (matchMode != MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE && aOptions != null) {
throw new IllegalArgumentException("Should not specify activity options for non-restore"
+ " lookup");
}
@@ -3481,7 +3479,7 @@
getLaunchStack(null, aOptions, task, onTop);
if (launchStack != null && task.getRootTask() != launchStack) {
final int reparentMode = onTop
- ? REPARENT_MOVE_STACK_TO_FRONT : REPARENT_LEAVE_STACK_IN_PLACE;
+ ? REPARENT_MOVE_ROOT_TASK_TO_FRONT : REPARENT_LEAVE_ROOT_TASK_IN_PLACE;
task.reparent(launchStack, onTop, reparentMode, ANIMATE, DEFER_RESUME,
"anyTaskForId");
}
@@ -3490,7 +3488,7 @@
}
// If we are matching stack tasks only, return now
- if (matchMode == MATCH_TASK_IN_STACKS_ONLY) {
+ if (matchMode == MATCH_ATTACHED_TASK_ONLY) {
return null;
}
@@ -3507,11 +3505,11 @@
return null;
}
- if (matchMode == MATCH_TASK_IN_STACKS_OR_RECENT_TASKS) {
+ if (matchMode == MATCH_ATTACHED_TASK_OR_RECENT_TASKS) {
return task;
}
- // Implicitly, this case is MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE
+ // Implicitly, this case is MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE
if (!mStackSupervisor.restoreRecentTaskLocked(task, aOptions, onTop)) {
if (DEBUG_RECENTS) {
Slog.w(TAG_RECENTS,
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 6fbd351..b46e796 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -24,6 +24,7 @@
import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
+import static android.content.Intent.EXTRA_PACKAGE_NAME;
import static android.content.Intent.EXTRA_SHORTCUT_ID;
import static android.content.Intent.EXTRA_TASK_ID;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -43,6 +44,7 @@
import android.content.ClipDescription;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.ShortcutServiceInternal;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
@@ -288,7 +290,8 @@
public IBinder performDrag(IWindow window, int flags, SurfaceControl surface, int touchSource,
float touchX, float touchY, float thumbCenterX, float thumbCenterY, ClipData data) {
// Validate and resolve ClipDescription data before clearing the calling identity
- validateAndResolveDragMimeTypeExtras(data, Binder.getCallingUid());
+ validateAndResolveDragMimeTypeExtras(data, Binder.getCallingUid(), Binder.getCallingPid(),
+ mPackageName);
final long ident = Binder.clearCallingIdentity();
try {
return mDragDropController.performDrag(mPid, mUid, window, flags, surface, touchSource,
@@ -302,8 +305,9 @@
* Validates the given drag data.
*/
@VisibleForTesting
- public void validateAndResolveDragMimeTypeExtras(ClipData data, int callingUid) {
- if (Binder.getCallingUid() == Process.SYSTEM_UID) {
+ void validateAndResolveDragMimeTypeExtras(ClipData data, int callingUid, int callingPid,
+ String callingPackage) {
+ if (callingUid == Process.SYSTEM_UID) {
throw new IllegalStateException("Need to validate before calling identify is cleared");
}
final ClipDescription desc = data != null ? data.getDescription() : null;
@@ -358,26 +362,58 @@
Binder.restoreCallingIdentity(origId);
}
} else if (hasShortcut) {
+ // Restrict who can start a shortcut drag since it will start the shortcut as the
+ // target shortcut package
mService.mAtmService.enforceCallerIsRecentsOrHasPermission(START_TASKS_FROM_RECENTS,
"performDrag");
for (int i = 0; i < data.getItemCount(); i++) {
- final Intent intent = data.getItemAt(i).getIntent();
+ final ClipData.Item item = data.getItemAt(i);
+ final Intent intent = item.getIntent();
+ final String shortcutId = intent.getStringExtra(EXTRA_SHORTCUT_ID);
+ final String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
final UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
- if (!intent.hasExtra(EXTRA_SHORTCUT_ID)
- || TextUtils.isEmpty(intent.getStringExtra(EXTRA_SHORTCUT_ID))
+ if (TextUtils.isEmpty(shortcutId)
+ || TextUtils.isEmpty(packageName)
|| user == null) {
- throw new IllegalArgumentException("Clip item must include the shortcut id and "
- + "the user to launch for.");
+ throw new IllegalArgumentException("Clip item must include the package name, "
+ + "shortcut id, and the user to launch for.");
}
+ final ShortcutServiceInternal shortcutService =
+ LocalServices.getService(ShortcutServiceInternal.class);
+ final Intent[] shortcutIntents = shortcutService.createShortcutIntents(
+ callingUid, callingPackage, packageName, shortcutId,
+ user.getIdentifier(), callingPid, callingUid);
+ if (shortcutIntents == null || shortcutIntents.length == 0) {
+ throw new IllegalArgumentException("Invalid shortcut id");
+ }
+ final ActivityInfo info = mService.mAtmService.resolveActivityInfoForIntent(
+ shortcutIntents[0], null /* resolvedType */, user.getIdentifier(),
+ callingUid);
+ item.setActivityInfo(info);
}
} else if (hasTask) {
+ // TODO(b/169894807): Consider opening this up for tasks from the same app as the caller
mService.mAtmService.enforceCallerIsRecentsOrHasPermission(START_TASKS_FROM_RECENTS,
"performDrag");
for (int i = 0; i < data.getItemCount(); i++) {
- final Intent intent = data.getItemAt(i).getIntent();
- if (intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID) == INVALID_TASK_ID) {
+ final ClipData.Item item = data.getItemAt(i);
+ final Intent intent = item.getIntent();
+ final int taskId = intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID);
+ if (taskId == INVALID_TASK_ID) {
throw new IllegalArgumentException("Clip item must include the task id.");
}
+ final Task task = mService.mRoot.anyTaskForId(taskId);
+ if (task == null) {
+ throw new IllegalArgumentException("Invalid task id.");
+ }
+ if (task.getRootActivity() != null) {
+ item.setActivityInfo(task.getRootActivity().info);
+ } else {
+ // Resolve the activity info manually if the task was restored after reboot
+ final ActivityInfo info = mService.mAtmService.resolveActivityInfoForIntent(
+ task.intent, null /* resolvedType */, task.mUserId, callingUid);
+ item.setActivityInfo(info);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 9273bf7..cbb3c42 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -43,10 +43,6 @@
import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
-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_ALLOWLISTED;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
@@ -107,7 +103,7 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ROOT_TASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATES;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
@@ -120,6 +116,11 @@
import static com.android.server.wm.IdentifierProto.HASH_CODE;
import static com.android.server.wm.IdentifierProto.TITLE;
import static com.android.server.wm.IdentifierProto.USER_ID;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_ALLOWLISTED;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_DONT_LOCK;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_PINNABLE;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.Task.ActivityState.PAUSED;
import static com.android.server.wm.Task.ActivityState.PAUSING;
@@ -145,7 +146,7 @@
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainerChildProto.TASK;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.MIN_TASK_LETTERBOX_ASPECT_RATIO;
@@ -251,7 +252,7 @@
static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP;
private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
- private static final String TAG_STACK = TAG + POSTFIX_STACK;
+ private static final String TAG_ROOT_TASK = TAG + POSTFIX_ROOT_TASK;
private static final String TAG_STATES = TAG + POSTFIX_STATES;
private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
private static final String TAG_TRANSITION = TAG + POSTFIX_TRANSITION;
@@ -308,38 +309,37 @@
private float mShadowRadius = 0;
/**
- * The modes to control how the stack is moved to the front when calling {@link Task#reparent}.
+ * The modes to control how root task is moved to the front when calling {@link Task#reparent}.
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({
- REPARENT_MOVE_STACK_TO_FRONT,
- REPARENT_KEEP_STACK_AT_FRONT,
- REPARENT_LEAVE_STACK_IN_PLACE
+ REPARENT_MOVE_ROOT_TASK_TO_FRONT,
+ REPARENT_KEEP_ROOT_TASK_AT_FRONT,
+ REPARENT_LEAVE_ROOT_TASK_IN_PLACE
})
- @interface ReparentMoveStackMode {}
- // Moves the stack to the front if it was not at the front
- static final int REPARENT_MOVE_STACK_TO_FRONT = 0;
- // Only moves the stack to the front if it was focused or front most already
- static final int REPARENT_KEEP_STACK_AT_FRONT = 1;
- // Do not move the stack as a part of reparenting
- static final int REPARENT_LEAVE_STACK_IN_PLACE = 2;
+ @interface ReparentMoveRootTaskMode {}
+ // Moves the root task to the front if it was not at the front
+ static final int REPARENT_MOVE_ROOT_TASK_TO_FRONT = 0;
+ // Only moves the root task to the front if it was focused or front most already
+ static final int REPARENT_KEEP_ROOT_TASK_AT_FRONT = 1;
+ // Do not move the root task as a part of reparenting
+ static final int REPARENT_LEAVE_ROOT_TASK_IN_PLACE = 2;
- // TODO (b/157876447): switch to Task related name
- @IntDef(prefix = {"STACK_VISIBILITY"}, value = {
- STACK_VISIBILITY_VISIBLE,
- STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
- STACK_VISIBILITY_INVISIBLE,
+ @IntDef(prefix = {"TASK_VISIBILITY"}, value = {
+ TASK_VISIBILITY_VISIBLE,
+ TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ TASK_VISIBILITY_INVISIBLE,
})
- @interface StackVisibility {}
+ @interface TaskVisibility {}
- /** Stack is visible. No other stacks on top that fully or partially occlude it. */
- static final int STACK_VISIBILITY_VISIBLE = 0;
+ /** Task is visible. No other tasks on top that fully or partially occlude it. */
+ static final int TASK_VISIBILITY_VISIBLE = 0;
- /** Stack is partially occluded by other translucent stack(s) on top of it. */
- static final int STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT = 1;
+ /** Task is partially occluded by other translucent task(s) on top of it. */
+ static final int TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT = 1;
- /** Stack is completely invisible. */
- static final int STACK_VISIBILITY_INVISIBLE = 2;
+ /** Task is completely invisible. */
+ static final int TASK_VISIBILITY_INVISIBLE = 2;
enum ActivityState {
INITIALIZING,
@@ -407,17 +407,6 @@
boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity
// was changed.
- /** Can't be put in lockTask mode. */
- final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
- /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
- final static int LOCK_TASK_AUTH_PINNABLE = 1;
- /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
- final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
- /** Can enter lockTask without user approval. Can start over existing lockTask task. */
- final static int LOCK_TASK_AUTH_ALLOWLISTED = 3;
- /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
- * lockTask task. */
- final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
int mLockTaskUid = -1; // The uid of the application that called startLockTask().
@@ -964,7 +953,7 @@
mAtmService.getLockTaskController().clearLockedTask(this);
}
if (shouldDeferRemoval()) {
- if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
+ if (DEBUG_ROOT_TASK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
return;
}
removeImmediately();
@@ -1056,7 +1045,7 @@
/** Convenience method to reparent a task to the top or bottom position of the stack. */
boolean reparent(Task preferredStack, boolean toTop,
- @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
+ @ReparentMoveRootTaskMode int moveStackMode, boolean animate, boolean deferResume,
String reason) {
return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate, deferResume,
true /* schedulePictureInPictureModeChange */, reason);
@@ -1067,7 +1056,7 @@
* an option to skip scheduling the picture-in-picture mode change.
*/
boolean reparent(Task preferredStack, boolean toTop,
- @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
+ @ReparentMoveRootTaskMode int moveStackMode, boolean animate, boolean deferResume,
boolean schedulePictureInPictureModeChange, String reason) {
return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate,
deferResume, schedulePictureInPictureModeChange, reason);
@@ -1075,7 +1064,7 @@
/** Convenience method to reparent a task to a specific position of the stack. */
boolean reparent(Task preferredStack, int position,
- @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
+ @ReparentMoveRootTaskMode int moveStackMode, boolean animate, boolean deferResume,
String reason) {
return reparent(preferredStack, position, moveStackMode, animate, deferResume,
true /* schedulePictureInPictureModeChange */, reason);
@@ -1101,7 +1090,7 @@
// TODO: Inspect all call sites and change to just changing windowing mode of the stack vs.
// re-parenting the task. Can only be done when we are no longer using static stack Ids.
boolean reparent(Task preferredStack, int position,
- @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
+ @ReparentMoveRootTaskMode int moveStackMode, boolean animate, boolean deferResume,
boolean schedulePictureInPictureModeChange, String reason) {
final ActivityStackSupervisor supervisor = mStackSupervisor;
final RootWindowContainer root = mRootWindowContainer;
@@ -1156,8 +1145,9 @@
final boolean wasFront = r != null && sourceStack.isTopStackInDisplayArea()
&& (sourceStack.topRunningActivity() == r);
- final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT
- || (moveStackMode == REPARENT_KEEP_STACK_AT_FRONT && (wasFocused || wasFront));
+ final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_ROOT_TASK_TO_FRONT
+ || (moveStackMode == REPARENT_KEEP_ROOT_TASK_AT_FRONT
+ && (wasFocused || wasFront));
reparent(toStack, position, moveStackToFront, reason);
@@ -1181,7 +1171,7 @@
toStack.prepareFreezingTaskBounds();
if (toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) {
+ && moveStackMode == REPARENT_KEEP_ROOT_TASK_AT_FRONT) {
// Move recents to front so it is not behind home stack when going into docked
// mode
mStackSupervisor.moveRecentsStackToFront(reason);
@@ -1532,7 +1522,7 @@
return;
}
- if (ActivityTaskManagerDebugConfig.DEBUG_STACK) Slog.d(TAG_STACK,
+ if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) Slog.d(TAG_ROOT_TASK,
"setResumedActivity stack:" + this + " + from: "
+ mResumedActivity + " to:" + r + " reason:" + reason);
mResumedActivity = r;
@@ -1941,32 +1931,7 @@
}
private void setLockTaskAuth(@Nullable ActivityRecord r) {
- if (r == null) {
- mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
- return;
- }
-
- final String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
- final LockTaskController lockTaskController = mAtmService.getLockTaskController();
- switch (r.lockTaskLaunchMode) {
- case LOCK_TASK_LAUNCH_MODE_DEFAULT:
- mLockTaskAuth = lockTaskController.isPackageAllowlisted(mUserId, pkg)
- ? LOCK_TASK_AUTH_ALLOWLISTED : LOCK_TASK_AUTH_PINNABLE;
- break;
-
- case LOCK_TASK_LAUNCH_MODE_NEVER:
- mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
- break;
-
- case LOCK_TASK_LAUNCH_MODE_ALWAYS:
- mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
- break;
-
- case LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED:
- mLockTaskAuth = lockTaskController.isPackageAllowlisted(mUserId, pkg)
- ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
- break;
- }
+ mLockTaskAuth = mAtmService.getLockTaskController().getLockTaskAuth(r, this);
ProtoLog.d(WM_DEBUG_LOCKTASK, "setLockTaskAuth: task=%s mLockTaskAuth=%s", this,
lockTaskAuthToString());
}
@@ -2210,8 +2175,8 @@
}
if (state == RESUMED) {
- if (ActivityTaskManagerDebugConfig.DEBUG_STACK) {
- Slog.v(TAG_STACK, "set resumed activity to:" + record + " reason:" + reason);
+ if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) {
+ Slog.v(TAG_ROOT_TASK, "set resumed activity to:" + record + " reason:" + reason);
}
setResumedActivity(record, reason + " - onActivityStateChanged");
if (record == mRootWindowContainer.getTopResumedActivity()) {
@@ -3265,7 +3230,7 @@
@Override
void removeImmediately() {
- if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
+ if (DEBUG_ROOT_TASK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
EventLogTags.writeWmTaskRemoved(mTaskId, "removeTask");
// If applicable let the TaskOrganizer know the Task is vanishing.
@@ -3276,7 +3241,7 @@
// TODO: Consolidate this with Task.reparent()
void reparent(Task stack, int position, boolean moveParents, String reason) {
- if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
+ if (DEBUG_ROOT_TASK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
+ " from stack=" + getRootTask());
EventLogTags.writeWmTaskRemoved(mTaskId, "reParentTask:" + reason);
@@ -4180,7 +4145,7 @@
* @param starting The currently starting activity or null if there is none.
*/
boolean shouldBeVisible(ActivityRecord starting) {
- return getVisibility(starting) != STACK_VISIBILITY_INVISIBLE;
+ return getVisibility(starting) != TASK_VISIBILITY_INVISIBLE;
}
/**
@@ -4188,14 +4153,14 @@
*
* @param starting The currently starting activity or null if there is none.
*/
- @Task.StackVisibility
+ @TaskVisibility
int getVisibility(ActivityRecord starting) {
if (!isAttached() || isForceHidden()) {
- return STACK_VISIBILITY_INVISIBLE;
+ return TASK_VISIBILITY_INVISIBLE;
}
if (isTopActivityLaunchedBehind()) {
- return STACK_VISIBILITY_VISIBLE;
+ return TASK_VISIBILITY_VISIBLE;
}
boolean gotSplitScreenStack = false;
@@ -4211,10 +4176,10 @@
final WindowContainer parent = getParent();
if (parent.asTask() != null) {
final int parentVisibility = parent.asTask().getVisibility(starting);
- if (parentVisibility == STACK_VISIBILITY_INVISIBLE) {
+ if (parentVisibility == TASK_VISIBILITY_INVISIBLE) {
// Can't be visible if parent isn't visible
- return STACK_VISIBILITY_INVISIBLE;
- } else if (parentVisibility == STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT) {
+ return TASK_VISIBILITY_INVISIBLE;
+ } else if (parentVisibility == TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT) {
// Parent is behind a translucent container so the highest visibility this container
// can get is that.
gotTranslucentFullscreen = true;
@@ -4249,7 +4214,7 @@
gotTranslucentFullscreen = true;
continue;
}
- return STACK_VISIBILITY_INVISIBLE;
+ return TASK_VISIBILITY_INVISIBLE;
} else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
&& !gotOpaqueSplitScreenPrimary) {
gotSplitScreenStack = true;
@@ -4258,7 +4223,7 @@
if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
&& gotOpaqueSplitScreenPrimary) {
// Can not be visible behind another opaque stack in split-screen-primary mode.
- return STACK_VISIBILITY_INVISIBLE;
+ return TASK_VISIBILITY_INVISIBLE;
}
} else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
&& !gotOpaqueSplitScreenSecondary) {
@@ -4268,24 +4233,24 @@
if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
&& gotOpaqueSplitScreenSecondary) {
// Can not be visible behind another opaque stack in split-screen-secondary mode.
- return STACK_VISIBILITY_INVISIBLE;
+ return TASK_VISIBILITY_INVISIBLE;
}
}
if (gotOpaqueSplitScreenPrimary && gotOpaqueSplitScreenSecondary) {
// Can not be visible if we are in split-screen windowing mode and both halves of
// the screen are opaque.
- return STACK_VISIBILITY_INVISIBLE;
+ return TASK_VISIBILITY_INVISIBLE;
}
if (isAssistantType && gotSplitScreenStack) {
// Assistant stack can't be visible behind split-screen. In addition to this not
// making sense, it also works around an issue here we boost the z-order of the
// assistant window surfaces in window manager whenever it is visible.
- return STACK_VISIBILITY_INVISIBLE;
+ return TASK_VISIBILITY_INVISIBLE;
}
}
if (!shouldBeVisible) {
- return STACK_VISIBILITY_INVISIBLE;
+ return TASK_VISIBILITY_INVISIBLE;
}
// Handle cases when there can be a translucent split-screen stack on top.
@@ -4293,26 +4258,26 @@
case WINDOWING_MODE_FULLSCREEN:
if (gotTranslucentSplitScreenPrimary || gotTranslucentSplitScreenSecondary) {
// At least one of the split-screen stacks that covers this one is translucent.
- return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
+ return TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
}
break;
case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
if (gotTranslucentSplitScreenPrimary) {
// Covered by translucent primary split-screen on top.
- return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
+ return TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
}
break;
case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY:
if (gotTranslucentSplitScreenSecondary) {
// Covered by translucent secondary split-screen on top.
- return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
+ return TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
}
break;
}
// Lastly - check if there is a translucent fullscreen stack on top.
- return gotTranslucentFullscreen ? STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT
- : STACK_VISIBILITY_VISIBLE;
+ return gotTranslucentFullscreen ? TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT
+ : TASK_VISIBILITY_VISIBLE;
}
private boolean isTopActivityLaunchedBehind() {
@@ -7326,7 +7291,7 @@
boolean toTop = position >= getChildCount();
boolean includingParents = toTop || getDisplayArea().getNextFocusableStack(this,
true /* ignoreCurrent */) == null;
- if (WindowManagerDebugConfig.DEBUG_STACK) {
+ if (WindowManagerDebugConfig.DEBUG_ROOT_TASK) {
Slog.i(TAG_WM, "positionChildAt: positioning task=" + task + " at " + position);
}
positionChildAt(position, task, includingParents);
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index e721319..9d14e0d 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -37,11 +37,11 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
-import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK;
+import static com.android.server.wm.ActivityTaskManagerService.TAG_ROOT_TASK;
import static com.android.server.wm.DisplayContent.alwaysCreateStack;
import static com.android.server.wm.Task.ActivityState.RESUMED;
-import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.Nullable;
@@ -311,7 +311,7 @@
@Override
void addChild(Task task, int position) {
- if (DEBUG_STACK) Slog.d(TAG_WM, "Set task=" + task + " on taskDisplayArea=" + this);
+ if (DEBUG_ROOT_TASK) Slog.d(TAG_WM, "Set task=" + task + " on taskDisplayArea=" + this);
addStackReferenceIfNeeded(task);
position = findPositionForStack(position, task, true /* adding */);
@@ -831,8 +831,8 @@
}
void onStackRemoved(Task stack) {
- if (ActivityTaskManagerDebugConfig.DEBUG_STACK) {
- Slog.v(TAG_STACK, "removeStack: detaching " + stack + " from displayId="
+ if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) {
+ Slog.v(TAG_ROOT_TASK, "removeStack: detaching " + stack + " from displayId="
+ mDisplayContent.mDisplayId);
}
if (mPreferredTopFocusableStack == stack) {
@@ -870,7 +870,7 @@
homeParentTask.positionChildAtBottom(task);
} else {
task.reparent(homeParentTask, false /* toTop */,
- Task.REPARENT_LEAVE_STACK_IN_PLACE, false /* animate */,
+ Task.REPARENT_LEAVE_ROOT_TASK_IN_PLACE, false /* animate */,
false /* deferResume */, "positionTaskBehindHome");
}
}
@@ -1205,8 +1205,8 @@
}
}
final Task currentFocusedStack = getFocusedStack();
- if (ActivityTaskManagerDebugConfig.DEBUG_STACK) {
- Slog.d(TAG_STACK, "allResumedActivitiesComplete: mLastFocusedStack changing from="
+ if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) {
+ Slog.d(TAG_ROOT_TASK, "allResumedActivitiesComplete: mLastFocusedStack changing from="
+ mLastFocusedStack + " to=" + currentFocusedStack);
}
mLastFocusedStack = currentFocusedStack;
@@ -1230,7 +1230,7 @@
final Task stack = getStackAt(stackNdx);
final ActivityRecord resumedActivity = stack.getResumedActivity();
if (resumedActivity != null
- && (stack.getVisibility(resuming) != STACK_VISIBILITY_VISIBLE
+ && (stack.getVisibility(resuming) != TASK_VISIBILITY_VISIBLE
|| !stack.isTopActivityFocusable())) {
ProtoLog.d(WM_DEBUG_STATES, "pauseBackStacks: stack=%s "
+ "mResumedActivity=%s", stack, resumedActivity);
@@ -1851,8 +1851,12 @@
.getTopStackInWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) : null;
for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
final Task stack = getStackAt(stackNdx);
- // Always finish non-standard type stacks.
- if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
+ // Always finish non-standard type stacks and stacks created by a organizer.
+ // TODO: For stacks created by organizer, consider reparenting children tasks if the use
+ // case arises in the future.
+ if (destroyContentOnRemoval
+ || !stack.isActivityTypeStandardOrUndefined()
+ || stack.mCreatedByOrganizer) {
stack.finishAllActivitiesImmediately();
} else {
// Reparent the stack to the root task of secondary-split-screen or display area.
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 2c39c2b..bd52b66 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -160,18 +160,20 @@
return;
}
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task info changed taskId=%d", task.mTaskId);
- if (!task.isOrganized()) {
- // This is safe to ignore if the task is no longer organized
- return;
- }
- try {
- // Purposely notify of task info change immediately instead of deferring (like
- // appear and vanish) to allow info changes (such as new PIP params) to flow
- // without waiting.
- mTaskOrganizer.onTaskInfoChanged(taskInfo);
- } catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onTaskInfoChanged callback", e);
- }
+ mDeferTaskOrgCallbacksConsumer.accept(() -> {
+ if (!task.isOrganized()) {
+ // This is safe to ignore if the task is no longer organized
+ return;
+ }
+ try {
+ // Purposely notify of task info change immediately instead of deferring (like
+ // appear and vanish) to allow info changes (such as new PIP params) to flow
+ // without waiting.
+ mTaskOrganizer.onTaskInfoChanged(taskInfo);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception sending onTaskInfoChanged callback", e);
+ }
+ });
}
void onBackPressedOnTaskRoot(Task task) {
@@ -181,15 +183,17 @@
// Skip if the task has not yet received taskAppeared().
return;
}
- if (!task.isOrganized()) {
- // This is safe to ignore if the task is no longer organized
- return;
- }
- try {
- mTaskOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo());
- } catch (Exception e) {
- Slog.e(TAG, "Exception sending onBackPressedOnTaskRoot callback", e);
- }
+ mDeferTaskOrgCallbacksConsumer.accept(() -> {
+ if (!task.isOrganized()) {
+ // This is safe to ignore if the task is no longer organized
+ return;
+ }
+ try {
+ mTaskOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo());
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception sending onBackPressedOnTaskRoot callback", e);
+ }
+ });
}
}
@@ -489,8 +493,7 @@
mTmpTaskInfo.positionInParent,
lastInfo.positionInParent)
|| mTmpTaskInfo.pictureInPictureParams != lastInfo.pictureInPictureParams
- || mTmpTaskInfo.getConfiguration().windowConfiguration.getWindowingMode()
- != lastInfo.getConfiguration().windowConfiguration.getWindowingMode()
+ || mTmpTaskInfo.getWindowingMode() != lastInfo.getWindowingMode()
|| !TaskDescription.equals(mTmpTaskInfo.taskDescription, lastInfo.taskDescription);
if (!changed) {
int cfgChanges = mTmpTaskInfo.configuration.diff(lastInfo.configuration);
diff --git a/services/core/java/com/android/server/wm/TaskPersister.java b/services/core/java/com/android/server/wm/TaskPersister.java
index a3dc290..eff4b9e 100644
--- a/services/core/java/com/android/server/wm/TaskPersister.java
+++ b/services/core/java/com/android/server/wm/TaskPersister.java
@@ -16,7 +16,7 @@
package com.android.server.wm;
-import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
+import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
import android.annotation.NonNull;
import android.graphics.Bitmap;
@@ -330,7 +330,7 @@
final int taskId = task.mTaskId;
if (mService.mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS) != null) {
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS) != null) {
// Should not happen.
Slog.wtf(TAG, "Existing task with taskId " + taskId + "found");
} else if (userId != task.mUserId) {
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index a6f0f46..614d221 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -225,10 +225,8 @@
mClientChannel, mService.mAnimationHandler.getLooper(),
mService.mAnimator.getChoreographer());
- mDragApplicationHandle = new InputApplicationHandle(new Binder());
- mDragApplicationHandle.name = TAG;
- mDragApplicationHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
-
+ mDragApplicationHandle = new InputApplicationHandle(new Binder(), TAG,
+ DEFAULT_DISPATCHING_TIMEOUT_MILLIS);
mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle,
displayContent.getDisplayId());
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index 93b0fd9..74337c2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -50,7 +50,7 @@
static final boolean DEBUG_WINDOW_TRACE = false;
static final boolean DEBUG_TASK_MOVEMENT = false;
static final boolean DEBUG_TASK_POSITIONING = false;
- static final boolean DEBUG_STACK = false;
+ static final boolean DEBUG_ROOT_TASK = false;
static final boolean DEBUG_DISPLAY = false;
static final boolean DEBUG_POWER = false;
static final boolean SHOW_VERBOSE_TRANSACTIONS = false;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c806c94..e7d9e6b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -44,6 +44,7 @@
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
+import static android.provider.Settings.Global.DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS;
import static android.provider.Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
@@ -197,7 +198,6 @@
import android.os.Trace;
import android.os.UserHandle;
import android.os.WorkSource;
-import android.provider.DeviceConfig;
import android.provider.Settings;
import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
@@ -576,6 +576,7 @@
final PackageManagerInternal mPmInternal;
private final TestUtilityService mTestUtilityService;
+ final DisplayWindowSettingsProvider mDisplayWindowSettingsProvider;
final DisplayWindowSettings mDisplayWindowSettings;
/** If the system should display notifications for apps displaying an alert window. */
@@ -799,6 +800,8 @@
DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM);
private final Uri mRenderShadowsInCompositorUri = Settings.Global.getUriFor(
DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR);
+ private final Uri mIgnoreVendorDisplaySettingsUri = Settings.Global.getUriFor(
+ DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS);
public SettingsObserver() {
super(new Handler());
@@ -823,6 +826,8 @@
UserHandle.USER_ALL);
resolver.registerContentObserver(mRenderShadowsInCompositorUri, false, this,
UserHandle.USER_ALL);
+ resolver.registerContentObserver(mIgnoreVendorDisplaySettingsUri, false, this,
+ UserHandle.USER_ALL);
}
@Override
@@ -866,6 +871,11 @@
return;
}
+ if (mIgnoreVendorDisplaySettingsUri.equals(uri)) {
+ updateIgnoreVendorDisplaySettings();
+ return;
+ }
+
@UpdateAnimationScaleMode
final int mode;
if (mWindowAnimationScaleUri.equals(uri)) {
@@ -955,6 +965,19 @@
mAtmService.mSizeCompatFreeform = sizeCompatFreeform;
}
+
+ void updateIgnoreVendorDisplaySettings() {
+ final ContentResolver resolver = mContext.getContentResolver();
+ final boolean ignoreVendorSettings = Settings.Global.getInt(resolver,
+ DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS, 0) != 0;
+ synchronized (mGlobalLock) {
+ mDisplayWindowSettingsProvider.setVendorSettingsIgnored(ignoreVendorSettings);
+ mRoot.forAllDisplays(display -> {
+ mDisplayWindowSettings.applySettingsToDisplayLocked(display);
+ display.reconfigureDisplayLocked();
+ });
+ }
+ }
}
private void setShadowRenderer() {
@@ -1213,7 +1236,6 @@
mSurfaceFactory = surfaceFactory;
mTransaction = mTransactionFactory.get();
- mDisplayWindowSettings = new DisplayWindowSettings(this);
mPolicy = policy;
mAnimator = new WindowAnimator(this);
mRoot = new RootWindowContainer(this);
@@ -1312,6 +1334,12 @@
mForceDesktopModeOnExternalDisplays = Settings.Global.getInt(resolver,
DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, 0) != 0;
+ final boolean ignoreVendorDisplaySettings = Settings.Global.getInt(resolver,
+ DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS, 0) != 0;
+ mDisplayWindowSettingsProvider = new DisplayWindowSettingsProvider();
+ mDisplayWindowSettingsProvider.setVendorSettingsIgnored(ignoreVendorDisplaySettings);
+ mDisplayWindowSettings = new DisplayWindowSettings(this, mDisplayWindowSettingsProvider);
+
IntentFilter filter = new IntentFilter();
// Track changes to DevicePolicyManager state so we can enable/disable keyguard.
filter.addAction(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
@@ -7669,6 +7697,7 @@
if (imeTarget == null) {
return;
}
+ Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, "WMS.showImePostLayout", 0);
final InsetsControlTarget controlTarget = imeTarget.getImeControlTarget();
imeTarget = controlTarget.getWindow();
// If InsetsControlTarget doesn't have a window, its using remoteControlTarget which
@@ -7682,6 +7711,7 @@
@Override
public void hideIme(IBinder imeTargetWindowToken, int displayId) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WMS.hideIme");
synchronized (mGlobalLock) {
WindowState imeTarget = mWindowMap.get(imeTargetWindowToken);
ProtoLog.d(WM_DEBUG_IME, "hideIme target: %s ", imeTarget);
@@ -7702,6 +7732,7 @@
WindowInsets.Type.ime(), true /* fromIme */);
}
}
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
@Override
@@ -8364,7 +8395,7 @@
embeddedWindow.getName());
return;
}
- t.requestFocusTransfer(newFocusTarget.mInputWindowHandle.token, targetInputToken,
+ t.requestFocusTransfer(newFocusTarget.mInputChannelToken, targetInputToken,
displayId).apply();
EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
"Transfer focus request " + newFocusTarget,
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 2e7905c..5bfa662 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -225,8 +225,19 @@
@Nullable
private final BackgroundActivityStartCallback mBackgroundActivityStartCallback;
- /** The state for oom-adjustment calculation. */
- private final OomScoreReferenceState mOomRefState;
+ // The bits used for mActivityStateFlags.
+ private static final int ACTIVITY_STATE_FLAG_IS_VISIBLE = 0x10000000;
+ private static final int ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED = 0x20000000;
+ private static final int ACTIVITY_STATE_FLAG_IS_STOPPING = 0x40000000;
+ private static final int ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING = 0x80000000;
+ private static final int ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER = 0x0000ffff;
+
+ /**
+ * The state for oom-adjustment calculation. The higher 16 bits are the activity states, and the
+ * lower 16 bits are the task layer rank (see {@link Task#mLayerRank}). This field is written by
+ * window manager and read by activity manager.
+ */
+ private volatile int mActivityStateFlags = ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER;
public WindowProcessController(@NonNull ActivityTaskManagerService atm, ApplicationInfo info,
String name, int uid, int userId, Object owner,
@@ -240,7 +251,6 @@
mAtm = atm;
mDisplayId = INVALID_DISPLAY;
mBackgroundActivityStartCallback = mAtm.getBackgroundActivityStartCallback();
- mOomRefState = new OomScoreReferenceState(this);
boolean isSysUiPackage = info.packageName.equals(
mAtm.getSysUiServiceComponentLocked().getPackageName());
@@ -707,7 +717,7 @@
@HotPath(caller = HotPath.OOM_ADJUSTMENT)
public boolean hasVisibleActivities() {
- return (mOomRefState.mActivityStateFlags & OomScoreReferenceState.FLAG_IS_VISIBLE) != 0;
+ return (mActivityStateFlags & ACTIVITY_STATE_FLAG_IS_VISIBLE) != 0;
}
@HotPath(caller = HotPath.LRU_UPDATE)
@@ -1000,34 +1010,6 @@
mHostActivities.remove(r);
}
- private static class OomScoreReferenceState extends RootWindowContainer.LockedScheduler {
- private static final int FLAG_IS_VISIBLE = 0x10000000;
- private static final int FLAG_IS_PAUSING = 0x20000000;
- private static final int FLAG_IS_STOPPING = 0x40000000;
- private static final int FLAG_IS_STOPPING_FINISHING = 0x80000000;
- /** @see Task#mLayerRank */
- private static final int MASK_MIN_TASK_LAYER = 0x0000ffff;
-
- private final WindowProcessController mOwner;
- boolean mChanged;
-
- /**
- * The higher 16 bits are the activity states, and the lower 16 bits are the task layer
- * rank. This field is written by window manager and read by activity manager.
- */
- volatile int mActivityStateFlags = MASK_MIN_TASK_LAYER;
-
- OomScoreReferenceState(WindowProcessController owner) {
- super(owner.mAtm);
- mOwner = owner;
- }
-
- @Override
- public void execute() {
- mOwner.computeOomScoreReferenceStateIfNeeded();
- }
- }
-
public interface ComputeOomAdjCallback {
void onVisibleActivity();
void onPausedActivity();
@@ -1041,26 +1023,21 @@
*/
@HotPath(caller = HotPath.OOM_ADJUSTMENT)
public int computeOomAdjFromActivities(ComputeOomAdjCallback callback) {
- final int flags = mOomRefState.mActivityStateFlags;
- if ((flags & OomScoreReferenceState.FLAG_IS_VISIBLE) != 0) {
+ final int flags = mActivityStateFlags;
+ if ((flags & ACTIVITY_STATE_FLAG_IS_VISIBLE) != 0) {
callback.onVisibleActivity();
- } else if ((flags & OomScoreReferenceState.FLAG_IS_PAUSING) != 0) {
+ } else if ((flags & ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED) != 0) {
callback.onPausedActivity();
- } else if ((flags & OomScoreReferenceState.FLAG_IS_STOPPING) != 0) {
+ } else if ((flags & ACTIVITY_STATE_FLAG_IS_STOPPING) != 0) {
callback.onStoppingActivity(
- (flags & OomScoreReferenceState.FLAG_IS_STOPPING_FINISHING) != 0);
+ (flags & ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING) != 0);
} else {
callback.onOtherActivity();
}
- return flags & OomScoreReferenceState.MASK_MIN_TASK_LAYER;
+ return flags & ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER;
}
- void computeOomScoreReferenceStateIfNeeded() {
- if (!mOomRefState.mChanged) {
- return;
- }
- mOomRefState.mChanged = false;
-
+ void computeProcessActivityState() {
// Since there could be more than one activities in a process record, we don't need to
// compute the OomAdj with each of them, just need to find out the activity with the
// "best" state, the order would be visible, pausing, stopping...
@@ -1101,36 +1078,25 @@
finishing &= r.finishing;
}
}
+ }
- int stateFlags = minTaskLayer & OomScoreReferenceState.MASK_MIN_TASK_LAYER;
- if (visible) {
- stateFlags |= OomScoreReferenceState.FLAG_IS_VISIBLE;
- } else if (best == PAUSING) {
- stateFlags |= OomScoreReferenceState.FLAG_IS_PAUSING;
- } else if (best == STOPPING) {
- stateFlags |= OomScoreReferenceState.FLAG_IS_STOPPING;
- if (finishing) {
- stateFlags |= OomScoreReferenceState.FLAG_IS_STOPPING_FINISHING;
- }
+ int stateFlags = minTaskLayer & ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER;
+ if (visible) {
+ stateFlags |= ACTIVITY_STATE_FLAG_IS_VISIBLE;
+ } else if (best == PAUSING) {
+ stateFlags |= ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED;
+ } else if (best == STOPPING) {
+ stateFlags |= ACTIVITY_STATE_FLAG_IS_STOPPING;
+ if (finishing) {
+ stateFlags |= ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING;
}
- mOomRefState.mActivityStateFlags = stateFlags;
}
- }
-
- void invalidateOomScoreReferenceState(boolean computeNow) {
- mOomRefState.mChanged = true;
- if (computeNow) {
- computeOomScoreReferenceStateIfNeeded();
- return;
- }
- mOomRefState.scheduleIfNeeded();
+ mActivityStateFlags = stateFlags;
}
/** Called when the process has some oom related changes and it is going to update oom-adj. */
private void prepareOomAdjustment() {
mAtm.mRootWindowContainer.rankTaskLayersIfNeeded();
- // The task layer may not change but the activity state in the same task may change.
- computeOomScoreReferenceStateIfNeeded();
}
public int computeRelaunchReason() {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 9234390..fc06461 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -556,9 +556,17 @@
boolean mWindowRemovalAllowed;
// Input channel and input window handle used by the input dispatcher.
- final InputWindowHandle mInputWindowHandle;
+ final InputWindowHandleWrapper mInputWindowHandle;
InputChannel mInputChannel;
+ /**
+ * The token will be assigned to {@link InputWindowHandle#token} if this window can receive
+ * input event. Note that the token of associated input window handle can be cleared if this
+ * window becomes unable to receive input, but this field will remain until the input channel
+ * is actually disposed.
+ */
+ IBinder mInputChannelToken;
+
// Used to improve performance of toString()
private String mStringNameCache;
private CharSequence mLastTitle;
@@ -856,6 +864,21 @@
DeathRecipient deathRecipient = new DeathRecipient();
mPowerManagerWrapper = powerManagerWrapper;
mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
+ mInputWindowHandle = new InputWindowHandleWrapper(new InputWindowHandle(
+ mActivityRecord != null
+ ? mActivityRecord.getInputApplicationHandle(false /* update */) : null,
+ getDisplayId()));
+ mInputWindowHandle.setOwnerPid(s.mPid);
+ mInputWindowHandle.setOwnerUid(s.mUid);
+ mInputWindowHandle.setName(getName());
+ mInputWindowHandle.setPackageName(mAttrs.packageName);
+ mInputWindowHandle.setLayoutParamsType(mAttrs.type);
+ // Check private trusted overlay flag and window type to set trustedOverlay variable of
+ // input window handle.
+ mInputWindowHandle.setTrustedOverlay(
+ ((mAttrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0
+ && mOwnerCanAddInternalSystemWindow)
+ || InputMonitor.isTrustedOverlay(mAttrs.type));
if (DEBUG) {
Slog.v(TAG, "Window " + this + " client=" + c.asBinder()
+ " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
@@ -871,7 +894,6 @@
mIsFloatingLayer = false;
mBaseLayer = 0;
mSubLayer = 0;
- mInputWindowHandle = null;
mWinAnimator = null;
mWpcForDisplayConfigChanges = null;
return;
@@ -919,16 +941,6 @@
mLastRequestedWidth = 0;
mLastRequestedHeight = 0;
mLayer = 0;
- mInputWindowHandle = new InputWindowHandle(
- mActivityRecord != null ? mActivityRecord.mInputApplicationHandle : null,
- getDisplayId());
-
- // Check private trusted overlay flag and window type to set trustedOverlay variable of
- // input window handle.
- mInputWindowHandle.trustedOverlay =
- (mAttrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0
- && mOwnerCanAddInternalSystemWindow;
- mInputWindowHandle.trustedOverlay |= InputMonitor.isTrustedOverlay(mAttrs.type);
// Make sure we initial all fields before adding to parentWindow, to prevent exception
// during onDisplayChanged.
@@ -1496,9 +1508,9 @@
}
super.onDisplayChanged(dc);
// Window was not laid out for this display yet, so make sure mLayoutSeq does not match.
- if (dc != null && mInputWindowHandle.displayId != dc.getDisplayId()) {
+ if (dc != null && mInputWindowHandle.getDisplayId() != dc.getDisplayId()) {
mLayoutSeq = dc.mLayoutSeq - 1;
- mInputWindowHandle.displayId = dc.getDisplayId();
+ mInputWindowHandle.setDisplayId(dc.getDisplayId());
}
}
@@ -2470,7 +2482,9 @@
}
String name = getName();
mInputChannel = mWmService.mInputManager.createInputChannel(name);
- mInputWindowHandle.token = mInputChannel.getToken();
+ mInputChannelToken = mInputChannel.getToken();
+ mInputWindowHandle.setToken(mInputChannelToken);
+ mWmService.mInputToWindowMap.put(mInputChannelToken, this);
if (outInputChannel != null) {
mInputChannel.copyTo(outInputChannel);
} else {
@@ -2479,7 +2493,6 @@
// Create fake event receiver that simply reports all events as handled.
mDeadWindowEventReceiver = new DeadWindowEventReceiver(mInputChannel);
}
- mWmService.mInputToWindowMap.put(mInputWindowHandle.token, this);
}
void disposeInputChannel() {
@@ -2487,17 +2500,19 @@
mDeadWindowEventReceiver.dispose();
mDeadWindowEventReceiver = null;
}
+ if (mInputChannelToken != null) {
+ // Unregister server channel first otherwise it complains about broken channel.
+ mWmService.mInputManager.removeInputChannel(mInputChannelToken);
+ mWmService.mKeyInterceptionInfoForToken.remove(mInputChannelToken);
+ mWmService.mInputToWindowMap.remove(mInputChannelToken);
+ mInputChannelToken = null;
+ }
- // unregister server channel first otherwise it complains about broken channel
if (mInputChannel != null) {
- mWmService.mInputManager.removeInputChannel(mInputChannel.getToken());
-
mInputChannel.dispose();
mInputChannel = null;
}
- mWmService.mKeyInterceptionInfoForToken.remove(mInputWindowHandle.token);
- mWmService.mInputToWindowMap.remove(mInputWindowHandle.token);
- mInputWindowHandle.token = null;
+ mInputWindowHandle.setToken(null);
}
/** Returns true if the replacement window was removed. */
@@ -2567,11 +2582,8 @@
}
}
- int getSurfaceTouchableRegion(InputWindowHandle inputWindowHandle, int flags) {
+ int getSurfaceTouchableRegion(Region region, int flags) {
final boolean modal = (flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0;
- final Region region = inputWindowHandle.touchableRegion;
- setTouchableRegionCropIfNeeded(inputWindowHandle);
-
if (modal) {
flags |= FLAG_NOT_TOUCH_MODAL;
if (mActivityRecord != null) {
@@ -2593,7 +2605,10 @@
}
// Translate to surface based coordinates.
- region.translate(-mWindowFrames.mFrame.left, -mWindowFrames.mFrame.top);
+ final Rect frame = mWindowFrames.mFrame;
+ if (frame.left != 0 || frame.top != 0) {
+ region.translate(-frame.left, -frame.top);
+ }
// TODO(b/139804591): sizecompat layout needs to be reworked. Currently mFrame is post-
// scaling but the existing logic doesn't expect that. The result is that the already-
@@ -3442,7 +3457,9 @@
break;
case TOUCHABLE_INSETS_REGION: {
outRegion.set(mGivenTouchableRegion);
- outRegion.translate(frame.left, frame.top);
+ if (frame.left != 0 || frame.top != 0) {
+ outRegion.translate(frame.left, frame.top);
+ }
break;
}
}
@@ -3469,22 +3486,6 @@
}
}
- private void setTouchableRegionCropIfNeeded(InputWindowHandle handle) {
- final Task task = getTask();
- if (task == null || !task.cropWindowsToStackBounds()) {
- handle.setTouchableRegionCrop(null);
- return;
- }
-
- final Task stack = task.getRootTask();
- if (stack == null || inFreeformWindowingMode()) {
- handle.setTouchableRegionCrop(null);
- return;
- }
-
- handle.setTouchableRegionCrop(stack.getSurfaceControl());
- }
-
private void cropRegionToStackBoundsIfNeeded(Region region) {
final Task task = getTask();
if (task == null || !task.cropWindowsToStackBounds()) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index d845b12..72aa766 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -488,6 +488,9 @@
mSurfaceFormat = format;
w.setHasSurface(true);
+ // The surface instance is changed. Make sure the input info can be applied to the
+ // new surface, e.g. relaunch activity.
+ w.mInputWindowHandle.forceChange();
ProtoLog.i(WM_SHOW_SURFACE_ALLOC,
" CREATE SURFACE %s IN SESSION %s: pid=%d format=%d flags=0x%x / %s",
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 21cb9a7..db93c89 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -17,7 +17,7 @@
package com.android.server.wm;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
-import static android.view.Surface.SCALING_MODE_SCALE_TO_WINDOW;
+import static android.view.SurfaceControl.METADATA_OWNER_PID;
import static android.view.SurfaceControl.METADATA_OWNER_UID;
import static android.view.SurfaceControl.METADATA_WINDOW_TYPE;
@@ -105,6 +105,7 @@
.setFlags(flags)
.setMetadata(METADATA_WINDOW_TYPE, windowType)
.setMetadata(METADATA_OWNER_UID, ownerUid)
+ .setMetadata(METADATA_OWNER_PID, mWindowSession.mPid)
.setCallsite("WindowSurfaceController");
final boolean useBLAST = mService.mUseBLAST && ((win.getAttrs().privateFlags &
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index c1d5f19..3a00196 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -650,7 +650,7 @@
base::Result<std::shared_ptr<KeyCharacterMap>> ret =
KeyCharacterMap::loadContents(filenameChars.c_str(), contentsChars.c_str(),
- KeyCharacterMap::FORMAT_OVERLAY);
+ KeyCharacterMap::Format::OVERLAY);
if (ret) {
result = *ret;
}
diff --git a/services/core/xsd/cec-config/cec-config.xsd b/services/core/xsd/cec-config/cec-config.xsd
index 0801c88..ca02f70 100644
--- a/services/core/xsd/cec-config/cec-config.xsd
+++ b/services/core/xsd/cec-config/cec-config.xsd
@@ -12,6 +12,7 @@
</xs:element>
<xs:complexType name="setting">
<xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="value-type" type="xs:string"/>
<xs:attribute name="user-configurable" type="xs:boolean"/>
<xs:element name="allowed-values" type="value-list" minOccurs="1" maxOccurs="1"/>
<xs:element name="default-value" type="value" minOccurs="1" maxOccurs="1"/>
@@ -23,5 +24,6 @@
</xs:complexType>
<xs:complexType name="value">
<xs:attribute name="string-value" type="xs:string"/>
+ <xs:attribute name="int-value" type="xs:int"/>
</xs:complexType>
</xs:schema>
diff --git a/services/core/xsd/cec-config/schema/current.txt b/services/core/xsd/cec-config/schema/current.txt
index 34faf45..00dd15b 100644
--- a/services/core/xsd/cec-config/schema/current.txt
+++ b/services/core/xsd/cec-config/schema/current.txt
@@ -12,15 +12,19 @@
method public com.android.server.hdmi.cec.config.Value getDefaultValue();
method public String getName();
method public boolean getUserConfigurable();
+ method public String getValueType();
method public void setAllowedValues(com.android.server.hdmi.cec.config.ValueList);
method public void setDefaultValue(com.android.server.hdmi.cec.config.Value);
method public void setName(String);
method public void setUserConfigurable(boolean);
+ method public void setValueType(String);
}
public class Value {
ctor public Value();
+ method public int getIntValue();
method public String getStringValue();
+ method public void setIntValue(int);
method public void setStringValue(String);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 6fea2aa..412f582 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -36,10 +36,10 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Slog;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.pm.UserRestrictionsUtils;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
index 279c678..3067d45 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
@@ -26,12 +26,12 @@
import android.content.pm.ServiceInfo;
import android.os.Handler;
import android.os.IBinder;
+import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.server.am.PersistentConnection;
import com.android.server.appbinding.AppBindingUtils;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
index d616ed3..15bc93e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
@@ -18,11 +18,11 @@
import android.annotation.UserIdInt;
import android.app.admin.DevicePolicyCache;
import android.app.admin.DevicePolicyManager;
+import android.util.IndentingPrintWriter;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.IndentingPrintWriter;
/**
* Implementation of {@link DevicePolicyCache}, to which {@link DevicePolicyManagerService} pushes
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java
index fec8a80..464d6f5 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java
@@ -15,11 +15,10 @@
*/
package com.android.server.devicepolicy;
+import android.util.IndentingPrintWriter;
import android.util.KeyValueListParser;
import android.util.Slog;
-import com.android.internal.util.IndentingPrintWriter;
-
import java.util.concurrent.TimeUnit;
/**
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 3bfcb6d..10e03b3 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -244,6 +244,7 @@
import android.text.format.DateUtils;
import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -269,7 +270,6 @@
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.JournaledFile;
import com.android.internal.util.Preconditions;
import com.android.internal.util.StatLogger;
@@ -8500,31 +8500,42 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, printWriter)) return;
- IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " ");
- synchronized (getLockObject()) {
+ try (IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " ")) {
pw.println("Current Device Policy Manager state:");
pw.increaseIndent();
- mOwners.dump(pw);
- pw.println();
- mDeviceAdminServiceController.dump(pw);
- pw.println();
- dumpDevicePolicyData(pw);
- pw.println();
- mConstants.dump(pw);
- pw.println();
- mStatLogger.dump(pw);
- pw.println();
+ dumpImmutableState(pw);
+ synchronized (getLockObject()) {
+ mOwners.dump(pw);
+ pw.println();
+ mDeviceAdminServiceController.dump(pw);
+ pw.println();
+ dumpDevicePolicyData(pw);
+ pw.println();
+ mConstants.dump(pw);
+ pw.println();
+ mStatLogger.dump(pw);
+ pw.println();
- pw.println("Encryption Status: " + getEncryptionStatusName(getEncryptionStatus()));
- pw.println();
- mPolicyCache.dump(pw);
- pw.println();
- mStateCache.dump(pw);
+ pw.println("Encryption Status: " + getEncryptionStatusName(getEncryptionStatus()));
+ pw.println();
+ mPolicyCache.dump(pw);
+ pw.println();
+ mStateCache.dump(pw);
+ }
}
}
+ private void dumpImmutableState(IndentingPrintWriter pw) {
+ pw.println("Immutable state:");
+ pw.increaseIndent();
+ pw.printf("mHasFeature=%b\n", mHasFeature);
+ pw.printf("mIsWatch=%b\n", mIsWatch);
+ pw.printf("mHasTelephonyFeature=%b\n", mHasTelephonyFeature);
+ pw.decreaseIndent();
+ }
+
private String getEncryptionStatusName(int encryptionStatus) {
switch (encryptionStatus) {
case DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE:
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceStateCacheImpl.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceStateCacheImpl.java
index c3cb9b0..1215253 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceStateCacheImpl.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceStateCacheImpl.java
@@ -16,9 +16,9 @@
package com.android.server.devicepolicy;
import android.app.admin.DeviceStateCache;
+import android.util.IndentingPrintWriter;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.IndentingPrintWriter;
/**
* Implementation of {@link DeviceStateCache}, to which {@link DevicePolicyManagerService} pushes
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 7649af4..cced359 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -33,6 +33,7 @@
import android.os.UserManagerInternal;
import android.util.ArrayMap;
import android.util.AtomicFile;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -42,7 +43,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.wm.ActivityTaskManagerInternal;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 267c9b7..dfa726f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1345,7 +1345,7 @@
mSystemServiceManager.startService(IorapForwardingService.class);
t.traceEnd();
- if (Build.IS_DEBUGGABLE) {
+ if (Build.IS_DEBUGGABLE && ProfcollectForwardingService.enabled()) {
t.traceBegin("ProfcollectForwardingService");
mSystemServiceManager.startService(ProfcollectForwardingService.class);
t.traceEnd();
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index d14ed5a..1944965 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -31,6 +31,7 @@
import android.os.SystemProperties;
import android.os.UpdateEngine;
import android.os.UpdateEngineCallback;
+import android.provider.DeviceConfig;
import android.util.Log;
import com.android.server.IoThread;
@@ -68,6 +69,14 @@
sSelfService = this;
}
+ /**
+ * Check whether profcollect is enabled through device config.
+ */
+ public static boolean enabled() {
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT, "enabled",
+ false);
+ }
+
@Override
public void onStart() {
if (DEBUG) {
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/FactoryPackageTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/FactoryPackageTest.kt
index 7ae2fe0..e17358d 100644
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/FactoryPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/FactoryPackageTest.kt
@@ -17,8 +17,11 @@
class FactoryPackageTest : BaseHostJUnit4Test() {
companion object {
+ private const val TEST_PKG_NAME = "com.android.server.pm.test.test_app"
+
+ private const val VERSION_ONE = "PackageManagerTestAppVersion1.apk"
+ private const val VERSION_TWO = "PackageManagerTestAppVersion2.apk"
private const val DEVICE_SIDE = "PackageManagerServiceDeviceSideTests.apk"
- private const val DEVICE_SIDE_PKG_NAME = "com.android.server.pm.test.deviceside"
@get:ClassRule
val deviceRebootRule = SystemPreparer.TestRuleDelegate(true)
@@ -37,8 +40,7 @@
@Before
@After
fun removeApk() {
- HostUtils.deleteAllTestPackages(device, preparer)
- device.uninstallPackage(DEVICE_SIDE_PKG_NAME)
+ device.uninstallPackage(TEST_PKG_NAME)
device.deleteFile(filePath.parent.toString())
device.reboot()
}
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt
index f0b60f4..9399030 100644
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt
@@ -23,15 +23,6 @@
import java.io.File
import java.io.FileOutputStream
-internal const val TEST_PKG_NAME = "com.android.server.pm.test.test_app"
-internal const val VERSION_STUB = "PackageManagerTestAppStub.apk"
-internal const val VERSION_ONE = "PackageManagerTestAppVersion1.apk"
-internal const val VERSION_TWO = "PackageManagerTestAppVersion2.apk"
-internal const val VERSION_THREE = "PackageManagerTestAppVersion3.apk"
-internal const val VERSION_THREE_INVALID = "PackageManagerTestAppVersion3Invalid.apk"
-internal const val VERSION_FOUR = "PackageManagerTestAppVersion4.apk"
-internal const val VERSION_OVERRIDE = "PackageManagerTestAppOriginalOverride.apk"
-
internal fun SystemPreparer.pushApk(javaResourceName: String, partition: Partition) =
pushResourceFile(javaResourceName, HostUtils.makePathForApk(javaResourceName, partition)
.toString())
@@ -98,25 +89,12 @@
internal object HostUtils {
- /**
- * Since most of the tests use the same test APKs, consolidate the logic for deleting them
- * before and after a test runs. This also ensures that a failing test doesn't leave an APK on
- * device that could spill over to another test when developing locally.
- *
- * Iterates all partitions since different tests use different partitions.
- */
- fun deleteAllTestPackages(device: ITestDevice, preparer: SystemPreparer) {
- Partition.values().forEach { partition ->
- device.uninstallPackage(TEST_PKG_NAME)
- preparer.deleteApkFolders(partition, VERSION_ONE, VERSION_TWO, VERSION_THREE,
- VERSION_THREE_INVALID, VERSION_FOUR, VERSION_OVERRIDE)
- }
-
- // TODO: There is an optimization that can be made here by hooking into the SystemPreparer's
- // reboot rule, avoiding a reboot cycle by doing the delete in line the built in @After
- // reboot.
- preparer.reboot()
- }
+ fun getDataDir(device: ITestDevice, pkgName: String) =
+ device.executeShellCommand("dumpsys package $pkgName")
+ .lineSequence()
+ .map(String::trim)
+ .single { it.startsWith("dataDir=") }
+ .removePrefix("dataDir=")
fun makePathForApk(fileName: String, partition: Partition) =
makePathForApk(File(fileName), partition)
@@ -158,35 +136,14 @@
}
.map(String::trim)
- fun getDataDir(device: ITestDevice, pkgName: String) =
- packageSection(device, pkgName)
- .singleOrNull { it.startsWith("dataDir=") }
- ?.removePrefix("dataDir=")
-
- /** Return all code paths for a package. This will include hidden system package code paths. */
fun getCodePaths(device: ITestDevice, pkgName: String) =
- (packageSection(device, pkgName) +
- packageSection(device, pkgName, "Hidden system packages"))
+ device.executeShellCommand("pm dump $pkgName")
+ .lineSequence()
+ .map(String::trim)
.filter { it.startsWith("codePath=") }
.map { it.removePrefix("codePath=") }
.toList()
- fun getVersionCode(device: ITestDevice, pkgName: String) =
- packageSection(device, pkgName)
- .filter { it.startsWith("versionCode=") }
- .map { it.removePrefix("versionCode=") }
- .map { it.takeWhile { !it.isWhitespace() } }
- .map { it.toInt() }
- .firstOrNull()
-
- fun getPrivateFlags(device: ITestDevice, pkgName: String) =
- packageSection(device, pkgName)
- .filter { it.startsWith("privateFlags=") }
- .map { it.removePrefix("privateFlags=[ ") }
- .map { it.removeSuffix(" ]") }
- .map { it.split(" ") }
- .firstOrNull()
-
private fun userIdLineSequence(device: ITestDevice, pkgName: String) =
packageSection(device, pkgName)
.filter { it.startsWith("User ") }
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt
index 8594706..37c999c 100644
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt
@@ -33,6 +33,12 @@
class InvalidNewSystemAppTest : BaseHostJUnit4Test() {
companion object {
+ private const val TEST_PKG_NAME = "com.android.server.pm.test.test_app"
+ private const val VERSION_ONE = "PackageManagerTestAppVersion1.apk"
+ private const val VERSION_TWO = "PackageManagerTestAppVersion2.apk"
+ private const val VERSION_THREE_INVALID = "PackageManagerTestAppVersion3Invalid.apk"
+ private const val VERSION_FOUR = "PackageManagerTestAppVersion4.apk"
+
@get:ClassRule
val deviceRebootRule = SystemPreparer.TestRuleDelegate(true)
}
@@ -49,7 +55,7 @@
@Before
@After
fun removeApk() {
- HostUtils.deleteAllTestPackages(device, preparer)
+ device.uninstallPackage(TEST_PKG_NAME)
preparer.deleteFile(filePath.parent.toString())
.reboot()
}
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt
index 0c5816b..4becae6 100644
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt
@@ -34,6 +34,10 @@
companion object {
private const val TEST_PKG_NAME = "com.android.server.pm.test.test_app"
+ private const val VERSION_ONE = "PackageManagerTestAppVersion1.apk"
+ private const val VERSION_TWO = "PackageManagerTestAppVersion2.apk"
+ private const val VERSION_THREE = "PackageManagerTestAppVersion3.apk"
+ private const val NEW_PKG = "PackageManagerTestAppOriginalOverride.apk"
@get:ClassRule
val deviceRebootRule = SystemPreparer.TestRuleDelegate(true)
@@ -50,7 +54,9 @@
@Before
@After
fun deleteApkFolders() {
- HostUtils.deleteAllTestPackages(device, preparer)
+ preparer.deleteApkFolders(Partition.SYSTEM, VERSION_ONE, VERSION_TWO, VERSION_THREE,
+ NEW_PKG)
+ .reboot()
}
@Test
@@ -83,10 +89,10 @@
device.pushFile(file, "${HostUtils.getDataDir(device, TEST_PKG_NAME)}/files/test.txt")
preparer.deleteApkFolders(Partition.SYSTEM, apk)
- .pushApk(VERSION_OVERRIDE, Partition.SYSTEM)
+ .pushApk(NEW_PKG, Partition.SYSTEM)
.reboot()
- assertCodePath(VERSION_OVERRIDE)
+ assertCodePath(NEW_PKG)
// And then reading the data contents back
assertThat(device.pullFileContents(
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemAppScanPriorityTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemAppScanPriorityTest.kt
deleted file mode 100644
index 8d789e0..0000000
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemAppScanPriorityTest.kt
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.pm.test
-
-import com.android.internal.util.test.SystemPreparer
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test
-import com.google.common.truth.Truth.assertThat
-import org.junit.After
-import org.junit.Before
-import org.junit.ClassRule
-import org.junit.Rule
-import org.junit.Test
-import org.junit.rules.RuleChain
-import org.junit.rules.TemporaryFolder
-import org.junit.runner.RunWith
-import java.io.File
-
-/**
- * Pushes APKs onto various system partitions to verify that multiple versions result in the
- * highest version being scanned. Also tries to upgrade/replace these APKs which should result
- * in a version upgrade on reboot.
- *
- * This will also verify that APKs under the same folder/file name across different partitions
- * are parsed as separate entities and don't get combined under the same cache entry.
- *
- * Known limitations:
- * - Does not verify that v1 isn't scanned. It's possible to introduce a bug that upgrades the
- * system on every reboot from v1 -> v2, as this isn't easily visible after scan has finished.
- * This would also have to successfully preserve the app data though, which seems unlikely.
- * - This takes a very long time to run. 105 seconds for the first test case, up to 60 seconds for
- * each following case. It's theoretically possible to parallelize these tests so that each
- * method is run by installing all the apps under different names, requiring only 3 reboots to
- * fully verify, rather than 3 * numTestCases.
- */
-@RunWith(DeviceJUnit4ClassRunner::class)
-class SystemAppScanPriorityTest : BaseHostJUnit4Test() {
-
- companion object {
- @get:ClassRule
- var deviceRebootRule = SystemPreparer.TestRuleDelegate(true)
- }
-
- private val tempFolder = TemporaryFolder()
- private val preparer: SystemPreparer = SystemPreparer(tempFolder,
- SystemPreparer.RebootStrategy.FULL, deviceRebootRule) { this.device }
-
- private var firstReboot = true
-
- @Rule
- @JvmField
- val rules = RuleChain.outerRule(tempFolder).around(preparer)!!
-
- @Before
- @After
- fun deleteFiles() {
- HostUtils.deleteAllTestPackages(device, preparer)
- }
-
- @Before
- fun resetFirstReboot() {
- firstReboot = true
- }
-
- @Test
- fun takeHigherPriority() {
- preparer.pushFile(VERSION_ONE, Partition.VENDOR)
- .pushFile(VERSION_TWO, Partition.PRODUCT)
- .rebootForTest()
-
- assertVersionAndPartition(2, Partition.PRODUCT)
- }
-
- @Test
- fun takeLowerPriority() {
- preparer.pushFile(VERSION_TWO, Partition.VENDOR)
- .pushFile(VERSION_ONE, Partition.PRODUCT)
- .rebootForTest()
-
- assertVersionAndPartition(2, Partition.VENDOR)
- }
-
- @Test
- fun upgradeToHigherOnLowerPriority() {
- preparer.pushFile(VERSION_ONE, Partition.VENDOR)
- .pushFile(VERSION_TWO, Partition.PRODUCT)
- .rebootForTest()
-
- assertVersionAndPartition(2, Partition.PRODUCT)
-
- preparer.pushFile(VERSION_THREE, Partition.VENDOR)
- .rebootForTest()
-
- assertVersionAndPartition(3, Partition.VENDOR)
- }
-
- @Test
- fun upgradeToNewerOnHigherPriority() {
- preparer.pushFile(VERSION_ONE, Partition.VENDOR)
- .pushFile(VERSION_TWO, Partition.PRODUCT)
- .rebootForTest()
-
- assertVersionAndPartition(2, Partition.PRODUCT)
-
- preparer.pushFile(VERSION_THREE, Partition.SYSTEM_EXT)
- .rebootForTest()
-
- assertVersionAndPartition(3, Partition.SYSTEM_EXT)
- }
-
- @Test
- fun replaceNewerOnLowerPriority() {
- preparer.pushFile(VERSION_TWO, Partition.VENDOR)
- .pushFile(VERSION_ONE, Partition.PRODUCT)
- .rebootForTest()
-
- assertVersionAndPartition(2, Partition.VENDOR)
-
- preparer.pushFile(VERSION_THREE, Partition.VENDOR)
- .rebootForTest()
-
- assertVersionAndPartition(3, Partition.VENDOR)
- }
-
- @Test
- fun replaceNewerOnHigherPriority() {
- preparer.pushFile(VERSION_ONE, Partition.VENDOR)
- .pushFile(VERSION_TWO, Partition.PRODUCT)
- .rebootForTest()
-
- assertVersionAndPartition(2, Partition.PRODUCT)
-
- preparer.pushFile(VERSION_THREE, Partition.PRODUCT)
- .rebootForTest()
-
- assertVersionAndPartition(3, Partition.PRODUCT)
- }
-
- @Test
- fun fallbackToLowerPriority() {
- preparer.pushFile(VERSION_TWO, Partition.VENDOR)
- .pushFile(VERSION_ONE, Partition.PRODUCT)
- .pushFile(VERSION_THREE, Partition.SYSTEM_EXT)
- .rebootForTest()
-
- assertVersionAndPartition(3, Partition.SYSTEM_EXT)
-
- preparer.deleteFile(VERSION_THREE, Partition.SYSTEM_EXT)
- .rebootForTest()
-
- assertVersionAndPartition(2, Partition.VENDOR)
- }
-
- @Test
- fun fallbackToHigherPriority() {
- preparer.pushFile(VERSION_THREE, Partition.VENDOR)
- .pushFile(VERSION_ONE, Partition.PRODUCT)
- .pushFile(VERSION_TWO, Partition.SYSTEM_EXT)
- .rebootForTest()
-
- assertVersionAndPartition(3, Partition.VENDOR)
-
- preparer.deleteFile(VERSION_THREE, Partition.VENDOR)
- .rebootForTest()
-
- assertVersionAndPartition(2, Partition.SYSTEM_EXT)
- }
-
- @Test
- fun removeBoth() {
- preparer.pushFile(VERSION_ONE, Partition.VENDOR)
- .pushFile(VERSION_TWO, Partition.PRODUCT)
- .rebootForTest()
-
- assertVersionAndPartition(2, Partition.PRODUCT)
-
- preparer.deleteFile(VERSION_ONE, Partition.VENDOR)
- .deleteFile(VERSION_TWO, Partition.PRODUCT)
- .rebootForTest()
-
- assertThat(device.getAppPackageInfo(TEST_PKG_NAME)).isNull()
- }
-
- private fun assertVersionAndPartition(versionCode: Int, partition: Partition) {
- assertThat(HostUtils.getVersionCode(device, TEST_PKG_NAME)).isEqualTo(versionCode)
-
- val privateFlags = HostUtils.getPrivateFlags(device, TEST_PKG_NAME)
-
- when (partition) {
- Partition.SYSTEM,
- Partition.SYSTEM_PRIVILEGED -> {
- assertThat(privateFlags).doesNotContain(Partition.VENDOR.toString())
- assertThat(privateFlags).doesNotContain(Partition.PRODUCT.toString())
- assertThat(privateFlags).doesNotContain(Partition.SYSTEM_EXT.toString())
- }
- Partition.VENDOR -> {
- assertThat(privateFlags).contains(Partition.VENDOR.toString())
- assertThat(privateFlags).doesNotContain(Partition.PRODUCT.toString())
- assertThat(privateFlags).doesNotContain(Partition.SYSTEM_EXT.toString())
- }
- Partition.PRODUCT -> {
- assertThat(privateFlags).doesNotContain(Partition.VENDOR.toString())
- assertThat(privateFlags).contains(Partition.PRODUCT.toString())
- assertThat(privateFlags).doesNotContain(Partition.SYSTEM_EXT.toString())
- }
- Partition.SYSTEM_EXT -> {
- assertThat(privateFlags).doesNotContain(Partition.VENDOR.toString())
- assertThat(privateFlags).doesNotContain(Partition.PRODUCT.toString())
- assertThat(privateFlags).contains(Partition.SYSTEM_EXT.toString())
- }
- }.run { /* exhaust */ }
- }
-
- // Following methods don't use HostUtils in order to test cache behavior when using the same
- // name across partitions. Writes all files under the version 1 name.
- private fun makeDevicePath(partition: Partition) =
- partition.baseAppFolder
- .resolve(File(VERSION_ONE).nameWithoutExtension)
- .resolve(VERSION_ONE)
- .toString()
-
- private fun SystemPreparer.pushFile(file: String, partition: Partition) =
- pushResourceFile(file, makeDevicePath(partition))
-
- private fun SystemPreparer.deleteFile(file: String, partition: Partition) =
- deleteFile(makeDevicePath(partition))
-
- /**
- * Custom reboot used to write app data after the first reboot. This can then be verified
- * after each subsequent reboot to ensure no data is lost.
- */
- private fun SystemPreparer.rebootForTest() {
- if (firstReboot) {
- firstReboot = false
- preparer.reboot()
-
- val file = tempFolder.newFile()
- file.writeText("Test")
- pushFile(file, "${HostUtils.getDataDir(device, TEST_PKG_NAME)}/files/test.txt")
- } else {
- val versionBefore = HostUtils.getVersionCode(device, TEST_PKG_NAME)
- preparer.reboot()
- val versionAfter = HostUtils.getVersionCode(device, TEST_PKG_NAME)
-
- if (versionBefore != null && versionAfter != null) {
- val fileContents = device.pullFileContents(
- "${HostUtils.getDataDir(device, TEST_PKG_NAME)}/files/test.txt")
- if (versionAfter < versionBefore) {
- // A downgrade will wipe app data
- assertThat(fileContents).isNull()
- } else {
- // An upgrade or update will preserve app data
- assertThat(fileContents).isEqualTo("Test")
- }
- }
- }
- }
-}
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt
index 99dff08..46120af 100644
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt
@@ -37,6 +37,9 @@
class SystemStubMultiUserDisableUninstallTest : BaseHostJUnit4Test() {
companion object {
+ private const val TEST_PKG_NAME = "com.android.server.pm.test.test_app"
+ private const val VERSION_STUB = "PackageManagerTestAppStub.apk"
+ private const val VERSION_ONE = "PackageManagerTestAppVersion1.apk"
/**
* How many total users on device to test, including primary. This will clean up any
@@ -87,12 +90,6 @@
savedDevice?.removeUser(it)
}
- savedDevice?.let { device ->
- savedPreparer?.let { preparer ->
- HostUtils.deleteAllTestPackages(device, preparer)
- }
- }
-
savedDevice?.uninstallPackage(TEST_PKG_NAME)
savedDevice?.deleteFile(stubFile.parent.toString())
savedDevice?.deleteFile(deviceCompressedFile.parent.toString())
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index 736a7be..2c92ae4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -27,9 +27,11 @@
import static com.android.server.RescueParty.LEVEL_FACTORY_RESET;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import android.content.ContentResolver;
@@ -79,8 +81,11 @@
private static final String CALLING_PACKAGE2 = "com.package.name2";
private static final String NAMESPACE1 = "namespace1";
private static final String NAMESPACE2 = "namespace2";
+ private static final String NAMESPACE3 = "namespace3";
private static final String PROP_DEVICE_CONFIG_DISABLE_FLAG =
"persist.device_config.configuration.disable_rescue_party";
+ private static final String PROP_DISABLE_FACTORY_RESET_FLAG =
+ "persist.device_config.configuration.disable_rescue_party_factory_reset";
private MockitoSession mSession;
private HashMap<String, String> mSystemSettingsMap;
@@ -183,27 +188,38 @@
@Test
public void testBootLoopDetectionWithExecutionForAllRescueLevels() {
+ RescueParty.onSettingsProviderPublished(mMockContext);
+ verify(() -> Settings.Config.registerMonitorCallback(eq(mMockContentResolver),
+ mMonitorCallbackCaptor.capture()));
+
noteBoot();
verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+ // Record DeviceConfig accesses
+ RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
+ RemoteCallback monitorCallback = mMonitorCallbackCaptor.getValue();
+ monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE1));
+ monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE2));
+
+ final String[] expectedAllResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2};
+
noteBoot();
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, /*resetNamespaces=*/ null);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, expectedAllResetNamespaces);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
noteBoot();
- verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, /*resetNamespaces=*/ null);
+ verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, expectedAllResetNamespaces);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
noteBoot();
- verify(() -> RecoverySystem.rebootPromptAndWipeUserData(mMockContext, RescueParty.TAG));
assertEquals(LEVEL_FACTORY_RESET,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
}
@@ -230,7 +246,6 @@
notePersistentAppCrash();
- verify(() -> RecoverySystem.rebootPromptAndWipeUserData(mMockContext, RescueParty.TAG));
assertEquals(LEVEL_FACTORY_RESET,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
}
@@ -247,6 +262,7 @@
monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE1));
monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE2));
monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE2, NAMESPACE2));
+ monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE2, NAMESPACE3));
// Fake DeviceConfig value changes
monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE1));
verify(mMockPackageWatchdog).startObservingHealth(observer,
@@ -255,10 +271,15 @@
verify(mMockPackageWatchdog, times(2)).startObservingHealth(eq(observer),
mPackageListCaptor.capture(),
eq(RescueParty.DEFAULT_OBSERVING_DURATION_MS));
+ monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE3));
+ verify(mMockPackageWatchdog).startObservingHealth(observer,
+ Arrays.asList(CALLING_PACKAGE2), RescueParty.DEFAULT_OBSERVING_DURATION_MS);
assertTrue(mPackageListCaptor.getValue().containsAll(
Arrays.asList(CALLING_PACKAGE1, CALLING_PACKAGE2)));
// Perform and verify scoped resets
final String[] expectedResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2};
+ final String[] expectedAllResetNamespaces =
+ new String[]{NAMESPACE1, NAMESPACE2, NAMESPACE3};
observer.execute(new VersionedPackage(
CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH);
verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, expectedResetNamespaces);
@@ -273,13 +294,12 @@
observer.execute(new VersionedPackage(
CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING);
- verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, /*resetNamespaces=*/null);
+ verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, expectedAllResetNamespaces);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
observer.execute(new VersionedPackage(
CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH);
- verify(() -> RecoverySystem.rebootPromptAndWipeUserData(mMockContext, RescueParty.TAG));
assertTrue(RescueParty.isAttemptingFactoryReset());
}
@@ -288,7 +308,6 @@
for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
noteBoot();
}
- verify(() -> RecoverySystem.rebootPromptAndWipeUserData(mMockContext, RescueParty.TAG));
assertTrue(RescueParty.isAttemptingFactoryReset());
}
@@ -337,12 +356,25 @@
assertEquals(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage,
PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING), false);
- // Restore the property value initalized in SetUp()
+ // Restore the property value initialized in SetUp()
SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(true));
SystemProperties.set(PROP_DEVICE_CONFIG_DISABLE_FLAG, Boolean.toString(false));
}
@Test
+ public void testDisablingFactoryResetByDeviceConfigFlag() {
+ SystemProperties.set(PROP_DISABLE_FACTORY_RESET_FLAG, Boolean.toString(true));
+
+ for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
+ noteBoot();
+ }
+ assertFalse(RescueParty.isAttemptingFactoryReset());
+
+ // Restore the property value initialized in SetUp()
+ SystemProperties.set(PROP_DISABLE_FACTORY_RESET_FLAG, "");
+ }
+
+ @Test
public void testHealthCheckLevels() {
RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
@@ -437,7 +469,7 @@
eq(resetMode), anyInt()));
// Verify DeviceConfig resets
if (resetNamespaces == null) {
- verify(() -> DeviceConfig.resetToDefaults(resetMode, /*namespace=*/ null));
+ verify(() -> DeviceConfig.resetToDefaults(anyInt(), anyString()), never());
} else {
for (String namespace : resetNamespaces) {
verify(() -> DeviceConfig.resetToDefaults(resetMode, namespace));
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index db4aba5..8e4942e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -47,6 +47,7 @@
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_LONG_TIME;
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_SHORT_TIME;
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION;
+import static com.android.server.alarm.AlarmManagerService.Constants.KEY_LAZY_BATCHING;
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_LISTENER_TIMEOUT;
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MAX_INTERVAL;
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MIN_FUTURITY;
@@ -62,6 +63,7 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
@@ -365,7 +367,7 @@
}
private void setIdleUntilAlarm(int type, long triggerTime, PendingIntent pi) {
- setTestAlarm(type, triggerTime, pi, 0, FLAG_IDLE_UNTIL, TEST_CALLING_UID);
+ setTestAlarm(type, triggerTime, pi, 0, FLAG_IDLE_UNTIL | FLAG_STANDALONE, TEST_CALLING_UID);
}
private void setWakeFromIdle(int type, long triggerTime, PendingIntent pi) {
@@ -410,6 +412,12 @@
mService.mConstants.onPropertiesChanged(mDeviceConfigProperties);
}
+ private void setDeviceConfigBoolean(String key, boolean val) {
+ mDeviceConfigKeys.add(key);
+ doReturn(val).when(mDeviceConfigProperties).getBoolean(eq(key), anyBoolean());
+ mService.mConstants.onPropertiesChanged(mDeviceConfigProperties);
+ }
+
/**
* Lowers quotas to make testing feasible. Careful while calling as this will replace any
* existing settings for the calling test.
@@ -1382,6 +1390,35 @@
}
}
+ @Test
+ public void alarmStoreMigration() {
+ setDeviceConfigBoolean(KEY_LAZY_BATCHING, false);
+ final int numAlarms = 10;
+ final PendingIntent[] pis = new PendingIntent[numAlarms];
+ for (int i = 0; i < numAlarms; i++) {
+ pis[i] = getNewMockPendingIntent();
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 1, pis[i]);
+ }
+
+ final ArrayList<Alarm> alarmsBefore = mService.mAlarmStore.asList();
+ assertEquals(numAlarms, alarmsBefore.size());
+ for (int i = 0; i < numAlarms; i++) {
+ final PendingIntent pi = pis[i];
+ assertTrue(i + "th PendingIntent missing: ",
+ alarmsBefore.removeIf(a -> a.matches(pi, null)));
+ }
+
+ setDeviceConfigBoolean(KEY_LAZY_BATCHING, true);
+
+ final ArrayList<Alarm> alarmsAfter = mService.mAlarmStore.asList();
+ assertEquals(numAlarms, alarmsAfter.size());
+ for (int i = 0; i < numAlarms; i++) {
+ final PendingIntent pi = pis[i];
+ assertTrue(i + "th PendingIntent missing: ",
+ alarmsAfter.removeIf(a -> a.matches(pi, null)));
+ }
+ }
+
@After
public void tearDown() {
if (mMockingSession != null) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java
index c4fc61a..42fa3d4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java
@@ -16,6 +16,9 @@
package com.android.server.alarm;
+import static android.app.AlarmManager.ELAPSED_REALTIME;
+import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
+
import static com.android.server.alarm.Constants.TEST_CALLING_PACKAGE;
import static com.android.server.alarm.Constants.TEST_CALLING_UID;
@@ -23,35 +26,50 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.platform.test.annotations.Presubmit;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
import java.util.ArrayList;
@Presubmit
-@RunWith(AndroidJUnit4.class)
+@RunWith(Parameterized.class)
public class AlarmStoreTest {
- private AlarmStore mAlarmStore;
- @Before
- public void setUp() {
- mAlarmStore = new BatchingAlarmStore(null);
+ @Parameter
+ public AlarmStore mAlarmStore;
+
+ @Parameters
+ public static Object[] stores() {
+ return new AlarmStore[]{
+ new LazyAlarmStore(),
+ new BatchingAlarmStore(),
+ };
}
private static Alarm createAlarm(long whenElapsed, long windowLength) {
- return createAlarm(AlarmManager.ELAPSED_REALTIME, whenElapsed, windowLength, 0);
+ return createAlarm(ELAPSED_REALTIME, whenElapsed, windowLength, 0);
}
private static Alarm createWakeupAlarm(long whenElapsed, long windowLength, int flags) {
- return createAlarm(AlarmManager.ELAPSED_REALTIME_WAKEUP, whenElapsed, windowLength, flags);
+ return createAlarm(ELAPSED_REALTIME_WAKEUP, whenElapsed, windowLength, flags);
+ }
+
+ private static Alarm createAlarmClock(long whenElapsed) {
+ final AlarmManager.AlarmClockInfo info = new AlarmManager.AlarmClockInfo(whenElapsed,
+ mock(PendingIntent.class));
+ return new Alarm(ELAPSED_REALTIME_WAKEUP, whenElapsed, whenElapsed, 0, 0,
+ mock(PendingIntent.class), null, null, null, 0, info, TEST_CALLING_UID,
+ TEST_CALLING_PACKAGE);
}
private static Alarm createAlarm(int type, long whenElapsed, long windowLength, int flags) {
@@ -206,4 +224,21 @@
});
assertEquals(7, mAlarmStore.getNextDeliveryTime());
}
+
+ @Test
+ public void alarmClockRemovalListener() {
+ final Runnable onRemoved = mock(Runnable.class);
+ mAlarmStore.setAlarmClockRemovalListener(onRemoved);
+
+ final Alarm simpleAlarm = createAlarm(5, 0);
+ final Alarm alarmClock = createAlarmClock(10);
+
+ addAlarmsToStore(simpleAlarm, alarmClock);
+
+ mAlarmStore.remove(simpleAlarm::equals);
+ verifyZeroInteractions(onRemoved);
+
+ mAlarmStore.remove(alarmClock::equals);
+ verify(onRemoved).run();
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
index 5c2b8ce..b955199 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
@@ -27,17 +27,18 @@
import android.os.Binder;
import android.os.IBinder;
import android.view.SurfaceControl;
-import android.view.SurfaceControl.DisplayPrimaries;
import android.view.SurfaceControl.CieXyz;
+import android.view.SurfaceControl.DisplayPrimaries;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.R;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.internal.R;
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;
@@ -190,6 +191,7 @@
* Matrix should match the precalculated one for given cct and display primaries.
*/
@Test
+ @Ignore
public void displayWhiteBalance_validateTransformMatrix() {
DisplayPrimaries displayPrimaries = new DisplayPrimaries();
displayPrimaries.red = new CieXyz();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index e82ff34..aed590b 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -27,6 +27,7 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -74,11 +75,16 @@
private static final int MODE_FULLSCREEN =
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
- @Mock private AccessibilityManagerService mService;
- @Mock private MagnificationController.TransitionCallBack mTransitionCallBack;
- @Mock private Context mContext;
- @Mock private FullScreenMagnificationController mScreenMagnificationController;
- @Captor private ArgumentCaptor<MagnificationAnimationCallback> mCallbackArgumentCaptor;
+ @Mock
+ private AccessibilityManagerService mService;
+ @Mock
+ private MagnificationController.TransitionCallBack mTransitionCallBack;
+ @Mock
+ private Context mContext;
+ @Mock
+ private FullScreenMagnificationController mScreenMagnificationController;
+ @Captor
+ private ArgumentCaptor<MagnificationAnimationCallback> mCallbackArgumentCaptor;
private MockWindowMagnificationConnection mMockConnection;
private WindowMagnificationManager mWindowMagnificationManager;
@@ -96,7 +102,8 @@
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, DEFAULT_SCALE,
CURRENT_USER_ID);
mWindowMagnificationManager = Mockito.spy(
- new WindowMagnificationManager(mContext, CURRENT_USER_ID));
+ new WindowMagnificationManager(mContext, CURRENT_USER_ID,
+ mock(WindowMagnificationManager.Callback.class)));
mMockConnection = new MockWindowMagnificationConnection(true);
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
mMagnificationController = new MagnificationController(mService, new Object(), mContext,
@@ -261,6 +268,19 @@
assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
}
+ @Test
+ public void onPerformScaleAction_magnifierEnabled_handleScaleChange() throws RemoteException {
+ final float newScale = 4.0f;
+ setMagnificationEnabled(MODE_WINDOW);
+
+ mMagnificationController.onPerformScaleAction(TEST_DISPLAY, newScale);
+
+ verify(mWindowMagnificationManager).setScale(eq(TEST_DISPLAY), eq(newScale));
+ verify(mWindowMagnificationManager).persistScale(eq(TEST_DISPLAY));
+ verify(mService).onMagnificationScaleChanged(eq(TEST_DISPLAY),
+ eq(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW));
+ }
+
private void setMagnificationEnabled(int mode) throws RemoteException {
setMagnificationEnabled(mode, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
index a10e0ba..41b6e98 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
@@ -70,7 +70,8 @@
@Before
public void setUp() throws RemoteException {
mContext = InstrumentationRegistry.getContext();
- mWindowMagnificationManager = new WindowMagnificationManager(mContext, 0);
+ mWindowMagnificationManager = new WindowMagnificationManager(mContext, 0,
+ mock(WindowMagnificationManager.Callback.class));
mMockConnection = new MockWindowMagnificationConnection();
mWindowMagnificationGestureHandler = new WindowMagnificationGestureHandler(
mContext, mWindowMagnificationManager, mock(ScaleChangedListener.class),
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
index d5be3ed..f26c86c 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
@@ -16,7 +16,6 @@
package com.android.server.accessibility.magnification;
-
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
@@ -76,6 +75,8 @@
private StatusBarManagerInternal mMockStatusBarManagerInternal;
@Mock
private MagnificationAnimationCallback mAnimationCallback;
+ @Mock
+ private WindowMagnificationManager.Callback mMockCallback;
private MockContentResolver mResolver;
private WindowMagnificationManager mWindowMagnificationManager;
@@ -86,7 +87,8 @@
LocalServices.addService(StatusBarManagerInternal.class, mMockStatusBarManagerInternal);
mResolver = new MockContentResolver();
mMockConnection = new MockWindowMagnificationConnection();
- mWindowMagnificationManager = new WindowMagnificationManager(mContext, CURRENT_USER_ID);
+ mWindowMagnificationManager = new WindowMagnificationManager(mContext, CURRENT_USER_ID,
+ mMockCallback);
when(mContext.getContentResolver()).thenReturn(mResolver);
doAnswer((InvocationOnMock invocation) -> {
@@ -300,6 +302,17 @@
}
@Test
+ public void onPerformScaleAction_magnifierEnabled_notifyAction() throws RemoteException {
+ final float newScale = 4.0f;
+ mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3.0f, NaN, NaN);
+
+ mMockConnection.getConnectionCallback().onPerformScaleAction(TEST_DISPLAY, newScale);
+
+ verify(mMockCallback).onPerformScaleAction(eq(TEST_DISPLAY), eq(newScale));
+ }
+
+ @Test
public void binderDied_windowMagnifierIsEnabled_resetState() throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, NaN, NaN);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
index ae9c618..a92357f 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
@@ -17,6 +17,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static junit.framework.Assert.assertTrue;
+
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
@@ -77,14 +79,16 @@
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
- + " <value string-value=\"0\" />"
- + " <value string-value=\"1\" />"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ " </allowed-values>"
- + " <default-value string-value=\"1\" />"
+ + " <default-value int-value=\"1\" />"
+ " </setting>"
+ " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ " user-configurable=\"false\">"
+ " <allowed-values>"
+ " <value string-value=\"to_tv\" />"
@@ -123,14 +127,16 @@
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
- + " <value string-value=\"0\" />"
- + " <value string-value=\"1\" />"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ " </allowed-values>"
- + " <default-value string-value=\"1\" />"
+ + " <default-value int-value=\"1\" />"
+ " </setting>"
+ " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
+ " <value string-value=\"to_tv\" />"
@@ -152,14 +158,16 @@
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
- + " <value string-value=\"0\" />"
- + " <value string-value=\"1\" />"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ " </allowed-values>"
- + " <default-value string-value=\"1\" />"
+ + " <default-value int-value=\"1\" />"
+ " </setting>"
+ " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
+ " <value string-value=\"to_tv\" />"
@@ -172,6 +180,7 @@
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ " user-configurable=\"false\">"
+ " <allowed-values>"
+ " <value string-value=\"to_tv\" />"
@@ -186,31 +195,32 @@
}
@Test
- public void getAllowedValues_NoMasterXml() {
+ public void isStringValueType_NoMasterXml() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter, null, null);
assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getAllowedValues("foo"));
+ () -> hdmiCecConfig.isStringValueType("foo"));
}
@Test
- public void getAllowedValues_InvalidSetting() {
+ public void isStringValueType_InvalidSetting() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter,
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ "</cec-settings>", null);
assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getAllowedValues("foo"));
+ () -> hdmiCecConfig.isStringValueType("foo"));
}
@Test
- public void getAllowedValues_BasicSanity() {
+ public void isStringValueType_BasicSanity() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter,
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
+ " <value string-value=\"to_tv\" />"
@@ -220,7 +230,107 @@
+ " <default-value string-value=\"to_tv\" />"
+ " </setting>"
+ "</cec-settings>", null);
- assertThat(hdmiCecConfig.getAllowedValues(
+ assertTrue(hdmiCecConfig.isStringValueType(
+ HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP));
+ }
+
+ @Test
+ public void isIntValueType_NoMasterXml() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter, null, null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.isIntValueType("foo"));
+ }
+
+ @Test
+ public void isIntValueType_InvalidSetting() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.isIntValueType("foo"));
+ }
+
+ @Test
+ public void isIntValueType_BasicSanity() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertTrue(hdmiCecConfig.isIntValueType(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED));
+ }
+
+ @Test
+ public void getAllowedStringValues_NoMasterXml() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter, null, null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getAllowedStringValues("foo"));
+ }
+
+ @Test
+ public void getAllowedStringValues_InvalidSetting() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getAllowedStringValues("foo"));
+ }
+
+ @Test
+ public void getAllowedStringValues_InvalidValueType() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getAllowedStringValues(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED));
+ }
+
+ @Test
+ public void getAllowedStringValues_BasicSanity() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value string-value=\"to_tv\" />"
+ + " <value string-value=\"broadcast\" />"
+ + " <value string-value=\"none\" />"
+ + " </allowed-values>"
+ + " <default-value string-value=\"to_tv\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThat(hdmiCecConfig.getAllowedStringValues(
HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP))
.containsExactly(HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV,
HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST,
@@ -228,31 +338,32 @@
}
@Test
- public void getDefaultValue_NoMasterXml() {
+ public void getAllowedIntValues_NoMasterXml() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter, null, null);
assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getDefaultValue("foo"));
+ () -> hdmiCecConfig.getAllowedIntValues("foo"));
}
@Test
- public void getDefaultValue_InvalidSetting() {
+ public void getAllowedIntValues_InvalidSetting() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter,
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ "</cec-settings>", null);
assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getDefaultValue("foo"));
+ () -> hdmiCecConfig.getAllowedIntValues("foo"));
}
@Test
- public void getDefaultValue_BasicSanity() {
+ public void getAllowedIntValues_InvalidValueType() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter,
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
+ " <value string-value=\"to_tv\" />"
@@ -262,32 +373,199 @@
+ " <default-value string-value=\"to_tv\" />"
+ " </setting>"
+ "</cec-settings>", null);
- assertThat(hdmiCecConfig.getDefaultValue(
- HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP))
- .isEqualTo(HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getAllowedIntValues(
+ HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP));
}
@Test
- public void getValue_NoMasterXml() {
+ public void getAllowedIntValues_BasicSanity() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThat(hdmiCecConfig.getAllowedIntValues(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
+ .containsExactly(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED,
+ HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+ }
+
+ @Test
+ public void getDefaultStringValue_NoMasterXml() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter, null, null);
assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getValue("foo"));
+ () -> hdmiCecConfig.getDefaultStringValue("foo"));
}
@Test
- public void getValue_InvalidSetting() {
+ public void getDefaultStringValue_InvalidSetting() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter,
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ "</cec-settings>", null);
assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getValue("foo"));
+ () -> hdmiCecConfig.getDefaultStringValue("foo"));
}
@Test
- public void getValue_GlobalSetting_BasicSanity() {
+ public void getDefaultStringValue_InvalidValueType() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getDefaultStringValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED));
+ }
+
+ @Test
+ public void getDefaultStringValue_BasicSanity() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value string-value=\"to_tv\" />"
+ + " <value string-value=\"broadcast\" />"
+ + " <value string-value=\"none\" />"
+ + " </allowed-values>"
+ + " <default-value string-value=\"to_tv\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThat(hdmiCecConfig.getDefaultStringValue(
+ HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP))
+ .isEqualTo(HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV);
+ }
+
+ @Test
+ public void getDefaultIntValue_NoMasterXml() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter, null, null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getDefaultIntValue("foo"));
+ }
+
+ @Test
+ public void getDefaultIntValue_InvalidSetting() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getDefaultIntValue("foo"));
+ }
+
+ @Test
+ public void getDefaultIntValue_InvalidValueType() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value string-value=\"to_tv\" />"
+ + " <value string-value=\"broadcast\" />"
+ + " <value string-value=\"none\" />"
+ + " </allowed-values>"
+ + " <default-value string-value=\"to_tv\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getDefaultIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP));
+ }
+
+ @Test
+ public void getDefaultIntValue_BasicSanity() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThat(hdmiCecConfig.getDefaultIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
+ .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+ }
+
+ @Test
+ public void getStringValue_NoMasterXml() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter, null, null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getStringValue("foo"));
+ }
+
+ @Test
+ public void getStringValue_InvalidSetting() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getStringValue("foo"));
+ }
+
+ @Test
+ public void getStringValue_InvalidType() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getStringValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED));
+ }
+
+ @Test
+ public void getStringValue_GlobalSetting_BasicSanity() {
when(mStorageAdapter.retrieveGlobalSetting(mContext,
Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV))
@@ -297,6 +575,7 @@
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
+ " <value string-value=\"to_tv\" />"
@@ -306,13 +585,13 @@
+ " <default-value string-value=\"to_tv\" />"
+ " </setting>"
+ "</cec-settings>", null);
- assertThat(hdmiCecConfig.getValue(
+ assertThat(hdmiCecConfig.getStringValue(
HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP))
.isEqualTo(HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
}
@Test
- public void getValue_SystemProperty_BasicSanity() {
+ public void getStringValue_SystemProperty_BasicSanity() {
when(mStorageAdapter.retrieveSystemProperty(
HdmiCecConfig.SYSPROP_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
HdmiProperties.power_state_change_on_active_source_lost_values
@@ -324,6 +603,7 @@
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"power_state_change_on_active_source_lost\""
+ + " value-type=\"string\""
+ " user-configurable=\"false\">"
+ " <allowed-values>"
+ " <value string-value=\"none\" />"
@@ -332,38 +612,130 @@
+ " <default-value string-value=\"none\" />"
+ " </setting>"
+ "</cec-settings>", null);
- assertThat(hdmiCecConfig.getValue(
+ assertThat(hdmiCecConfig.getStringValue(
HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST))
.isEqualTo(HdmiProperties.power_state_change_on_active_source_lost_values
.STANDBY_NOW.name().toLowerCase());
}
@Test
- public void setValue_NoMasterXml() {
+ public void getIntValue_NoMasterXml() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter, null, null);
assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.setValue("foo", "bar"));
+ () -> hdmiCecConfig.getIntValue("foo"));
}
@Test
- public void setValue_InvalidSetting() {
+ public void getIntValue_InvalidSetting() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter,
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ "</cec-settings>", null);
assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.setValue("foo", "bar"));
+ () -> hdmiCecConfig.getIntValue("foo"));
}
@Test
- public void setValue_NotConfigurable() {
+ public void getIntValue_InvalidType() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter,
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value string-value=\"to_tv\" />"
+ + " <value string-value=\"broadcast\" />"
+ + " <value string-value=\"none\" />"
+ + " </allowed-values>"
+ + " <default-value string-value=\"to_tv\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP));
+ }
+
+ @Test
+ public void getIntValue_GlobalSetting_BasicSanity() {
+ when(mStorageAdapter.retrieveGlobalSetting(mContext,
+ Global.HDMI_CONTROL_ENABLED,
+ Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED)))
+ .thenReturn(Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED));
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThat(hdmiCecConfig.getIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
+ .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+ }
+
+ @Test
+ public void getIntValue_SystemProperty_BasicSanity() {
+ when(mStorageAdapter.retrieveSystemProperty(
+ HdmiCecConfig.SYSPROP_SYSTEM_AUDIO_MODE_MUTING,
+ Integer.toString(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_ENABLED)))
+ .thenReturn(Integer.toString(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED));
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"system_audio_mode_muting\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThat(hdmiCecConfig.getIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING))
+ .isEqualTo(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED);
+ }
+
+ @Test
+ public void setStringValue_NoMasterXml() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter, null, null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.setStringValue("foo", "bar"));
+ }
+
+ @Test
+ public void setStringValue_InvalidSetting() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.setStringValue("foo", "bar"));
+ }
+
+ @Test
+ public void setStringValue_NotConfigurable() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ " user-configurable=\"false\">"
+ " <allowed-values>"
+ " <value string-value=\"to_tv\" />"
@@ -374,18 +746,19 @@
+ " </setting>"
+ "</cec-settings>", null);
assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.setValue(
+ () -> hdmiCecConfig.setStringValue(
HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST));
}
@Test
- public void setValue_InvalidValue() {
+ public void setStringValue_InvalidValue() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter,
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
+ " <value string-value=\"to_tv\" />"
@@ -396,18 +769,19 @@
+ " </setting>"
+ "</cec-settings>", null);
assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.setValue(
+ () -> hdmiCecConfig.setStringValue(
HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
"bar"));
}
@Test
- public void setValue_GlobalSetting_BasicSanity() {
+ public void setStringValue_GlobalSetting_BasicSanity() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter,
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
+ " <value string-value=\"to_tv\" />"
@@ -417,7 +791,7 @@
+ " <default-value string-value=\"to_tv\" />"
+ " </setting>"
+ "</cec-settings>", null);
- hdmiCecConfig.setValue(HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
+ hdmiCecConfig.setStringValue(HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
verify(mStorageAdapter).storeGlobalSetting(mContext,
Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
@@ -425,12 +799,13 @@
}
@Test
- public void setValue_SystemProperty_BasicSanity() {
+ public void setStringValue_SystemProperty_BasicSanity() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter,
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"power_state_change_on_active_source_lost\""
+ + " value-type=\"string\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
+ " <value string-value=\"none\" />"
@@ -439,7 +814,7 @@
+ " <default-value string-value=\"none\" />"
+ " </setting>"
+ "</cec-settings>", null);
- hdmiCecConfig.setValue(
+ hdmiCecConfig.setStringValue(
HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
HdmiProperties.power_state_change_on_active_source_lost_values
.STANDBY_NOW.name().toLowerCase());
@@ -448,4 +823,114 @@
HdmiProperties.power_state_change_on_active_source_lost_values
.STANDBY_NOW.name().toLowerCase());
}
+
+ @Test
+ public void setIntValue_NoMasterXml() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter, null, null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.setIntValue("foo", 0));
+ }
+
+ @Test
+ public void setIntValue_InvalidSetting() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.setIntValue("foo", 0));
+ }
+
+ @Test
+ public void setIntValue_NotConfigurable() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"false\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+ HdmiControlManager.HDMI_CEC_CONTROL_DISABLED));
+ }
+
+ @Test
+ public void setIntValue_InvalidValue() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+ 123));
+ }
+
+ @Test
+ public void setIntValue_GlobalSetting_BasicSanity() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ hdmiCecConfig.setIntValue(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+ HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+ verify(mStorageAdapter).storeGlobalSetting(mContext,
+ Global.HDMI_CONTROL_ENABLED,
+ Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED));
+ }
+
+ @Test
+ public void setIntValue_SystemProperty_BasicSanity() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"system_audio_mode_muting\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ hdmiCecConfig.setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
+ HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED);
+ verify(mStorageAdapter).storeSystemProperty(
+ HdmiCecConfig.SYSPROP_SYSTEM_AUDIO_MODE_MUTING,
+ Integer.toString(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
index 4702940..553df3b 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
@@ -130,6 +130,17 @@
}
@Test
+ public void isValid_setTimerProgramTitle() {
+ assertMessageValidity("40:67:47:61:6D:65:20:6F:66:20:54:68:72:6F:6E:65:73").isEqualTo(OK);
+ assertMessageValidity("40:67:4A").isEqualTo(OK);
+
+ assertMessageValidity("4F:67:47:4F:54").isEqualTo(ERROR_DESTINATION);
+ assertMessageValidity("F4:67:47:4F:54").isEqualTo(ERROR_SOURCE);
+ assertMessageValidity("40:67").isEqualTo(ERROR_PARAMETER_SHORT);
+ assertMessageValidity("40:67:47:9A:54").isEqualTo(ERROR_PARAMETER);
+ }
+
+ @Test
public void isValid_setMenuLanguage() {
assertMessageValidity("4F:32:53:50:41").isEqualTo(OK);
assertMessageValidity("0F:32:45:4E:47:8C:49:D3:48").isEqualTo(OK);
@@ -182,6 +193,166 @@
assertMessageValidity("40:0A:30").isEqualTo(ERROR_PARAMETER);
}
+ @Test
+ public void isValid_setAnalogueTimer_clearAnalogueTimer() {
+ assertMessageValidity("04:33:0C:08:10:1E:04:30:08:00:13:AD:06").isEqualTo(OK);
+ assertMessageValidity("04:34:04:0C:16:0F:08:37:00:02:EA:60:03:34").isEqualTo(OK);
+
+ assertMessageValidity("0F:33:0C:08:10:1E:04:30:08:00:13:AD:06")
+ .isEqualTo(ERROR_DESTINATION);
+ assertMessageValidity("F0:34:04:0C:16:0F:08:37:00:02:EA:60:03").isEqualTo(ERROR_SOURCE);
+ assertMessageValidity("04:33:0C:08:10:1E:04:30:08:13:AD:06")
+ .isEqualTo(ERROR_PARAMETER_SHORT);
+ // Out of range Day of Month
+ assertMessageValidity("04:34:20:0C:16:0F:08:37:00:02:EA:60:03").isEqualTo(ERROR_PARAMETER);
+ // Out of range Month of Year
+ assertMessageValidity("04:33:0C:00:10:1E:04:30:08:00:13:AD:06").isEqualTo(ERROR_PARAMETER);
+ // Out of range Start Time - Hour
+ assertMessageValidity("04:34:04:0C:18:0F:08:37:00:02:EA:60:03").isEqualTo(ERROR_PARAMETER);
+ // Out of range Start Time - Minute
+ assertMessageValidity("04:33:0C:08:10:50:04:30:08:00:13:AD:06").isEqualTo(ERROR_PARAMETER);
+ // Out of range Duration - Duration Hours
+ assertMessageValidity("04:34:04:0C:16:0F:64:37:00:02:EA:60:03").isEqualTo(ERROR_PARAMETER);
+ // Out of range Duration - Minute
+ assertMessageValidity("04:33:0C:08:10:1E:04:64:08:00:13:AD:06").isEqualTo(ERROR_PARAMETER);
+ // Invalid Recording Sequence
+ assertMessageValidity("04:34:04:0C:16:0F:08:37:88:02:EA:60:03").isEqualTo(ERROR_PARAMETER);
+ // Invalid Recording Sequence
+ assertMessageValidity("04:33:0C:08:10:1E:04:30:A2:00:13:AD:06").isEqualTo(ERROR_PARAMETER);
+ // Out of range Analogue Broadcast Type
+ assertMessageValidity("04:34:04:0C:16:0F:08:37:00:03:EA:60:03").isEqualTo(ERROR_PARAMETER);
+ // Out of range Analogue Frequency
+ assertMessageValidity("04:33:0C:08:10:1E:04:30:08:00:FF:FF:06").isEqualTo(ERROR_PARAMETER);
+ // Out of range Broadcast System
+ assertMessageValidity("04:34:04:0C:16:0F:08:37:00:02:EA:60:20").isEqualTo(ERROR_PARAMETER);
+ }
+
+ @Test
+ public void isValid_setDigitalTimer_clearDigitalTimer() {
+ // Services identified by Digital IDs - ARIB Broadcast System
+ assertMessageValidity("04:99:0C:08:15:05:04:1E:00:00:C4:C2:11:D8:75:30").isEqualTo(OK);
+ // Service identified by Digital IDs - ATSC Broadcast System
+ assertMessageValidity("04:97:1E:07:12:20:50:28:01:01:8B:5E:39:5A").isEqualTo(OK);
+ // Service identified by Digital IDs - DVB Broadcast System
+ assertMessageValidity("04:99:05:0C:06:0A:19:3B:40:19:8B:44:03:11:04:FC").isEqualTo(OK);
+ // Service identified by Channel - 1 part channel number
+ assertMessageValidity("04:97:12:06:0C:2D:5A:19:08:91:04:00:B1").isEqualTo(OK);
+ // Service identified by Channel - 2 part channel number
+ assertMessageValidity("04:99:15:09:00:0F:00:2D:04:82:09:C8:72:C8").isEqualTo(OK);
+
+ assertMessageValidity("4F:97:0C:08:15:05:04:1E:00:00:C4:C2:11:D8:75:30")
+ .isEqualTo(ERROR_DESTINATION);
+ assertMessageValidity("F0:99:15:09:00:0F:00:2D:04:82:09:C8:72:C8").isEqualTo(ERROR_SOURCE);
+ assertMessageValidity("04:97:1E:12:20:58:01:01:8B:5E:39:5A")
+ .isEqualTo(ERROR_PARAMETER_SHORT);
+ // Out of range Day of Month
+ assertMessageValidity("04:99:24:0C:06:0A:19:3B:40:19:8B:44:03:11:04:FC")
+ .isEqualTo(ERROR_PARAMETER);
+ // Out of range Month of Year
+ assertMessageValidity("04:97:12:10:0C:2D:5A:19:08:91:04:00:B1").isEqualTo(ERROR_PARAMETER);
+ // Out of range Start Time - Hour
+ assertMessageValidity("04:99:0C:08:20:05:04:1E:00:00:C4:C2:11:D8:75:30")
+ .isEqualTo(ERROR_PARAMETER);
+ // Out of range Start Time - Minute
+ assertMessageValidity("04:97:15:09:00:4B:00:2D:04:82:09:C8:72:C8")
+ .isEqualTo(ERROR_PARAMETER);
+ // Out of range Duration - Duration Hours
+ assertMessageValidity("04:99:1E:07:12:20:78:28:01:01:8B:5E:39:5A")
+ .isEqualTo(ERROR_PARAMETER);
+ // Out of range Duration - Minute
+ assertMessageValidity("04:97:05:0C:06:0A:19:48:40:19:8B:44:03:11:04:FC")
+ .isEqualTo(ERROR_PARAMETER);
+ // Invalid Recording Sequence
+ assertMessageValidity("04:99:12:06:0C:2D:5A:19:90:91:04:00:B1").isEqualTo(ERROR_PARAMETER);
+ // Invalid Recording Sequence
+ assertMessageValidity("04:97:0C:08:15:05:04:1E:21:00:C4:C2:11:D8:75:30")
+ .isEqualTo(ERROR_PARAMETER);
+
+ // Invalid Digital Broadcast System
+ assertMessageValidity("04:99:1E:07:12:20:50:28:01:04:8B:5E:39:5A")
+ .isEqualTo(ERROR_PARAMETER);
+ // Invalid Digital Broadcast System
+ assertMessageValidity("04:97:05:0C:06:0A:19:3B:40:93:8B:44:03:11:04:FC")
+ .isEqualTo(ERROR_PARAMETER);
+ // Insufficient data for ARIB Broadcast system
+ assertMessageValidity("04:99:0C:08:15:05:04:1E:00:00:C4:C2:11:D8:75")
+ .isEqualTo(ERROR_PARAMETER);
+ // Insufficient data for ATSC Broadcast system
+ assertMessageValidity("04:97:1E:07:12:20:50:28:01:01:8B:5E:39").isEqualTo(ERROR_PARAMETER);
+ // Insufficient data for DVB Broadcast system
+ assertMessageValidity("04:99:05:0C:06:0A:19:3B:40:19:8B:44:03:11:04")
+ .isEqualTo(ERROR_PARAMETER);
+ // Insufficient data for 2 part channel number
+ assertMessageValidity("04:97:15:09:00:0F:00:2D:04:82:09:C8:72").isEqualTo(ERROR_PARAMETER);
+ // Invalid Channel Number format
+ assertMessageValidity("04:99:12:06:0C:2D:5A:19:08:91:0D:00:B1").isEqualTo(ERROR_PARAMETER);
+ }
+
+ @Test
+ public void isValid_setExternalTimer_clearExternalTimer() {
+ assertMessageValidity("40:A1:0C:08:15:05:04:1E:02:04:20").isEqualTo(OK);
+ assertMessageValidity("40:A2:14:09:12:28:4B:19:10:05:10:00").isEqualTo(OK);
+
+ assertMessageValidity("4F:A1:0C:08:15:05:04:1E:02:04:20").isEqualTo(ERROR_DESTINATION);
+ assertMessageValidity("F4:A2:14:09:12:28:4B:19:10:05:10:00").isEqualTo(ERROR_SOURCE);
+ assertMessageValidity("40:A1:0C:08:15:05:04:1E:02:04").isEqualTo(ERROR_PARAMETER_SHORT);
+ // Out of range Day of Month
+ assertMessageValidity("40:A2:28:09:12:28:4B:19:10:05:10:00").isEqualTo(ERROR_PARAMETER);
+ // Out of range Month of Year
+ assertMessageValidity("40:A1:0C:0F:15:05:04:1E:02:04:20").isEqualTo(ERROR_PARAMETER);
+ // Out of range Start Time - Hour
+ assertMessageValidity("40:A2:14:09:1A:28:4B:19:10:05:10:00").isEqualTo(ERROR_PARAMETER);
+ // Out of range Start Time - Minute
+ assertMessageValidity("40:A1:0C:08:15:48:04:1E:02:04:20").isEqualTo(ERROR_PARAMETER);
+ // Out of range Duration - Duration Hours
+ assertMessageValidity("40:A2:14:09:12:28:66:19:10:05:10:00").isEqualTo(ERROR_PARAMETER);
+ // Out of range Duration - Minute
+ assertMessageValidity("40:A1:0C:08:15:05:04:3F:02:04:20").isEqualTo(ERROR_PARAMETER);
+ // Invalid Recording Sequence
+ assertMessageValidity("40:A2:14:09:12:28:4B:19:84:05:10:00").isEqualTo(ERROR_PARAMETER);
+ // Invalid Recording Sequence
+ assertMessageValidity("40:A1:0C:08:15:05:04:1E:14:04:20").isEqualTo(ERROR_PARAMETER);
+ // Invalid external source specifier
+ assertMessageValidity("40:A2:14:09:12:28:4B:19:10:08:10:00").isEqualTo(ERROR_PARAMETER);
+ // Invalid External PLug
+ assertMessageValidity("04:A1:0C:08:15:05:04:1E:02:04:00").isEqualTo(ERROR_PARAMETER);
+ }
+
+ @Test
+ public void isValid_timerClearedStatus() {
+ assertMessageValidity("40:43:01:7E").isEqualTo(OK);
+ assertMessageValidity("40:43:80").isEqualTo(OK);
+
+ assertMessageValidity("4F:43:01").isEqualTo(ERROR_DESTINATION);
+ assertMessageValidity("F0:43:80").isEqualTo(ERROR_SOURCE);
+ assertMessageValidity("40:43").isEqualTo(ERROR_PARAMETER_SHORT);
+ assertMessageValidity("40:43:03").isEqualTo(ERROR_PARAMETER);
+ }
+
+ @Test
+ public void isValid_timerStatus() {
+ // Programmed - Space available
+ assertMessageValidity("40:35:58").isEqualTo(OK);
+ // Programmed - Not enough space available
+ assertMessageValidity("40:35:B9:32:1C:4F").isEqualTo(OK);
+ // Not programmed - Date out of range
+ assertMessageValidity("40:35:82:3B").isEqualTo(OK);
+ // Not programmed - Duplicate
+ assertMessageValidity("40:35:EE:52:0C").isEqualTo(OK);
+
+ assertMessageValidity("4F:35:58").isEqualTo(ERROR_DESTINATION);
+ assertMessageValidity("F0:35:82").isEqualTo(ERROR_SOURCE);
+ assertMessageValidity("40:35").isEqualTo(ERROR_PARAMETER_SHORT);
+ // Programmed - Invalid programmed info
+ assertMessageValidity("40:35:BD").isEqualTo(ERROR_PARAMETER);
+ // Non programmed - Invalid not programmed error info
+ assertMessageValidity("40:35:DE").isEqualTo(ERROR_PARAMETER);
+ // Programmed - Might not be enough space available - Invalid duration hours
+ assertMessageValidity("40:35:BB:96:1C").isEqualTo(ERROR_PARAMETER);
+ // Not programmed - Duplicate - Invalid duration minutes
+ assertMessageValidity("40:35:EE:52:4A").isEqualTo(ERROR_PARAMETER);
+ }
+
private IntegerSubject assertMessageValidity(String message) {
return assertThat(mHdmiCecMessageValidator.isValid(buildMessage(message)));
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java b/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java
index 40d959d..9ba0967 100644
--- a/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java
@@ -44,7 +44,6 @@
public class IncrementalStatesTest {
private IncrementalStates mIncrementalStates;
private ConditionVariable mUnstartableCalled = new ConditionVariable();
- private ConditionVariable mStartableCalled = new ConditionVariable();
private ConditionVariable mFullyLoadedCalled = new ConditionVariable();
private AtomicInteger mUnstartableReason = new AtomicInteger(0);
private static final int WAIT_TIMEOUT_MILLIS = 1000; /* 1 second */
@@ -57,7 +56,6 @@
@Override
public void onPackageStartable() {
- mStartableCalled.open();
}
@Override
@@ -77,24 +75,22 @@
mIncrementalStates.setCallback(mCallback);
mIncrementalStates.onCommit(true);
// Test that package is now startable and loading
- assertTrue(mStartableCalled.block(WAIT_TIMEOUT_MILLIS));
assertTrue(mIncrementalStates.isStartable());
assertTrue(mIncrementalStates.isLoading());
- mStartableCalled.close();
mUnstartableCalled.close();
mFullyLoadedCalled.close();
}
/**
- * Test that startable state changes to false when Incremental Storage is unhealthy.
+ * Test that the package is still startable when Incremental Storage is unhealthy.
*/
@Test
public void testStartableTransition_IncrementalStorageUnhealthy() {
mIncrementalStates.onStorageHealthStatusChanged(
IStorageHealthListener.HEALTH_STATUS_UNHEALTHY);
- // Test that package is now unstartable
- assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertFalse(mIncrementalStates.isStartable());
+ // Test that package is still startable
+ assertFalse(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
+ assertTrue(mIncrementalStates.isStartable());
assertEquals(PackageManager.UNSTARTABLE_REASON_UNKNOWN, mUnstartableReason.get());
}
@@ -112,73 +108,34 @@
}
/**
- * Test that the package becomes unstartable when health status indicate storage issues.
+ * Test that the package is still startable when health status indicate storage issues.
*/
@Test
public void testStartableTransition_IncrementalStorageBlocked() {
mIncrementalStates.onStorageHealthStatusChanged(
IStorageHealthListener.HEALTH_STATUS_UNHEALTHY_STORAGE);
- // Test that package is now unstartable
- assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertFalse(mIncrementalStates.isStartable());
- assertEquals(PackageManager.UNSTARTABLE_REASON_INSUFFICIENT_STORAGE,
+ // Test that package is still startable
+ assertFalse(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
+ assertTrue(mIncrementalStates.isStartable());
+ assertEquals(PackageManager.UNSTARTABLE_REASON_UNKNOWN,
mUnstartableReason.get());
}
/**
- * Test that the package becomes unstartable when health status indicates transport issues.
+ * Test that the package is still startable when health status indicates transport issues.
*/
@Test
public void testStartableTransition_DataLoaderIntegrityError() {
mIncrementalStates.onStorageHealthStatusChanged(
IStorageHealthListener.HEALTH_STATUS_UNHEALTHY_TRANSPORT);
- // Test that package is now unstartable
- assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertFalse(mIncrementalStates.isStartable());
- assertEquals(PackageManager.UNSTARTABLE_REASON_CONNECTION_ERROR,
+ // Test that package is still startable
+ assertFalse(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
+ assertTrue(mIncrementalStates.isStartable());
+ assertEquals(PackageManager.UNSTARTABLE_REASON_UNKNOWN,
mUnstartableReason.get());
}
/**
- * Test that the package becomes unstartable when Incremental Storage is unhealthy, and it
- * becomes startable again when Incremental Storage is healthy again.
- */
- @Test
- public void testStartableTransition_IncrementalStorageUnhealthyBackToHealthy()
- throws InterruptedException {
- mIncrementalStates.onStorageHealthStatusChanged(
- IStorageHealthListener.HEALTH_STATUS_UNHEALTHY);
- // Test that package is unstartable
- assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertFalse(mIncrementalStates.isStartable());
-
- mIncrementalStates.onStorageHealthStatusChanged(
- IStorageHealthListener.HEALTH_STATUS_OK);
- // Test that package is now startable
- assertTrue(mStartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertTrue(mIncrementalStates.isStartable());
- }
-
- /**
- * Test that the package becomes unstartable when health status indicates transportation issue,
- * and it becomes startable again when health status is ok again.
- */
- @Test
- public void testStartableTransition_DataLoaderUnhealthyBackToHealthy()
- throws InterruptedException {
- mIncrementalStates.onStorageHealthStatusChanged(
- IStorageHealthListener.HEALTH_STATUS_UNHEALTHY_TRANSPORT);
- // Test that package is unstartable
- assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertFalse(mIncrementalStates.isStartable());
-
- mIncrementalStates.onStorageHealthStatusChanged(IStorageHealthListener.HEALTH_STATUS_OK);
- // Test that package is now startable
- assertTrue(mStartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertTrue(mIncrementalStates.isStartable());
- }
-
- /**
* Test that when loading progress is 1, the package becomes fully loaded, and the change of
* Incremental Storage health status does not affect the startable state.
*/
@@ -197,43 +154,11 @@
}
/**
- * Test that when loading progress is 1, the package becomes fully loaded, and if the package
- * was unstartable, it becomes startable.
- */
- @Test
- public void testLoadingTransition_FullyLoadedWhenUnstartable() throws InterruptedException {
- mIncrementalStates.onStorageHealthStatusChanged(
- IStorageHealthListener.HEALTH_STATUS_UNHEALTHY);
- // Test that package is unstartable
- assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertFalse(mIncrementalStates.isStartable());
- // Test that package is still loading
- assertTrue(mIncrementalStates.isLoading());
-
- mIncrementalStates.setProgress(0.5f);
- // Test that package is still unstartable
- assertFalse(mStartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertFalse(mIncrementalStates.isStartable());
- mIncrementalStates.setProgress(1.0f);
- // Test that package is now startable
- assertTrue(mStartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertTrue(mIncrementalStates.isStartable());
- // Test that package is now fully loaded
- assertTrue(mFullyLoadedCalled.block(WAIT_TIMEOUT_MILLIS));
- assertFalse(mIncrementalStates.isLoading());
- }
-
- /**
* Test startability transitions if app crashes or anrs
*/
@Test
public void testStartableTransition_AppCrashOrAnr() {
mIncrementalStates.onCrashOrAnr();
- assertFalse(mIncrementalStates.isStartable());
- mIncrementalStates.setProgress(1.0f);
- assertTrue(mIncrementalStates.isStartable());
- mIncrementalStates.onCrashOrAnr();
- // Test that if fully loaded, app remains startable even if it has crashed
assertTrue(mIncrementalStates.isStartable());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
new file mode 100644
index 0000000..40575e4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
@@ -0,0 +1,304 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.util.Preconditions;
+import com.android.internal.util.TraceBuffer;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test class for {@link Watcher}, {@link Watchable}, {@link WatchableImpl},
+ * {@link WatchedArrayMap}, {@link WatchedSparseArray}, and
+ * {@link WatchedSparseBooleanArray}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:WatcherTest
+ */
+@SmallTest
+public class WatcherTest {
+
+ // A small Watchable leaf node
+ private class Leaf extends WatchableImpl {
+ private int datum = 0;
+ void set(int i) {
+ if (datum != i) {
+ datum = i;
+ dispatchChange(this);
+ }
+ }
+ void tick() {
+ set(datum + 1);
+ }
+ }
+
+ // A top-most watcher. It counts the number of notifications that it receives.
+ private class Tester extends Watcher {
+ // The count of changes.
+ public int changes = 0;
+
+ // The single Watchable that this monitors.
+ public final Watchable mWatched;
+
+ // The key, used for messages
+ public String mKey;
+
+ // Create the Tester with a Watcher
+ public Tester(Watchable w, String k) {
+ mWatched = w;
+ mKey = k;
+ }
+
+ // Listen for events
+ public void register() {
+ mWatched.registerObserver(this);
+ }
+
+ // Stop listening for events
+ public void unregister() {
+ mWatched.unregisterObserver(this);
+ }
+
+ // Count the number of notifications received.
+ @Override
+ public void onChange(Watchable what) {
+ changes++;
+ }
+
+ // Verify the count.
+ public void verify(int want, String msg) {
+ assertEquals(mKey + " " + msg, want, changes);
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void test_notify() {
+
+ Tester tester;
+
+ // Create a few leaves
+ Leaf a = new Leaf();
+ Leaf b = new Leaf();
+ Leaf c = new Leaf();
+ Leaf d = new Leaf();
+
+ // Basic test. Create a leaf and verify that changes to the leaf get notified to
+ // the tester.
+ tester = new Tester(a, "Leaf");
+ tester.verify(0, "Initial leaf - no registration");
+ a.tick();
+ tester.verify(0, "Updates with no registration");
+ tester.register();
+ a.tick();
+ tester.verify(1, "Updates with registration");
+ a.tick();
+ a.tick();
+ tester.verify(3, "Updates with registration");
+
+ // Add the same leaf to more than one tester. Verify that a change to the leaf is seen by
+ // all registered listeners.
+ Tester buddy1 = new Tester(a, "Leaf2");
+ Tester buddy2 = new Tester(a, "Leaf3");
+ buddy1.verify(0, "Initial leaf - no registration");
+ buddy2.verify(0, "Initial leaf - no registration");
+ a.tick();
+ tester.verify(4, "Updates with buddies");
+ buddy1.verify(0, "Updates - no registration");
+ buddy2.verify(0, "Updates - no registration");
+ buddy1.register();
+ buddy2.register();
+ buddy1.verify(0, "No updates - registered");
+ buddy2.verify(0, "No updates - registered");
+ a.tick();
+ buddy1.verify(1, "First update");
+ buddy2.verify(1, "First update");
+ buddy1.unregister();
+ a.tick();
+ buddy1.verify(1, "Second update - unregistered");
+ buddy2.verify(2, "Second update");
+
+ buddy1 = null;
+ buddy2 = null;
+
+ final int INDEX_A = 1;
+ final int INDEX_B = 2;
+ final int INDEX_C = 3;
+ final int INDEX_D = 4;
+
+ // Test WatchedArrayMap
+ WatchedArrayMap<Integer, Leaf> am = new WatchedArrayMap<>();
+ am.put(INDEX_A, a);
+ am.put(INDEX_B, b);
+ tester = new Tester(am, "WatchedArrayMap");
+ tester.verify(0, "Initial array - no registration");
+ a.tick();
+ tester.verify(0, "Updates with no registration");
+ tester.register();
+ tester.verify(0, "Updates with no registration");
+ a.tick();
+ tester.verify(1, "Updates with registration");
+ b.tick();
+ tester.verify(2, "Updates with registration");
+ am.remove(INDEX_B);
+ tester.verify(3, "Removed b");
+ b.tick();
+ tester.verify(3, "Updates with b not watched");
+ am.put(INDEX_B, b);
+ am.put(INDEX_C, b);
+ tester.verify(5, "Added b twice");
+ b.tick();
+ tester.verify(6, "Changed b - single notification");
+ am.remove(INDEX_C);
+ tester.verify(7, "Removed first b");
+ b.tick();
+ tester.verify(8, "Changed b - single notification");
+ am.remove(INDEX_B);
+ tester.verify(9, "Removed second b");
+ b.tick();
+ tester.verify(9, "Updated b - no change");
+ am.clear();
+ tester.verify(10, "Cleared array");
+ b.tick();
+ tester.verify(10, "Change to b not in array");
+
+ // Special methods
+ am.put(INDEX_C, c);
+ tester.verify(11, "Added c");
+ c.tick();
+ tester.verify(12, "Ticked c");
+ am.setValueAt(am.indexOfKey(INDEX_C), d);
+ tester.verify(13, "Replaced c with d");
+ c.tick();
+ d.tick();
+ tester.verify(14, "Ticked d and c (c not registered)");
+
+ am = null;
+
+ // Test WatchedSparseArray
+ WatchedSparseArray<Leaf> sa = new WatchedSparseArray<>();
+ sa.put(INDEX_A, a);
+ sa.put(INDEX_B, b);
+ tester = new Tester(sa, "WatchedSparseArray");
+ tester.verify(0, "Initial array - no registration");
+ a.tick();
+ tester.verify(0, "Updates with no registration");
+ tester.register();
+ tester.verify(0, "Updates with no registration");
+ a.tick();
+ tester.verify(1, "Updates with registration");
+ b.tick();
+ tester.verify(2, "Updates with registration");
+ sa.remove(INDEX_B);
+ tester.verify(3, "Removed b");
+ b.tick();
+ tester.verify(3, "Updates with b not watched");
+ sa.put(INDEX_B, b);
+ sa.put(INDEX_C, b);
+ tester.verify(5, "Added b twice");
+ b.tick();
+ tester.verify(6, "Changed b - single notification");
+ sa.remove(INDEX_C);
+ tester.verify(7, "Removed first b");
+ b.tick();
+ tester.verify(8, "Changed b - single notification");
+ sa.remove(INDEX_B);
+ tester.verify(9, "Removed second b");
+ b.tick();
+ tester.verify(9, "Updated b - no change");
+ sa.clear();
+ tester.verify(10, "Cleared array");
+ b.tick();
+ tester.verify(10, "Change to b not in array");
+
+ // Special methods
+ sa.put(INDEX_A, a);
+ sa.put(INDEX_B, b);
+ sa.put(INDEX_C, c);
+ tester.verify(13, "Added c");
+ c.tick();
+ tester.verify(14, "Ticked c");
+ sa.setValueAt(sa.indexOfKey(INDEX_C), d);
+ tester.verify(15, "Replaced c with d");
+ c.tick();
+ d.tick();
+ tester.verify(16, "Ticked d and c (c not registered)");
+ sa.append(INDEX_D, c);
+ tester.verify(17, "Append c");
+ c.tick();
+ d.tick();
+ tester.verify(19, "Ticked d and c");
+ assertEquals("Verify four elements", 4, sa.size());
+ // Figure out which elements are at which indices.
+ Leaf[] x = new Leaf[4];
+ for (int i = 0; i < 4; i++) {
+ x[i] = sa.valueAt(i);
+ }
+ sa.removeAtRange(0, 2);
+ tester.verify(20, "Removed two elements in one operation");
+ x[0].tick();
+ x[1].tick();
+ tester.verify(20, "Ticked two removed elements");
+ x[2].tick();
+ x[3].tick();
+ tester.verify(22, "Ticked two remaining elements");
+
+ sa = null;
+
+ // Test WatchedSparseBooleanArray
+ WatchedSparseBooleanArray sb = new WatchedSparseBooleanArray();
+ tester = new Tester(sb, "WatchedSparseBooleanArray");
+ tester.verify(0, "Initial array - no registration");
+ sb.put(INDEX_A, true);
+ tester.verify(0, "Updates with no registration");
+ tester.register();
+ tester.verify(0, "Updates with no registration");
+ sb.put(INDEX_B, true);
+ tester.verify(1, "Updates with registration");
+ sb.put(INDEX_B, true);
+ tester.verify(1, "Null update");
+ sb.put(INDEX_B, false);
+ sb.put(INDEX_C, true);
+ tester.verify(3, "Updates with registration");
+ // Special methods
+ sb.put(INDEX_C, true);
+ tester.verify(3, "Added true, no change");
+ sb.setValueAt(sb.indexOfKey(INDEX_C), false);
+ tester.verify(4, "Replaced true with false");
+ sb.append(INDEX_D, true);
+ tester.verify(5, "Append true");
+
+ sb = null;
+ }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index bf742b7..7ec8689 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -19,6 +19,7 @@
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
import static android.app.NotificationChannel.CONVERSATION_CHANNEL_ID_FORMAT;
+import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
@@ -3796,4 +3797,40 @@
}
}
}
+
+ @Test
+ public void testUnlockNotificationChannelImportance() {
+ NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
+ channel.lockFields(USER_LOCKED_IMPORTANCE);
+ assertTrue((channel.getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0);
+
+ mHelper.unlockNotificationChannelImportance(PKG_O, UID_O, channel.getId());
+ assertTrue((channel.getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0);
+
+ }
+
+ @Test
+ public void testUnlockAllNotificationChannels() {
+ NotificationChannel channelA = new NotificationChannel("a", "a", IMPORTANCE_LOW);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channelA, true, false);
+ NotificationChannel channelB = new NotificationChannel("b", "b", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_P, UID_P, channelB, true, false);
+ NotificationChannel channelC = new NotificationChannel("c", "c", IMPORTANCE_HIGH);
+ mHelper.createNotificationChannel(PKG_P, UID_O, channelC, false, false);
+
+ channelA.lockFields(USER_LOCKED_IMPORTANCE);
+ channelB.lockFields(USER_LOCKED_IMPORTANCE);
+ channelC.lockFields(USER_LOCKED_IMPORTANCE);
+
+ assertTrue((channelA.getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0);
+ assertTrue((channelB.getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0);
+ assertTrue((channelC.getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0);
+
+ mHelper.unlockAllNotificationChannels();
+ assertTrue((channelA.getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0);
+ assertTrue((channelB.getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0);
+ assertTrue((channelC.getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0);
+
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index f026b85..5685ea5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -197,8 +197,7 @@
// Add activity that should be shown on the keyguard.
final ActivityRecord showWhenLockedActivity = new ActivityBuilder(mAtm)
- .setCreateTask(true)
- .setStack(stack)
+ .setTask(stack)
.setActivityFlags(FLAG_SHOW_WHEN_LOCKED)
.build();
@@ -225,8 +224,8 @@
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
final Task alwaysOnTopStack = taskDisplayArea.createStack(WINDOWING_MODE_FREEFORM,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true)
- .setStack(alwaysOnTopStack).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
+ .setTask(alwaysOnTopStack).build();
alwaysOnTopStack.setAlwaysOnTop(true);
taskDisplayArea.positionChildAt(POSITION_TOP, alwaysOnTopStack,
false /* includingParents */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index f1d3e18..0654968 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -362,8 +362,7 @@
.setDisplay(addNewDisplayContentAt(DisplayContent.POSITION_BOTTOM))
.build();
final ActivityRecord activityOnNewDisplay = new ActivityBuilder(mAtm)
- .setStack(stack)
- .setCreateTask(true)
+ .setTask(stack)
.setProcessName("new")
.build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index f378345..cf7f741 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -59,9 +59,9 @@
import static com.android.server.wm.Task.ActivityState.STARTED;
import static com.android.server.wm.Task.ActivityState.STOPPED;
import static com.android.server.wm.Task.ActivityState.STOPPING;
-import static com.android.server.wm.Task.STACK_VISIBILITY_INVISIBLE;
-import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE;
-import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
+import static com.android.server.wm.Task.TASK_VISIBILITY_INVISIBLE;
+import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE;
+import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
import static com.google.common.truth.Truth.assertThat;
@@ -131,8 +131,9 @@
@Before
public void setUp() throws Exception {
- mStack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
- mTask = mStack.getBottomMostTask();
+ mTask = new TaskBuilder(mSupervisor)
+ .setCreateParentTask(true).setCreateActivity(true).build();
+ mStack = mTask.getRootTask();
mActivity = mTask.getTopNonFinishingActivity();
setBooted(mAtm);
@@ -515,13 +516,13 @@
mActivity.setState(Task.ActivityState.STOPPED, "Testing");
spyOn(mStack);
- doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
+ doReturn(TASK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */));
- doReturn(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT).when(mStack).getVisibility(null);
+ doReturn(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT).when(mStack).getVisibility(null);
assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
- doReturn(STACK_VISIBILITY_INVISIBLE).when(mStack).getVisibility(null);
+ doReturn(TASK_VISIBILITY_INVISIBLE).when(mStack).getVisibility(null);
assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
}
@@ -534,7 +535,7 @@
mActivity.addResultLocked(topActivity, "resultWho", 0, 0, new Intent());
topActivity.finishing = true;
- doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
+ doReturn(TASK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */));
assertEquals(false, mActivity.shouldPauseActivity(null /*activeActivity */));
}
@@ -787,7 +788,7 @@
// Have two tasks (topRootableTask and mTask) as the children of mStack.
ActivityRecord topActivity = new ActivityBuilder(mActivity.mAtmService)
.setCreateTask(true)
- .setStack(mStack)
+ .setParentTask(mStack)
.build();
Task topRootableTask = topActivity.getTask();
topRootableTask.moveToFront("test");
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
index f9ad49b..1d5dc43 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
@@ -71,8 +71,8 @@
*/
@Test
public void testStoppingActivityRemovedWhenResumed() {
- final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true)
- .setStack(mFullscreenStack).build();
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
+ .setTask(mFullscreenStack).build();
mSupervisor.mStoppingActivities.add(firstActivity);
firstActivity.completeResumeLocked();
@@ -85,8 +85,8 @@
*/
@Test
public void testReportWaitingActivityLaunchedIfNeeded() {
- final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true)
- .setStack(mFullscreenStack).build();
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
+ .setTask(mFullscreenStack).build();
final WaitResult taskToFrontWait = new WaitResult();
mSupervisor.mWaitingActivityLaunched.add(taskToFrontWait);
@@ -153,7 +153,7 @@
@Test
public void testNotifyTaskFocusChanged() {
final ActivityRecord fullScreenActivityA = new ActivityBuilder(mAtm).setCreateTask(true)
- .setStack(mFullscreenStack).build();
+ .setParentTask(mFullscreenStack).build();
final Task taskA = fullScreenActivityA.getTask();
final TaskChangeNotificationController taskChangeNotifier =
@@ -166,7 +166,7 @@
reset(taskChangeNotifier);
final ActivityRecord fullScreenActivityB = new ActivityBuilder(mAtm).setCreateTask(true)
- .setStack(mFullscreenStack).build();
+ .setParentTask(mFullscreenStack).build();
final Task taskB = fullScreenActivityB.getTask();
mAtm.setResumedActivityUncheckLocked(fullScreenActivityB, "resumeB");
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index b632331..faf4f52 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -43,10 +43,10 @@
import static com.android.server.wm.Task.ActivityState.STOPPED;
import static com.android.server.wm.Task.ActivityState.STOPPING;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
-import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
-import static com.android.server.wm.Task.STACK_VISIBILITY_INVISIBLE;
-import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE;
-import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
+import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT;
+import static com.android.server.wm.Task.TASK_VISIBILITY_INVISIBLE;
+import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE;
+import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
import static com.android.server.wm.TaskDisplayArea.getStackAbove;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -123,7 +123,7 @@
final Task destStack = mDefaultTaskDisplayArea.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- mTask.reparent(destStack, true /* toTop */, Task.REPARENT_KEEP_STACK_AT_FRONT,
+ mTask.reparent(destStack, true /* toTop */, Task.REPARENT_KEEP_ROOT_TASK_AT_FRONT,
false /* animate */, true /* deferResume*/,
"testResumedActivityFromTaskReparenting");
@@ -140,7 +140,7 @@
final Task destStack = mDefaultTaskDisplayArea.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- mTask.reparent(destStack, true /*toTop*/, REPARENT_MOVE_STACK_TO_FRONT, false, false,
+ mTask.reparent(destStack, true /*toTop*/, REPARENT_MOVE_ROOT_TASK_TO_FRONT, false, false,
"testResumedActivityFromActivityReparenting");
assertNull(mStack.getResumedActivity());
@@ -242,8 +242,7 @@
public void testRemoveOrganizedTask_UpdateStackReference() {
final Task rootHomeTask = mDefaultTaskDisplayArea.getRootHomeTask();
final ActivityRecord homeActivity = new ActivityBuilder(mAtm)
- .setStack(rootHomeTask)
- .setCreateTask(true)
+ .setTask(rootHomeTask)
.build();
final Task secondaryStack = mAtm.mTaskOrganizerController.createRootTask(
rootHomeTask.getDisplayContent(), WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, null);
@@ -291,7 +290,7 @@
@Test
public void testStopActivityWhenActivityDestroyed() {
- final ActivityRecord r = new ActivityBuilder(mAtm).setTask(mTask).build();
+ final ActivityRecord r = new ActivityBuilder(mAtm).setCreateTask(true).build();
r.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
mStack.moveToFront("testStopActivityWithDestroy");
r.stopIfPossible();
@@ -303,7 +302,6 @@
public void testFindTaskWithOverlay() {
final ActivityRecord r = new ActivityBuilder(mAtm)
.setCreateTask(true)
- .setStack(mStack)
.setUid(0)
.build();
final Task task = r.getTask();
@@ -314,7 +312,7 @@
final RootWindowContainer.FindTaskResult result =
new RootWindowContainer.FindTaskResult();
- result.process(r, mStack);
+ result.process(r, task);
assertEquals(r, task.getTopNonFinishingActivity(false /* includeOverlays */));
assertEquals(taskOverlay, task.getTopNonFinishingActivity(true /* includeOverlays */));
@@ -355,9 +353,11 @@
final TaskDisplayArea taskDisplayArea = addNewDisplayContentAt(DisplayContent.POSITION_TOP)
.getDefaultTaskDisplayArea();
final Task stack1 = createStackForShouldBeVisibleTest(taskDisplayArea,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */,
+ true /* twoLevelTask */);
final Task stack2 = createStackForShouldBeVisibleTest(taskDisplayArea,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */,
+ true /* twoLevelTask */);
// Do not move display to back because there is still another stack.
stack2.moveToBack("testMoveStackToBackIncludingParent", stack2.getTopMostTask());
@@ -377,8 +377,7 @@
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Add an activity to the pinned stack so it isn't considered empty for visibility check.
final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm)
- .setCreateTask(true)
- .setStack(pinnedStack)
+ .setTask(pinnedStack)
.build();
assertTrue(homeStack.shouldBeVisible(null /* starting */));
@@ -419,10 +418,10 @@
assertFalse(homeStack.shouldBeVisible(null /* starting */));
assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE, homeStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE, homeStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenPrimary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenSecondary.getVisibility(null /* starting */));
// Home stack should be visible if one of the halves of split-screen is translucent.
@@ -430,11 +429,11 @@
assertTrue(homeStack.shouldBeVisible(null /* starting */));
assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
homeStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenPrimary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenSecondary.getVisibility(null /* starting */));
final Task splitScreenSecondary2 =
@@ -445,9 +444,9 @@
doReturn(false).when(splitScreenSecondary2).isTranslucent(any());
assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
splitScreenSecondary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenSecondary2.getVisibility(null /* starting */));
// First split-screen secondary should be visible behind another translucent split-screen
@@ -455,9 +454,9 @@
doReturn(true).when(splitScreenSecondary2).isTranslucent(any());
assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
splitScreenSecondary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenSecondary2.getVisibility(null /* starting */));
final Task assistantStack = createStackForShouldBeVisibleTest(
@@ -470,13 +469,13 @@
assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
assertFalse(splitScreenSecondary2.shouldBeVisible(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
assistantStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
splitScreenPrimary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
splitScreenSecondary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
splitScreenSecondary2.getVisibility(null /* starting */));
// Split-screen stacks should be visible behind a translucent fullscreen stack.
@@ -485,13 +484,13 @@
assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
assistantStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
splitScreenPrimary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
splitScreenSecondary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
splitScreenSecondary2.getVisibility(null /* starting */));
// Assistant stack shouldn't be visible behind translucent split-screen stack,
@@ -506,25 +505,25 @@
assertTrue(assistantStack.shouldBeVisible(null /* starting */));
assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertFalse(splitScreenSecondary2.shouldBeVisible(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
assistantStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
splitScreenPrimary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
splitScreenSecondary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
splitScreenSecondary2.getVisibility(null /* starting */));
} else {
assertFalse(assistantStack.shouldBeVisible(null /* starting */));
assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
assistantStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenPrimary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
splitScreenSecondary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenSecondary2.getVisibility(null /* starting */));
}
}
@@ -549,33 +548,33 @@
// Re-parent home to split secondary.
homeStack.reparent(splitSecondary, POSITION_TOP);
// Current tasks should be visible.
- assertEquals(STACK_VISIBILITY_VISIBLE, splitPrimary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE, splitSecondary.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE, splitPrimary.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE, splitSecondary.getVisibility(null /* starting */));
// Home task should still be visible even though it is a child of another visible task.
- assertEquals(STACK_VISIBILITY_VISIBLE, homeStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE, homeStack.getVisibility(null /* starting */));
// Add fullscreen translucent task that partially occludes split tasks
final Task translucentStack = createStandardStackForVisibilityTest(
WINDOWING_MODE_FULLSCREEN, true /* translucent */);
// Fullscreen translucent task should be visible
- assertEquals(STACK_VISIBILITY_VISIBLE, translucentStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE, translucentStack.getVisibility(null /* starting */));
// Split tasks should be visible behind translucent
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
splitPrimary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
splitSecondary.getVisibility(null /* starting */));
// Home task should be visible behind translucent since its parent is visible behind
// translucent.
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
homeStack.getVisibility(null /* starting */));
// Hide split-secondary
splitSecondary.setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, true /* set */);
// Home split secondary and home task should be invisible.
- assertEquals(STACK_VISIBILITY_INVISIBLE, splitSecondary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE, homeStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_INVISIBLE, splitSecondary.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_INVISIBLE, homeStack.getVisibility(null /* starting */));
}
@Test
@@ -587,9 +586,9 @@
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
true /* translucent */);
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
bottomStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
translucentStack.getVisibility(null /* starting */));
}
@@ -605,10 +604,10 @@
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
false /* translucent */);
- assertEquals(STACK_VISIBILITY_INVISIBLE, bottomStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE, bottomStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
translucentStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE, opaqueStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE, opaqueStack.getVisibility(null /* starting */));
}
@Test
@@ -623,10 +622,10 @@
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
true /* translucent */);
- assertEquals(STACK_VISIBILITY_INVISIBLE, bottomStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_INVISIBLE, bottomStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
opaqueStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
translucentStack.getVisibility(null /* starting */));
}
@@ -639,9 +638,9 @@
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
true /* translucent */);
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
bottomTranslucentStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
translucentStack.getVisibility(null /* starting */));
}
@@ -654,9 +653,9 @@
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
false /* translucent */);
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
bottomTranslucentStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE, opaqueStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE, opaqueStack.getVisibility(null /* starting */));
}
@Test
@@ -670,16 +669,15 @@
final Task pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
bottomStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
translucentStack.getVisibility(null /* starting */));
// Add an activity to the pinned stack so it isn't considered empty for visibility check.
final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm)
- .setCreateTask(true)
- .setStack(pinnedStack)
+ .setTask(pinnedStack)
.build();
- assertEquals(STACK_VISIBILITY_VISIBLE, pinnedStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE, pinnedStack.getVisibility(null /* starting */));
}
@Test
@@ -689,8 +687,7 @@
ActivityRecord topRunningHomeActivity = homeStack.topRunningActivity();
if (topRunningHomeActivity == null) {
topRunningHomeActivity = new ActivityBuilder(mAtm)
- .setStack(homeStack)
- .setCreateTask(true)
+ .setTask(homeStack)
.build();
}
@@ -721,7 +718,7 @@
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
- .setStack(homeStack)
+ .setParentTask(homeStack)
.setCreateTask(true)
.build();
final Task task = firstActivity.getTask();
@@ -985,14 +982,29 @@
return stack;
}
- @SuppressWarnings("TypeParameterUnusedInFormals")
private Task createStackForShouldBeVisibleTest(
TaskDisplayArea taskDisplayArea, int windowingMode, int activityType, boolean onTop) {
+ return createStackForShouldBeVisibleTest(taskDisplayArea,
+ windowingMode, activityType, onTop, false /* twoLevelTask */);
+ }
+
+ @SuppressWarnings("TypeParameterUnusedInFormals")
+ private Task createStackForShouldBeVisibleTest(TaskDisplayArea taskDisplayArea,
+ int windowingMode, int activityType, boolean onTop, boolean twoLevelTask) {
final Task task;
if (activityType == ACTIVITY_TYPE_HOME) {
task = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
mDefaultTaskDisplayArea.positionChildAt(onTop ? POSITION_TOP : POSITION_BOTTOM, task,
false /* includingParents */);
+ } else if (twoLevelTask) {
+ task = new TaskBuilder(mSupervisor)
+ .setTaskDisplayArea(taskDisplayArea)
+ .setWindowingMode(windowingMode)
+ .setActivityType(activityType)
+ .setOnTop(onTop)
+ .setCreateActivity(true)
+ .setCreateParentTask(true)
+ .build().getRootTask();
} else {
task = new TaskBuilder(mSupervisor)
.setTaskDisplayArea(taskDisplayArea)
@@ -1154,7 +1166,7 @@
ActivityRecord activity = homeStack.topRunningActivity();
if (activity == null) {
activity = new ActivityBuilder(mAtm)
- .setStack(homeStack)
+ .setParentTask(homeStack)
.setCreateTask(true)
.build();
}
@@ -1319,8 +1331,7 @@
@Test
public void testResetTaskWithFinishingActivities() {
- final ActivityRecord taskTop =
- new ActivityBuilder(mAtm).setStack(mStack).setCreateTask(true).build();
+ final ActivityRecord taskTop = new ActivityBuilder(mAtm).setTask(mStack).build();
// Make all activities in the task are finishing to simulate Task#getTopActivity
// returns null.
taskTop.finishing = true;
@@ -1334,10 +1345,8 @@
public void testIterateOccludedActivity() {
final ArrayList<ActivityRecord> occludedActivities = new ArrayList<>();
final Consumer<ActivityRecord> handleOccludedActivity = occludedActivities::add;
- final ActivityRecord bottomActivity =
- new ActivityBuilder(mAtm).setStack(mStack).setTask(mTask).build();
- final ActivityRecord topActivity =
- new ActivityBuilder(mAtm).setStack(mStack).setTask(mTask).build();
+ final ActivityRecord bottomActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
+ final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
// Top activity occludes bottom activity.
doReturn(true).when(mStack).shouldBeVisible(any());
assertTrue(topActivity.shouldBeVisible());
@@ -1355,8 +1364,7 @@
assertThat(occludedActivities).isEmpty();
// A finishing activity should not occlude other activities behind.
- final ActivityRecord finishingActivity =
- new ActivityBuilder(mAtm).setStack(mStack).setTask(mTask).build();
+ final ActivityRecord finishingActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
finishingActivity.finishing = true;
doCallRealMethod().when(finishingActivity).occludesParent();
assertTrue(topActivity.shouldBeVisible());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 3720e520..a7ced1d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -486,7 +486,7 @@
final ActivityStarter starter = prepareStarter(0);
final LockTaskController lockTaskController = mAtm.getLockTaskController();
- doReturn(true).when(lockTaskController).isLockTaskModeViolation(any());
+ doReturn(true).when(lockTaskController).isNewTaskLockTaskModeViolation(any());
final int result = starter.setReason("testTaskModeViolation").execute();
@@ -712,10 +712,10 @@
// Put 2 tasks in the same stack (simulate the behavior of home stack).
final Task rootTask = new TaskBuilder(mSupervisor).build();
final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setStack(rootTask)
+ .setParentTask(rootTask)
.setCreateTask(true).build();
new ActivityBuilder(mAtm)
- .setStack(activity.getRootTask())
+ .setParentTask(activity.getRootTask())
.setCreateTask(true).build();
// Create a top finishing activity.
diff --git a/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
index 0f54895..9d8710d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
@@ -17,7 +17,6 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyZeroInteractions;
@@ -63,8 +62,7 @@
@Test
public void testDeferring() {
- final ActivityRecord activity1 = createActivityRecord(mDisplayContent,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
final ActivityRecord activity2 = createAppWindow(activity1.getTask(), ACTIVITY_TYPE_STANDARD,
"activity2").mActivityRecord;
final AnimatingActivityRegistry registry =
@@ -87,8 +85,7 @@
@Test
public void testContainerRemoved() {
- final ActivityRecord window1 = createActivityRecord(mDisplayContent,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final ActivityRecord window1 = createActivityRecord(mDisplayContent);
final ActivityRecord window2 = createAppWindow(window1.getTask(), ACTIVITY_TYPE_STANDARD,
"window2").mActivityRecord;
final AnimatingActivityRegistry registry =
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index 30502d8..87a5985 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -58,7 +58,7 @@
private ActivityRecord mActivity;
public void setUpOnDisplay(DisplayContent dc) {
- mActivity = createTestActivityRecord(dc, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD);
+ mActivity = createActivityRecord(dc, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD);
mTask = mActivity.getTask();
mStack = mTask.getRootTask();
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index c1212f5..bc4f16e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -132,13 +132,11 @@
@Test
public void testGetAnimationTargets_visibilityAlreadyUpdated() {
- // [DisplayContent] -+- [TaskStack1] - [Task1] - [ActivityRecord1] (opening, visible)
- // +- [TaskStack2] - [Task2] - [ActivityRecord2] (closing, invisible)
- final Task stack1 = createTaskStackOnDisplay(mDisplayContent);
- final ActivityRecord activity1 = createTestActivityRecord(stack1);
+ // [DisplayContent] -+- [Task1] - [ActivityRecord1] (opening, visible)
+ // +- [Task2] - [ActivityRecord2] (closing, invisible)
+ final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
- final Task stack2 = createTaskStackOnDisplay(mDisplayContent);
- final ActivityRecord activity2 = createTestActivityRecord(stack2);
+ final ActivityRecord activity2 = createActivityRecord(mDisplayContent);
activity2.setVisible(false);
activity2.mVisibleRequested = false;
@@ -161,16 +159,14 @@
@Test
public void testGetAnimationTargets_visibilityAlreadyUpdated_butForcedTransitionRequested() {
- // [DisplayContent] -+- [TaskStack1] - [Task1] - [ActivityRecord1] (closing, invisible)
- // +- [TaskStack2] - [Task2] - [ActivityRecord2] (opening, visible)
- final Task stack1 = createTaskStackOnDisplay(mDisplayContent);
- final ActivityRecord activity1 = createTestActivityRecord(stack1);
+ // [DisplayContent] -+- [Task1] - [ActivityRecord1] (closing, invisible)
+ // +- [Task2] - [ActivityRecord2] (opening, visible)
+ final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
activity1.setVisible(true);
activity1.mVisibleRequested = true;
activity1.mRequestForceTransition = true;
- final Task stack2 = createTaskStackOnDisplay(mDisplayContent);
- final ActivityRecord activity2 = createTestActivityRecord(stack2);
+ final ActivityRecord activity2 = createActivityRecord(mDisplayContent);
activity2.setVisible(false);
activity2.mVisibleRequested = false;
activity2.mRequestForceTransition = true;
@@ -195,10 +191,8 @@
@Test
public void testGetAnimationTargets_exitingBeforeTransition() {
// Create another non-empty task so the animation target won't promote to task display area.
- createTestActivityRecord(
- mDisplayContent.getDefaultTaskDisplayArea().getOrCreateRootHomeTask());
- final Task stack = createTaskStackOnDisplay(mDisplayContent);
- final ActivityRecord activity = createTestActivityRecord(stack);
+ createActivityRecord(mDisplayContent);
+ final ActivityRecord activity = createActivityRecord(mDisplayContent);
activity.setVisible(false);
activity.mIsExiting = true;
@@ -208,19 +202,18 @@
// Animate closing apps even if it's not visible when it is exiting before we had a chance
// to play the transition animation.
assertEquals(
- new ArraySet<>(new WindowContainer[]{stack}),
+ new ArraySet<>(new WindowContainer[]{activity.getRootTask()}),
AppTransitionController.getAnimationTargets(
new ArraySet<>(), closing, false /* visible */));
}
@Test
public void testGetAnimationTargets_windowsAreBeingReplaced() {
- // [DisplayContent] -+- [TaskStack1] - [Task1] - [ActivityRecord1] (opening, visible)
- // +- [AppWindow1] (being-replaced)
- // +- [TaskStack2] - [Task2] - [ActivityRecord2] (closing, invisible)
- // +- [AppWindow2] (being-replaced)
- final Task stack1 = createTaskStackOnDisplay(mDisplayContent);
- final ActivityRecord activity1 = createTestActivityRecord(stack1);
+ // [DisplayContent] -+- [Task1] - [ActivityRecord1] (opening, visible)
+ // +- [AppWindow1] (being-replaced)
+ // +- [Task2] - [ActivityRecord2] (closing, invisible)
+ // +- [AppWindow2] (being-replaced)
+ final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
TYPE_BASE_APPLICATION);
attrs.setTitle("AppWindow1");
@@ -228,8 +221,7 @@
appWindow1.mWillReplaceWindow = true;
activity1.addWindow(appWindow1);
- final Task stack2 = createTaskStackOnDisplay(mDisplayContent);
- final ActivityRecord activity2 = createTestActivityRecord(stack2);
+ final ActivityRecord activity2 = createActivityRecord(mDisplayContent);
activity2.setVisible(false);
activity2.mVisibleRequested = false;
attrs.setTitle("AppWindow2");
@@ -246,7 +238,7 @@
// Don't animate closing apps if it's already invisible even though its windows are being
// replaced.
assertEquals(
- new ArraySet<>(new WindowContainer[]{stack1}),
+ new ArraySet<>(new WindowContainer[]{activity1.getRootTask()}),
AppTransitionController.getAnimationTargets(
opening, closing, true /* visible */));
assertEquals(
@@ -257,24 +249,22 @@
@Test
public void testGetAnimationTargets_openingClosingInDifferentTask() {
- // [DisplayContent] -+- [TaskStack1] - [Task1] -+- [ActivityRecord1] (opening, invisible)
- // | +- [ActivityRecord2] (invisible)
+ // [DisplayContent] -+- [Task1] -+- [ActivityRecord1] (opening, invisible)
+ // | +- [ActivityRecord2] (invisible)
// |
- // +- [TaskStack2] - [Task2] -+- [ActivityRecord3] (closing, visible)
- // +- [ActivityRecord4] (invisible)
- final Task stack1 = createTaskStackOnDisplay(mDisplayContent);
- final Task task1 = createTaskInStack(stack1, 0 /* userId */);
- final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task1);
+ // +- [Task2] -+- [ActivityRecord3] (closing, visible)
+ // +- [ActivityRecord4] (invisible)
+ final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
activity1.setVisible(false);
activity1.mVisibleRequested = true;
- final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task1);
+ final ActivityRecord activity2 = createActivityRecord(mDisplayContent,
+ activity1.getTask());
activity2.setVisible(false);
activity2.mVisibleRequested = false;
- final Task stack2 = createTaskStackOnDisplay(mDisplayContent);
- final Task task2 = createTaskInStack(stack2, 0 /* userId */);
- final ActivityRecord activity3 = createActivityRecordInTask(mDisplayContent, task2);
- final ActivityRecord activity4 = createActivityRecordInTask(mDisplayContent, task2);
+ final ActivityRecord activity3 = createActivityRecord(mDisplayContent);
+ final ActivityRecord activity4 = createActivityRecord(mDisplayContent,
+ activity3.getTask());
activity4.setVisible(false);
activity4.mVisibleRequested = false;
@@ -286,25 +276,24 @@
// Promote animation targets to TaskStack level. Invisible ActivityRecords don't affect
// promotion decision.
assertEquals(
- new ArraySet<>(new WindowContainer[]{stack1}),
+ new ArraySet<>(new WindowContainer[]{activity1.getRootTask()}),
AppTransitionController.getAnimationTargets(
opening, closing, true /* visible */));
assertEquals(
- new ArraySet<>(new WindowContainer[]{stack2}),
+ new ArraySet<>(new WindowContainer[]{activity3.getRootTask()}),
AppTransitionController.getAnimationTargets(
opening, closing, false /* visible */));
}
@Test
public void testGetAnimationTargets_openingClosingInSameTask() {
- // [DisplayContent] - [TaskStack] - [Task] -+- [ActivityRecord1] (opening, invisible)
- // +- [ActivityRecord2] (closing, visible)
- final Task stack = createTaskStackOnDisplay(mDisplayContent);
- final Task task = createTaskInStack(stack, 0 /* userId */);
- final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task);
+ // [DisplayContent] - [Task] -+- [ActivityRecord1] (opening, invisible)
+ // +- [ActivityRecord2] (closing, visible)
+ final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
activity1.setVisible(false);
activity1.mVisibleRequested = true;
- final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task);
+ final ActivityRecord activity2 = createActivityRecord(mDisplayContent,
+ activity1.getTask());
final ArraySet<ActivityRecord> opening = new ArraySet<>();
opening.add(activity1);
@@ -325,26 +314,24 @@
@Test
public void testGetAnimationTargets_animateOnlyTranslucentApp() {
- // [DisplayContent] -+- [TaskStack1] - [Task1] -+- [ActivityRecord1] (opening, invisible)
- // | +- [ActivityRecord2] (visible)
+ // [DisplayContent] -+- [Task1] -+- [ActivityRecord1] (opening, invisible)
+ // | +- [ActivityRecord2] (visible)
// |
- // +- [TaskStack2] - [Task2] -+- [ActivityRecord3] (closing, visible)
- // +- [ActivityRecord4] (visible)
+ // +- [Task2] -+- [ActivityRecord3] (closing, visible)
+ // +- [ActivityRecord4] (visible)
- final Task stack1 = createTaskStackOnDisplay(mDisplayContent);
- final Task task1 = createTaskInStack(stack1, 0 /* userId */);
- final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task1);
+ final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
activity1.setVisible(false);
activity1.mVisibleRequested = true;
activity1.setOccludesParent(false);
- final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task1);
+ final ActivityRecord activity2 = createActivityRecord(mDisplayContent,
+ activity1.getTask());
- final Task stack2 = createTaskStackOnDisplay(mDisplayContent);
- final Task task2 = createTaskInStack(stack2, 0 /* userId */);
- final ActivityRecord activity3 = createActivityRecordInTask(mDisplayContent, task2);
+ final ActivityRecord activity3 = createActivityRecord(mDisplayContent);
activity3.setOccludesParent(false);
- final ActivityRecord activity4 = createActivityRecordInTask(mDisplayContent, task2);
+ final ActivityRecord activity4 = createActivityRecord(mDisplayContent,
+ activity3.getTask());
final ArraySet<ActivityRecord> opening = new ArraySet<>();
opening.add(activity1);
@@ -365,28 +352,26 @@
@Test
public void testGetAnimationTargets_animateTranslucentAndOpaqueApps() {
- // [DisplayContent] -+- [TaskStack1] - [Task1] -+- [ActivityRecord1] (opening, invisible)
- // | +- [ActivityRecord2] (opening, invisible)
+ // [DisplayContent] -+- [Task1] -+- [ActivityRecord1] (opening, invisible)
+ // | +- [ActivityRecord2] (opening, invisible)
// |
- // +- [TaskStack2] - [Task2] -+- [ActivityRecord3] (closing, visible)
- // +- [ActivityRecord4] (closing, visible)
+ // +- [Task2] -+- [ActivityRecord3] (closing, visible)
+ // +- [ActivityRecord4] (closing, visible)
- final Task stack1 = createTaskStackOnDisplay(mDisplayContent);
- final Task task1 = createTaskInStack(stack1, 0 /* userId */);
- final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task1);
+ final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
activity1.setVisible(false);
activity1.mVisibleRequested = true;
activity1.setOccludesParent(false);
- final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task1);
+ final ActivityRecord activity2 = createActivityRecord(mDisplayContent,
+ activity1.getTask());
activity2.setVisible(false);
activity2.mVisibleRequested = true;
- final Task stack2 = createTaskStackOnDisplay(mDisplayContent);
- final Task task2 = createTaskInStack(stack2, 0 /* userId */);
- final ActivityRecord activity3 = createActivityRecordInTask(mDisplayContent, task2);
+ final ActivityRecord activity3 = createActivityRecord(mDisplayContent);
activity3.setOccludesParent(false);
- final ActivityRecord activity4 = createActivityRecordInTask(mDisplayContent, task2);
+ final ActivityRecord activity4 = createActivityRecord(mDisplayContent,
+ activity3.getTask());
final ArraySet<ActivityRecord> opening = new ArraySet<>();
opening.add(activity1);
@@ -398,26 +383,24 @@
// Promote animation targets to TaskStack level even though opening (closing) app is
// translucent as long as all visible siblings animate at the same time.
assertEquals(
- new ArraySet<>(new WindowContainer[]{stack1}),
+ new ArraySet<>(new WindowContainer[]{activity1.getRootTask()}),
AppTransitionController.getAnimationTargets(
opening, closing, true /* visible */));
assertEquals(
- new ArraySet<>(new WindowContainer[]{stack2}),
+ new ArraySet<>(new WindowContainer[]{activity3.getRootTask()}),
AppTransitionController.getAnimationTargets(
opening, closing, false /* visible */));
}
@Test
- public void testGetAnimationTargets_stackContainsMultipleTasks() {
- // [DisplayContent] - [TaskStack] -+- [Task1] - [ActivityRecord1] (opening, invisible)
- // +- [Task2] - [ActivityRecord2] (closing, visible)
- final Task stack = createTaskStackOnDisplay(mDisplayContent);
- final Task task1 = createTaskInStack(stack, 0 /* userId */);
- final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task1);
+ public void testGetAnimationTargets_taskContainsMultipleTasks() {
+ // [DisplayContent] - [Task] -+- [Task1] - [ActivityRecord1] (opening, invisible)
+ // +- [Task2] - [ActivityRecord2] (closing, visible)
+ final Task parentTask = createTaskStackOnDisplay(mDisplayContent);
+ final ActivityRecord activity1 = createActivityRecordWithParentTask(parentTask);
activity1.setVisible(false);
activity1.mVisibleRequested = true;
- final Task task2 = createTaskInStack(stack, 0 /* userId */);
- final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task2);
+ final ActivityRecord activity2 = createActivityRecordWithParentTask(parentTask);
final ArraySet<ActivityRecord> opening = new ArraySet<>();
opening.add(activity1);
@@ -426,11 +409,11 @@
// Promote animation targets up to Task level, not beyond.
assertEquals(
- new ArraySet<>(new WindowContainer[]{task1}),
+ new ArraySet<>(new WindowContainer[]{activity1.getTask()}),
AppTransitionController.getAnimationTargets(
opening, closing, true /* visible */));
assertEquals(
- new ArraySet<>(new WindowContainer[]{task2}),
+ new ArraySet<>(new WindowContainer[]{activity2.getTask()}),
AppTransitionController.getAnimationTargets(
opening, closing, false /* visible */));
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 485f92f..850e72e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -16,8 +16,6 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
@@ -116,10 +114,8 @@
final DisplayContent dc2 = createNewDisplay(Display.STATE_ON);
// Create 2 app window tokens to represent 2 activity window.
- final ActivityRecord activity1 = createTestActivityRecord(dc1,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
- final ActivityRecord activity2 = createTestActivityRecord(dc2,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final ActivityRecord activity1 = createActivityRecord(dc1);
+ final ActivityRecord activity2 = createActivityRecord(dc2);
activity1.allDrawn = true;
activity1.startingDisplayed = true;
@@ -153,7 +149,7 @@
final Task stack1 = createTaskStackOnDisplay(dc1);
final Task task1 = createTaskInStack(stack1, 0 /* userId */);
- final ActivityRecord activity1 = createTestActivityRecord(dc1);
+ final ActivityRecord activity1 = createNonAttachedActivityRecord(dc1);
task1.addChild(activity1, 0);
// Simulate same app is during opening / closing transition set stage.
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
index b93a8fc..fd562c3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
@@ -16,9 +16,6 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
@@ -31,7 +28,6 @@
import android.platform.test.annotations.Presubmit;
import android.view.SurfaceControl;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Before;
@@ -62,8 +58,7 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mActivity = createTestActivityRecord(mDisplayContent, WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD);
+ mActivity = createActivityRecord(mDisplayContent);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 6837e0e..28d5ffe 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -92,7 +92,7 @@
public void setUp() throws Exception {
mStack = createTaskStackOnDisplay(mDisplayContent);
mTask = createTaskInStack(mStack, 0 /* userId */);
- mActivity = createTestActivityRecord(mDisplayContent);
+ mActivity = createNonAttachedActivityRecord(mDisplayContent);
mTask.addChild(mActivity, 0);
}
@@ -307,7 +307,7 @@
assertEquals(Configuration.ORIENTATION_PORTRAIT, displayConfig.orientation);
assertEquals(Configuration.ORIENTATION_PORTRAIT, activityConfig.orientation);
- final ActivityRecord topActivity = createTestActivityRecord(mStack);
+ final ActivityRecord topActivity = createActivityRecord(mTask);
topActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
assertEquals(Configuration.ORIENTATION_LANDSCAPE, displayConfig.orientation);
@@ -490,7 +490,7 @@
}
private ActivityRecord createTestActivityRecordForGivenTask(Task task) {
- final ActivityRecord activity = createTestActivityRecord(mDisplayContent);
+ final ActivityRecord activity = createNonAttachedActivityRecord(mDisplayContent);
task.addChild(activity, 0);
waitUntilHandlersIdle();
return activity;
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
index 9a668b9..4a5a81e8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
@@ -67,7 +67,7 @@
mDisplayAreaGroup.addChild(mTaskDisplayArea, POSITION_TOP);
mStack = mTaskDisplayArea.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- mActivity = new ActivityBuilder(mAtm).setCreateTask(true).setStack(mStack).build();
+ mActivity = new ActivityBuilder(mAtm).setTask(mStack).build();
mDisplayContent.setLastFocusedTaskDisplayArea(mTaskDisplayArea);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index f52f983..fbfc0e0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -283,8 +282,7 @@
@UseTestDisplay(addAllCommonWindows = true)
@Test
public void testComputeImeTarget_startingWindow() {
- ActivityRecord activity = createActivityRecord(mDisplayContent,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ ActivityRecord activity = createActivityRecord(mDisplayContent);
final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, activity,
"startingWin");
@@ -328,7 +326,7 @@
assertEquals(dc, stack.getDisplayContent());
final Task task = createTaskInStack(stack, 0 /* userId */);
- final ActivityRecord activity = createTestActivityRecord(dc);
+ final ActivityRecord activity = createNonAttachedActivityRecord(dc);
task.addChild(activity, 0);
assertEquals(dc, task.getDisplayContent());
assertEquals(dc, activity.getDisplayContent());
@@ -399,14 +397,14 @@
// Add stack with activity.
final Task stack0 = createTaskStackOnDisplay(dc0);
final Task task0 = createTaskInStack(stack0, 0 /* userId */);
- final ActivityRecord activity = createTestActivityRecord(dc0);
+ final ActivityRecord activity = createNonAttachedActivityRecord(dc0);
task0.addChild(activity, 0);
dc0.configureDisplayPolicy();
assertNotNull(dc0.mTapDetector);
final Task stack1 = createTaskStackOnDisplay(dc1);
final Task task1 = createTaskInStack(stack1, 0 /* userId */);
- final ActivityRecord activity1 = createTestActivityRecord(dc0);
+ final ActivityRecord activity1 = createNonAttachedActivityRecord(dc0);
task1.addChild(activity1, 0);
dc1.configureDisplayPolicy();
assertNotNull(dc1.mTapDetector);
@@ -1223,7 +1221,7 @@
// Launch another activity before the transition is finished.
final Task task2 = new TaskBuilder(mSupervisor).setDisplay(mDisplayContent).build();
- final ActivityRecord app2 = new ActivityBuilder(mAtm).setStack(task2)
+ final ActivityRecord app2 = new ActivityBuilder(mAtm).setTask(task2)
.setUseProcess(app.app).build();
app2.setVisible(false);
mDisplayContent.mOpeningApps.add(app2);
@@ -1260,8 +1258,7 @@
@Test
public void testFinishFixedRotationNoAppTransitioningTask() {
unblockDisplayRotation(mDisplayContent);
- final ActivityRecord app = createActivityRecord(mDisplayContent, WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD);
+ final ActivityRecord app = createActivityRecord(mDisplayContent);
final Task task = app.getTask();
final ActivityRecord app2 = new ActivityBuilder(mWm.mAtmService).setTask(task).build();
mDisplayContent.setFixedRotationLaunchingApp(app2, (mDisplayContent.getRotation() + 1) % 4);
@@ -1314,8 +1311,7 @@
final ActivityRecord pinnedActivity = createActivityRecord(displayContent,
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD);
final Task pinnedTask = pinnedActivity.getRootTask();
- final ActivityRecord homeActivity = createTestActivityRecord(
- displayContent.getDefaultTaskDisplayArea().getOrCreateRootHomeTask());
+ final ActivityRecord homeActivity = createActivityRecord(displayContent);
if (displayConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
homeActivity.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
pinnedActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
@@ -1378,10 +1374,8 @@
// Skip freezing so the unrelated conditions in updateRotationUnchecked won't disturb.
doNothing().when(mWm).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
- final ActivityRecord activity = createActivityRecord(mDisplayContent,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
- final ActivityRecord recentsActivity = createActivityRecord(mDisplayContent,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS);
+ final ActivityRecord activity = createActivityRecord(mDisplayContent);
+ final ActivityRecord recentsActivity = createActivityRecord(mDisplayContent);
recentsActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
// Do not rotate if the recents animation is animating on top.
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
new file mode 100644
index 0000000..b346bb8
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.Nullable;
+import android.platform.test.annotations.Presubmit;
+import android.util.Xml;
+import android.view.Display;
+import android.view.DisplayAddress;
+import android.view.DisplayInfo;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Tests for the {@link DisplayWindowSettingsProvider} class.
+ *
+ * Build/Install/Run:
+ * atest WmTests:DisplayWindowSettingsProviderTests
+ */
+@SmallTest
+@Presubmit
+@WindowTestsBase.UseTestDisplay
+@RunWith(WindowTestRunner.class)
+public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
+ private static final int DISPLAY_PORT = 0xFF;
+ private static final long DISPLAY_MODEL = 0xEEEEEEEEL;
+
+ private static final File TEST_FOLDER = getInstrumentation().getTargetContext().getCacheDir();
+
+ private TestStorage mBaseSettingsStorage;
+ private TestStorage mOverrideSettingsStorage;
+
+ private DisplayContent mPrimaryDisplay;
+ private DisplayContent mSecondaryDisplay;
+
+ @Before
+ public void setUp() throws Exception {
+ deleteRecursively(TEST_FOLDER);
+
+ mBaseSettingsStorage = new TestStorage();
+ mOverrideSettingsStorage = new TestStorage();
+
+ mPrimaryDisplay = mWm.getDefaultDisplayContentLocked();
+ mSecondaryDisplay = mDisplayContent;
+ assertNotEquals(Display.DEFAULT_DISPLAY, mSecondaryDisplay.getDisplayId());
+ }
+
+ @After
+ public void tearDown() {
+ deleteRecursively(TEST_FOLDER);
+ }
+
+ @Test
+ public void testReadingDisplaySettingsFromStorage() {
+ final String displayIdentifier = mSecondaryDisplay.getDisplayInfo().uniqueId;
+ prepareOverrideDisplaySettings(displayIdentifier);
+
+ SettingsEntry expectedSettings = new SettingsEntry();
+ expectedSettings.mWindowingMode = WINDOWING_MODE_PINNED;
+ readAndAssertExpectedSettings(mPrimaryDisplay, expectedSettings);
+ }
+
+ @Test
+ public void testReadingDisplaySettingsFromStorage_LegacyDisplayId() {
+ final String displayIdentifier = mPrimaryDisplay.getDisplayInfo().name;
+ prepareOverrideDisplaySettings(displayIdentifier);
+
+ SettingsEntry expectedSettings = new SettingsEntry();
+ expectedSettings.mWindowingMode = WINDOWING_MODE_PINNED;
+ readAndAssertExpectedSettings(mPrimaryDisplay, expectedSettings);
+ }
+
+ @Test
+ public void testReadingDisplaySettingsFromStorage_LegacyDisplayId_UpdateAfterAccess()
+ throws Exception {
+ // Store display settings with legacy display identifier.
+ final DisplayInfo mPrimaryDisplayInfo = mPrimaryDisplay.getDisplayInfo();
+ final String displayIdentifier = mPrimaryDisplayInfo.name;
+ prepareOverrideDisplaySettings(displayIdentifier);
+
+ // Update settings with new value, should trigger write to injector.
+ DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
+ mBaseSettingsStorage, mOverrideSettingsStorage);
+ SettingsEntry overrideSettings = provider.getOverrideSettings(mPrimaryDisplayInfo);
+ overrideSettings.mForcedDensity = 200;
+ provider.updateOverrideSettings(mPrimaryDisplayInfo, overrideSettings);
+ assertTrue(mOverrideSettingsStorage.wasWriteSuccessful());
+
+ // Verify that display identifier was updated.
+ final String newDisplayIdentifier = getStoredDisplayAttributeValue(
+ mOverrideSettingsStorage, "name");
+ assertEquals("Display identifier must be updated to use uniqueId",
+ mPrimaryDisplayInfo.uniqueId, newDisplayIdentifier);
+ }
+
+ @Test
+ public void testReadingDisplaySettingsFromStorage_UsePortAsId() {
+ final DisplayAddress.Physical displayAddress =
+ DisplayAddress.fromPortAndModel(DISPLAY_PORT, DISPLAY_MODEL);
+ mPrimaryDisplay.getDisplayInfo().address = displayAddress;
+
+ final String displayIdentifier = "port:" + DISPLAY_PORT;
+ prepareOverrideDisplaySettings(displayIdentifier, true /* usePortAsId */);
+
+ SettingsEntry expectedSettings = new SettingsEntry();
+ expectedSettings.mWindowingMode = WINDOWING_MODE_PINNED;
+ readAndAssertExpectedSettings(mPrimaryDisplay, expectedSettings);
+ }
+
+ @Test
+ public void testReadingDisplaySettingsFromStorage_UsePortAsId_IncorrectAddress() {
+ final String displayIdentifier = mPrimaryDisplay.getDisplayInfo().uniqueId;
+ prepareOverrideDisplaySettings(displayIdentifier, true /* usePortAsId */);
+
+ mPrimaryDisplay.getDisplayInfo().address = DisplayAddress.fromPhysicalDisplayId(123456);
+
+ // Verify that the entry is not matched and default settings are returned instead.
+ SettingsEntry expectedSettings = new SettingsEntry();
+ readAndAssertExpectedSettings(mPrimaryDisplay, expectedSettings);
+ }
+
+ @Test
+ public void testWritingDisplaySettingsToStorage() throws Exception {
+ final DisplayInfo secondaryDisplayInfo = mSecondaryDisplay.getDisplayInfo();
+
+ // Write some settings to storage.
+ DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
+ mBaseSettingsStorage, mOverrideSettingsStorage);
+ SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo);
+ overrideSettings.mShouldShowSystemDecors = true;
+ overrideSettings.mShouldShowIme = true;
+ provider.updateOverrideSettings(secondaryDisplayInfo, overrideSettings);
+ assertTrue(mOverrideSettingsStorage.wasWriteSuccessful());
+
+ // Verify that settings were stored correctly.
+ assertEquals("Attribute value must be stored", secondaryDisplayInfo.uniqueId,
+ getStoredDisplayAttributeValue(mOverrideSettingsStorage, "name"));
+ assertEquals("Attribute value must be stored", "true",
+ getStoredDisplayAttributeValue(mOverrideSettingsStorage, "shouldShowSystemDecors"));
+ assertEquals("Attribute value must be stored", "true",
+ getStoredDisplayAttributeValue(mOverrideSettingsStorage, "shouldShowIme"));
+ }
+
+ @Test
+ public void testWritingDisplaySettingsToStorage_UsePortAsId() throws Exception {
+ prepareOverrideDisplaySettings(null /* displayIdentifier */, true /* usePortAsId */);
+
+ // Store config to use port as identifier.
+ final DisplayInfo secondaryDisplayInfo = mSecondaryDisplay.getDisplayInfo();
+ final DisplayAddress.Physical displayAddress =
+ DisplayAddress.fromPortAndModel(DISPLAY_PORT, DISPLAY_MODEL);
+ secondaryDisplayInfo.address = displayAddress;
+
+ // Write some settings to storage.
+ DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
+ mBaseSettingsStorage, mOverrideSettingsStorage);
+ SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo);
+ overrideSettings.mShouldShowSystemDecors = true;
+ overrideSettings.mShouldShowIme = true;
+ provider.updateOverrideSettings(secondaryDisplayInfo, overrideSettings);
+ assertTrue(mOverrideSettingsStorage.wasWriteSuccessful());
+
+ // Verify that settings were stored correctly.
+ assertEquals("Attribute value must be stored", "port:" + DISPLAY_PORT,
+ getStoredDisplayAttributeValue(mOverrideSettingsStorage, "name"));
+ assertEquals("Attribute value must be stored", "true",
+ getStoredDisplayAttributeValue(mOverrideSettingsStorage, "shouldShowSystemDecors"));
+ assertEquals("Attribute value must be stored", "true",
+ getStoredDisplayAttributeValue(mOverrideSettingsStorage, "shouldShowIme"));
+ }
+
+ /**
+ * Prepares display settings and stores in {@link #mOverrideSettingsStorage}. Uses provided
+ * display identifier and stores windowingMode=WINDOWING_MODE_PINNED.
+ */
+ private void prepareOverrideDisplaySettings(String displayIdentifier) {
+ prepareOverrideDisplaySettings(displayIdentifier, false /* usePortAsId */);
+ }
+
+ private void prepareOverrideDisplaySettings(String displayIdentifier, boolean usePortAsId) {
+ String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<display-settings>\n";
+ if (usePortAsId) {
+ contents += " <config identifier=\"1\"/>\n";
+ }
+ if (displayIdentifier != null) {
+ contents += " <display\n"
+ + " name=\"" + displayIdentifier + "\"\n"
+ + " windowingMode=\"" + WINDOWING_MODE_PINNED + "\"/>\n";
+ }
+ contents += "</display-settings>\n";
+
+ final InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8));
+ mOverrideSettingsStorage.setReadStream(is);
+ }
+
+ private void readAndAssertExpectedSettings(DisplayContent displayContent,
+ SettingsEntry expectedSettings) {
+ final DisplayWindowSettingsProvider provider =
+ new DisplayWindowSettingsProvider(mBaseSettingsStorage, mOverrideSettingsStorage);
+ assertEquals(expectedSettings, provider.getSettings(displayContent.getDisplayInfo()));
+ }
+
+ @Nullable
+ private String getStoredDisplayAttributeValue(TestStorage storage, String attr)
+ throws Exception {
+ try (InputStream stream = storage.openRead()) {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, StandardCharsets.UTF_8.name());
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ // Do nothing.
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new IllegalStateException("no start tag found");
+ }
+
+ int outerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("display")) {
+ return parser.getAttributeValue(null, attr);
+ }
+ }
+ } finally {
+ storage.closeRead();
+ }
+ return null;
+ }
+
+ private static boolean deleteRecursively(File file) {
+ boolean fullyDeleted = true;
+ if (file.isFile()) {
+ return file.delete();
+ } else if (file.isDirectory()) {
+ final File[] files = file.listFiles();
+ for (File child : files) {
+ fullyDeleted &= deleteRecursively(child);
+ }
+ fullyDeleted &= file.delete();
+ }
+ return fullyDeleted;
+ }
+
+ /** In-memory storage implementation. */
+ public class TestStorage implements DisplayWindowSettingsProvider.WritableSettingsStorage {
+ private InputStream mReadStream;
+ private ByteArrayOutputStream mWriteStream;
+
+ private boolean mWasSuccessful;
+
+ /**
+ * Returns input stream for reading. By default tries forward the output stream if previous
+ * write was successful.
+ * @see #closeRead()
+ */
+ @Override
+ public InputStream openRead() throws FileNotFoundException {
+ if (mReadStream == null && mWasSuccessful) {
+ mReadStream = new ByteArrayInputStream(mWriteStream.toByteArray());
+ }
+ if (mReadStream == null) {
+ throw new FileNotFoundException();
+ }
+ if (mReadStream.markSupported()) {
+ mReadStream.mark(Integer.MAX_VALUE);
+ }
+ return mReadStream;
+ }
+
+ /** Must be called after each {@link #openRead} to reset the position in the stream. */
+ void closeRead() throws IOException {
+ if (mReadStream == null) {
+ throw new FileNotFoundException();
+ }
+ if (mReadStream.markSupported()) {
+ mReadStream.reset();
+ }
+ mReadStream = null;
+ }
+
+ /**
+ * Creates new or resets existing output stream for write. Automatically closes previous
+ * read stream, since following reads should happen based on this new write.
+ */
+ @Override
+ public OutputStream startWrite() throws IOException {
+ if (mWriteStream == null) {
+ mWriteStream = new ByteArrayOutputStream();
+ } else {
+ mWriteStream.reset();
+ }
+ if (mReadStream != null) {
+ closeRead();
+ }
+ return mWriteStream;
+ }
+
+ @Override
+ public void finishWrite(OutputStream os, boolean success) {
+ mWasSuccessful = success;
+ try {
+ os.close();
+ } catch (IOException e) {
+ // This method can't throw IOException since the super implementation doesn't, so
+ // we just wrap it in a RuntimeException so we end up crashing the test all the
+ // same.
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** Overrides the read stream of the injector. By default it uses current write stream. */
+ private void setReadStream(InputStream is) {
+ mReadStream = is;
+ }
+
+ private boolean wasWriteSuccessful() {
+ return mWasSuccessful;
+ }
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index a3d3739a..2ca5583 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -17,15 +17,12 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT;
import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_DISABLED;
import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_ENABLED;
import static android.view.WindowManager.REMOVE_CONTENT_MODE_DESTROY;
import static android.view.WindowManager.REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY;
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
@@ -40,12 +37,11 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Matchers.eq;
+import android.annotation.NonNull;
import android.app.WindowConfiguration;
import android.content.res.Configuration;
import android.platform.test.annotations.Presubmit;
-import android.util.Xml;
import android.view.Display;
-import android.view.DisplayAddress;
import android.view.DisplayInfo;
import android.view.Surface;
@@ -53,21 +49,14 @@
import com.android.server.LocalServices;
import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.xmlpull.v1.XmlPullParser;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
/**
* Tests for the {@link DisplayWindowSettings} class.
@@ -80,12 +69,8 @@
@WindowTestsBase.UseTestDisplay
@RunWith(WindowTestRunner.class)
public class DisplayWindowSettingsTests extends WindowTestsBase {
-
- private static final int DISPLAY_PORT = 0xFF;
- private static final long DISPLAY_MODEL = 0xEEEEEEEEL;
-
- private static final File TEST_FOLDER = getInstrumentation().getTargetContext().getCacheDir();
- private DisplayWindowSettings mTarget;
+ private TestSettingsProvider mSettingsProvider;
+ private DisplayWindowSettings mDisplayWindowSettings;
private DisplayInfo mPrivateDisplayInfo;
@@ -93,18 +78,19 @@
private DisplayContent mSecondaryDisplay;
private DisplayContent mPrivateDisplay;
- private TestStorage mStorage;
-
@Before
public void setUp() throws Exception {
- deleteRecursively(TEST_FOLDER);
-
+ // TODO(b/121296525): We may want to restore other display settings (not only overscans in
+ // testPersistOverscan*test) on mPrimaryDisplay and mSecondaryDisplay back to default
+ // values after each test finishes, since we are going to reuse a singleton
+ // WindowManagerService instance among all tests that extend {@link WindowTestsBase} class
+ // (b/113239988).
mWm.mAtmService.mSupportsFreeformWindowManagement = false;
mWm.setIsPc(false);
mWm.setForceDesktopModeOnExternalDisplays(false);
- mStorage = new TestStorage();
- mTarget = new DisplayWindowSettings(mWm, mStorage);
+ mSettingsProvider = new TestSettingsProvider();
+ mDisplayWindowSettings = new DisplayWindowSettings(mWm, mSettingsProvider);
mPrimaryDisplay = mWm.getDefaultDisplayContentLocked();
mSecondaryDisplay = mDisplayContent;
@@ -117,20 +103,9 @@
assertNotEquals(mSecondaryDisplay.getDisplayId(), mPrivateDisplay.getDisplayId());
}
- @After
- public void tearDown() {
- deleteRecursively(TEST_FOLDER);
-
- // TODO(b/121296525): We may want to restore other display settings (not only overscans in
- // testPersistOverscan*test) on mPrimaryDisplay and mSecondaryDisplay back to default
- // values after each test finishes, since we are going to reuse a singleton
- // WindowManagerService instance among all tests that extend {@link WindowTestsBase} class
- // (b/113239988).
- }
-
@Test
public void testPrimaryDisplayDefaultToFullscreen_NoFreeformSupport() {
- mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
mPrimaryDisplay.getWindowingMode());
@@ -140,7 +115,7 @@
public void testPrimaryDisplayDefaultToFullscreen_HasFreeformSupport_NonPc_NoDesktopMode() {
mWm.mAtmService.mSupportsFreeformWindowManagement = true;
- mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
mPrimaryDisplay.getWindowingMode());
@@ -151,7 +126,7 @@
mWm.mAtmService.mSupportsFreeformWindowManagement = true;
mWm.setForceDesktopModeOnExternalDisplays(true);
- mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
mPrimaryDisplay.getWindowingMode());
@@ -162,20 +137,19 @@
mWm.mAtmService.mSupportsFreeformWindowManagement = true;
mWm.setIsPc(true);
- mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
- assertEquals(WINDOWING_MODE_FREEFORM,
- mPrimaryDisplay.getWindowingMode());
+ assertEquals(WINDOWING_MODE_FREEFORM, mPrimaryDisplay.getWindowingMode());
}
@Test
public void testPrimaryDisplayUpdateToFreeform_HasFreeformSupport_IsPc() {
- mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
mWm.mAtmService.mSupportsFreeformWindowManagement = true;
mWm.setIsPc(true);
- mTarget.updateSettingsForDisplay(mPrimaryDisplay);
+ mDisplayWindowSettings.updateSettingsForDisplay(mPrimaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FREEFORM,
mPrimaryDisplay.getWindowingMode());
@@ -183,7 +157,7 @@
@Test
public void testSecondaryDisplayDefaultToFullscreen_NoFreeformSupport() {
- mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
mSecondaryDisplay.getWindowingMode());
@@ -193,7 +167,7 @@
public void testSecondaryDisplayDefaultToFreeform_HasFreeformSupport_NonPc_NoDesktopMode() {
mWm.mAtmService.mSupportsFreeformWindowManagement = true;
- mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
mSecondaryDisplay.getWindowingMode());
@@ -204,7 +178,7 @@
mWm.mAtmService.mSupportsFreeformWindowManagement = true;
mWm.setForceDesktopModeOnExternalDisplays(true);
- mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(WINDOWING_MODE_FREEFORM,
mSecondaryDisplay.getWindowingMode());
@@ -215,7 +189,7 @@
mWm.mAtmService.mSupportsFreeformWindowManagement = true;
mWm.setIsPc(true);
- mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(WINDOWING_MODE_FREEFORM,
mSecondaryDisplay.getWindowingMode());
@@ -228,7 +202,7 @@
final int originalDensity = mSecondaryDisplay.mBaseDisplayDensity;
final boolean originalScalingDisabled = mSecondaryDisplay.mDisplayScalingDisabled;
- mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(originalWidth, mSecondaryDisplay.mBaseDisplayWidth);
assertEquals(originalHeight, mSecondaryDisplay.mBaseDisplayHeight);
@@ -245,8 +219,9 @@
return null;
}).when(mWm.mDisplayManagerInternal).getNonOverrideDisplayInfo(anyInt(), any());
- mTarget.setForcedSize(mSecondaryDisplay, 1000 /* width */, 2000 /* height */);
- applySettingsToDisplayByNewInstance(mSecondaryDisplay);
+ mDisplayWindowSettings.setForcedSize(mSecondaryDisplay, 1000 /* width */,
+ 2000 /* height */);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(1000 /* width */, mSecondaryDisplay.mBaseDisplayWidth);
assertEquals(2000 /* height */, mSecondaryDisplay.mBaseDisplayHeight);
@@ -258,8 +233,9 @@
@Test
public void testSetForcedDensity() {
- mTarget.setForcedDensity(mSecondaryDisplay, 600 /* density */, 0 /* userId */);
- applySettingsToDisplayByNewInstance(mSecondaryDisplay);
+ mDisplayWindowSettings.setForcedDensity(mSecondaryDisplay, 600 /* density */,
+ 0 /* userId */);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(600 /* density */, mSecondaryDisplay.mBaseDisplayDensity);
@@ -270,8 +246,9 @@
@Test
public void testSetForcedScalingMode() {
- mTarget.setForcedScalingMode(mSecondaryDisplay, DisplayContent.FORCE_SCALING_MODE_DISABLED);
- applySettingsToDisplayByNewInstance(mSecondaryDisplay);
+ mDisplayWindowSettings.setForcedScalingMode(mSecondaryDisplay,
+ DisplayContent.FORCE_SCALING_MODE_DISABLED);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertTrue(mSecondaryDisplay.mDisplayScalingDisabled);
@@ -282,7 +259,7 @@
@Test
public void testDefaultToFreeUserRotation() {
- mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
final DisplayRotation rotation = mSecondaryDisplay.getDisplayRotation();
assertEquals(WindowManagerPolicy.USER_ROTATION_FREE, rotation.getUserRotationMode());
@@ -291,7 +268,7 @@
@Test
public void testDefaultTo0DegRotation() {
- mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(Surface.ROTATION_0, mSecondaryDisplay.getDisplayRotation().getUserRotation());
}
@@ -299,70 +276,68 @@
@Test
public void testPrivateDisplayDefaultToDestroyContent() {
assertEquals(REMOVE_CONTENT_MODE_DESTROY,
- mTarget.getRemoveContentModeLocked(mPrivateDisplay));
+ mDisplayWindowSettings.getRemoveContentModeLocked(mPrivateDisplay));
}
@Test
public void testPublicDisplayDefaultToMoveToPrimary() {
assertEquals(REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY,
- mTarget.getRemoveContentModeLocked(mSecondaryDisplay));
+ mDisplayWindowSettings.getRemoveContentModeLocked(mSecondaryDisplay));
}
@Test
public void testDefaultToNotShowWithInsecureKeyguard() {
- assertFalse(mTarget.shouldShowWithInsecureKeyguardLocked(mPrivateDisplay));
- assertFalse(mTarget.shouldShowWithInsecureKeyguardLocked(mSecondaryDisplay));
+ assertFalse(mDisplayWindowSettings.shouldShowWithInsecureKeyguardLocked(mPrivateDisplay));
+ assertFalse(mDisplayWindowSettings.shouldShowWithInsecureKeyguardLocked(mSecondaryDisplay));
}
- @Test
+ @Test(expected = IllegalArgumentException.class)
public void testPublicDisplayNotAllowSetShouldShowWithInsecureKeyguard() {
- mTarget.setShouldShowWithInsecureKeyguardLocked(mSecondaryDisplay, true);
-
- assertFalse(mTarget.shouldShowWithInsecureKeyguardLocked(mSecondaryDisplay));
+ mDisplayWindowSettings.setShouldShowWithInsecureKeyguardLocked(mSecondaryDisplay, true);
}
@Test
public void testPrivateDisplayAllowSetShouldShowWithInsecureKeyguard() {
- mTarget.setShouldShowWithInsecureKeyguardLocked(mPrivateDisplay, true);
+ mDisplayWindowSettings.setShouldShowWithInsecureKeyguardLocked(mPrivateDisplay, true);
- assertTrue(mTarget.shouldShowWithInsecureKeyguardLocked(mPrivateDisplay));
+ assertTrue(mDisplayWindowSettings.shouldShowWithInsecureKeyguardLocked(mPrivateDisplay));
}
@Test
public void testPrimaryDisplayShouldShowSystemDecors() {
- assertTrue(mTarget.shouldShowSystemDecorsLocked(mPrimaryDisplay));
+ assertTrue(mDisplayWindowSettings.shouldShowSystemDecorsLocked(mPrimaryDisplay));
- mTarget.setShouldShowSystemDecorsLocked(mPrimaryDisplay, false);
+ mDisplayWindowSettings.setShouldShowSystemDecorsLocked(mPrimaryDisplay, false);
// Default display should show system decors
- assertTrue(mTarget.shouldShowSystemDecorsLocked(mPrimaryDisplay));
+ assertTrue(mDisplayWindowSettings.shouldShowSystemDecorsLocked(mPrimaryDisplay));
}
@Test
public void testSecondaryDisplayDefaultToNotShowSystemDecors() {
- assertFalse(mTarget.shouldShowSystemDecorsLocked(mSecondaryDisplay));
+ assertFalse(mDisplayWindowSettings.shouldShowSystemDecorsLocked(mSecondaryDisplay));
}
@Test
public void testPrimaryDisplayShouldShowIme() {
- assertTrue(mTarget.shouldShowImeLocked(mPrimaryDisplay));
+ assertTrue(mDisplayWindowSettings.shouldShowImeLocked(mPrimaryDisplay));
- mTarget.setShouldShowImeLocked(mPrimaryDisplay, false);
+ mDisplayWindowSettings.setShouldShowImeLocked(mPrimaryDisplay, false);
- assertTrue(mTarget.shouldShowImeLocked(mPrimaryDisplay));
+ assertTrue(mDisplayWindowSettings.shouldShowImeLocked(mPrimaryDisplay));
}
@Test
public void testSecondaryDisplayDefaultToNotShowIme() {
- assertFalse(mTarget.shouldShowImeLocked(mSecondaryDisplay));
+ assertFalse(mDisplayWindowSettings.shouldShowImeLocked(mSecondaryDisplay));
}
@Test
- public void testPersistUserRotationModeInSameInstance() {
- mTarget.setUserRotation(mSecondaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
- Surface.ROTATION_90);
+ public void testSetUserRotationMode() {
+ mDisplayWindowSettings.setUserRotation(mSecondaryDisplay,
+ WindowManagerPolicy.USER_ROTATION_LOCKED, Surface.ROTATION_90);
- mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
final DisplayRotation rotation = mSecondaryDisplay.getDisplayRotation();
assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation.getUserRotationMode());
@@ -370,48 +345,25 @@
}
@Test
- public void testPersistUserRotationInSameInstance() {
- mTarget.setUserRotation(mSecondaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
- Surface.ROTATION_90);
+ public void testSetUserRotation() {
+ mDisplayWindowSettings.setUserRotation(mSecondaryDisplay,
+ WindowManagerPolicy.USER_ROTATION_LOCKED, Surface.ROTATION_90);
- mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(Surface.ROTATION_90, mSecondaryDisplay.getDisplayRotation().getUserRotation());
}
@Test
- public void testPersistUserRotationModeAcrossInstances() {
- mTarget.setUserRotation(mSecondaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
- Surface.ROTATION_270);
-
- applySettingsToDisplayByNewInstance(mSecondaryDisplay);
-
- final DisplayRotation rotation = mSecondaryDisplay.getDisplayRotation();
- assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation.getUserRotationMode());
- assertTrue(rotation.isRotationFrozen());
- }
-
- @Test
- public void testPersistUserRotationAcrossInstances() {
- mTarget.setUserRotation(mSecondaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
- Surface.ROTATION_270);
-
- applySettingsToDisplayByNewInstance(mSecondaryDisplay);
-
- assertEquals(Surface.ROTATION_270,
- mSecondaryDisplay.getDisplayRotation().getUserRotation());
- }
-
- @Test
public void testFixedToUserRotationDefault() {
- mTarget.setUserRotation(mPrimaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
- Surface.ROTATION_0);
+ mDisplayWindowSettings.setUserRotation(mPrimaryDisplay,
+ WindowManagerPolicy.USER_ROTATION_LOCKED, Surface.ROTATION_0);
final DisplayRotation displayRotation = mock(DisplayRotation.class);
spyOn(mPrimaryDisplay);
doReturn(displayRotation).when(mPrimaryDisplay).getDisplayRotation();
- mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
verify(displayRotation).restoreSettings(anyInt(), anyInt(),
eq(FIXED_TO_USER_ROTATION_DEFAULT));
@@ -419,13 +371,14 @@
@Test
public void testSetFixedToUserRotationDisabled() {
- mTarget.setFixedToUserRotation(mPrimaryDisplay, FIXED_TO_USER_ROTATION_DISABLED);
+ mDisplayWindowSettings.setFixedToUserRotation(mPrimaryDisplay,
+ FIXED_TO_USER_ROTATION_DISABLED);
final DisplayRotation displayRotation = mock(DisplayRotation.class);
spyOn(mPrimaryDisplay);
doReturn(displayRotation).when(mPrimaryDisplay).getDisplayRotation();
- applySettingsToDisplayByNewInstance(mPrimaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
verify(displayRotation).restoreSettings(anyInt(), anyInt(),
eq(FIXED_TO_USER_ROTATION_DISABLED));
@@ -433,120 +386,20 @@
@Test
public void testSetFixedToUserRotationEnabled() {
- mTarget.setFixedToUserRotation(mPrimaryDisplay, FIXED_TO_USER_ROTATION_ENABLED);
+ mDisplayWindowSettings.setFixedToUserRotation(mPrimaryDisplay,
+ FIXED_TO_USER_ROTATION_ENABLED);
final DisplayRotation displayRotation = mock(DisplayRotation.class);
spyOn(mPrimaryDisplay);
doReturn(displayRotation).when(mPrimaryDisplay).getDisplayRotation();
- applySettingsToDisplayByNewInstance(mPrimaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
verify(displayRotation).restoreSettings(anyInt(), anyInt(),
eq(FIXED_TO_USER_ROTATION_ENABLED));
}
@Test
- public void testReadingDisplaySettingsFromStorage() {
- final String displayIdentifier = mSecondaryDisplay.getDisplayInfo().uniqueId;
- prepareDisplaySettings(displayIdentifier);
-
- readAndAssertDisplaySettings(mPrimaryDisplay);
- }
-
- @Test
- public void testReadingDisplaySettingsFromStorage_LegacyDisplayId() {
- final String displayIdentifier = mPrimaryDisplay.getDisplayInfo().name;
- prepareDisplaySettings(displayIdentifier);
-
- readAndAssertDisplaySettings(mPrimaryDisplay);
- }
-
- @Test
- public void testReadingDisplaySettingsFromStorage_LegacyDisplayId_UpdateAfterAccess()
- throws Exception {
- // Store display settings with legacy display identifier.
- final String displayIdentifier = mPrimaryDisplay.getDisplayInfo().name;
- prepareDisplaySettings(displayIdentifier);
-
- // Update settings with new value, should trigger write to injector.
- final DisplayWindowSettings settings = new DisplayWindowSettings(mWm, mStorage);
- settings.setRemoveContentModeLocked(mPrimaryDisplay, REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY);
- assertEquals("Settings value must be updated", REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY,
- settings.getRemoveContentModeLocked(mPrimaryDisplay));
- assertTrue(mStorage.wasWriteSuccessful());
-
- // Verify that display identifier was updated.
- final String newDisplayIdentifier = getStoredDisplayAttributeValue("name");
- assertEquals("Display identifier must be updated to use uniqueId",
- mPrimaryDisplay.getDisplayInfo().uniqueId, newDisplayIdentifier);
- }
-
- @Test
- public void testReadingDisplaySettingsFromStorage_UsePortAsId() {
- final DisplayAddress.Physical displayAddress =
- DisplayAddress.fromPortAndModel(DISPLAY_PORT, DISPLAY_MODEL);
- mPrimaryDisplay.getDisplayInfo().address = displayAddress;
-
- final String displayIdentifier = "port:" + DISPLAY_PORT;
- prepareDisplaySettings(displayIdentifier, true /* usePortAsId */);
-
- readAndAssertDisplaySettings(mPrimaryDisplay);
- }
-
- @Test
- public void testReadingDisplaySettingsFromStorage_UsePortAsId_IncorrectAddress() {
- final String displayIdentifier = mPrimaryDisplay.getDisplayInfo().uniqueId;
- prepareDisplaySettings(displayIdentifier, true /* usePortAsId */);
-
- mPrimaryDisplay.getDisplayInfo().address = DisplayAddress.fromPhysicalDisplayId(123456);
-
- // Verify that the entry is not matched and default settings are returned instead.
- final DisplayWindowSettings settings = new DisplayWindowSettings(mWm);
- assertNotEquals("Default setting must be returned for new entry",
- WINDOWING_MODE_PINNED, settings.getWindowingModeLocked(mPrimaryDisplay));
- }
-
- @Test
- public void testWritingDisplaySettingsToStorage() throws Exception {
- // Write some settings to storage.
- final DisplayWindowSettings settings = new DisplayWindowSettings(mWm, mStorage);
- settings.setShouldShowSystemDecorsLocked(mSecondaryDisplay, true);
- settings.setShouldShowImeLocked(mSecondaryDisplay, true);
- assertTrue(mStorage.wasWriteSuccessful());
-
- // Verify that settings were stored correctly.
- assertEquals("Attribute value must be stored", mSecondaryDisplay.getDisplayInfo().uniqueId,
- getStoredDisplayAttributeValue("name"));
- assertEquals("Attribute value must be stored", "true",
- getStoredDisplayAttributeValue("shouldShowSystemDecors"));
- assertEquals("Attribute value must be stored", "true",
- getStoredDisplayAttributeValue("shouldShowIme"));
- }
-
- @Test
- public void testWritingDisplaySettingsToStorage_UsePortAsId() throws Exception {
- // Store config to use port as identifier.
- final DisplayAddress.Physical displayAddress =
- DisplayAddress.fromPortAndModel(DISPLAY_PORT, DISPLAY_MODEL);
- mSecondaryDisplay.getDisplayInfo().address = displayAddress;
- prepareDisplaySettings(null /* displayIdentifier */, true /* usePortAsId */);
-
- // Write some settings.
- final DisplayWindowSettings settings = new DisplayWindowSettings(mWm, mStorage);
- settings.setShouldShowSystemDecorsLocked(mSecondaryDisplay, true);
- settings.setShouldShowImeLocked(mSecondaryDisplay, true);
- assertTrue(mStorage.wasWriteSuccessful());
-
- // Verify that settings were stored correctly.
- assertEquals("Attribute value must be stored", "port:" + DISPLAY_PORT,
- getStoredDisplayAttributeValue("name"));
- assertEquals("Attribute value must be stored", "true",
- getStoredDisplayAttributeValue("shouldShowSystemDecors"));
- assertEquals("Attribute value must be stored", "true",
- getStoredDisplayAttributeValue("shouldShowIme"));
- }
-
- @Test
public void testShouldShowImeWithinForceDesktopMode() {
try {
// Presume display enabled force desktop mode from developer options.
@@ -567,14 +420,13 @@
public void testDisplayWindowSettingsAppliedOnDisplayReady() {
// Set forced densities for two displays in DisplayWindowSettings
final DisplayContent dc = createMockSimulatedDisplay();
- final DisplayWindowSettings settings = new DisplayWindowSettings(mWm, mStorage);
- settings.setForcedDensity(mPrimaryDisplay, 123, 0 /* userId */);
- settings.setForcedDensity(dc, 456, 0 /* userId */);
+ mDisplayWindowSettings.setForcedDensity(mPrimaryDisplay, 123, 0 /* userId */);
+ mDisplayWindowSettings.setForcedDensity(dc, 456, 0 /* userId */);
// Apply settings to displays - the settings will be stored, but config will not be
// recalculated immediately.
- settings.applySettingsToDisplayLocked(mPrimaryDisplay);
- settings.applySettingsToDisplayLocked(dc);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(dc);
assertFalse(mPrimaryDisplay.mWaitingForConfig);
assertFalse(dc.mWaitingForConfig);
@@ -589,173 +441,34 @@
assertEquals(456, config.densityDpi);
}
- /**
- * Prepares display settings and stores in {@link #mStorage}. Uses provided display identifier
- * and stores windowingMode=WINDOWING_MODE_PINNED.
- */
- private void prepareDisplaySettings(String displayIdentifier) {
- prepareDisplaySettings(displayIdentifier, false /* usePortAsId */);
- }
+ public final class TestSettingsProvider implements DisplayWindowSettings.SettingsProvider {
+ Map<DisplayInfo, SettingsEntry> mOverrideSettingsCache = new HashMap<>();
- private void prepareDisplaySettings(String displayIdentifier, boolean usePortAsId) {
- String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
- + "<display-settings>\n";
- if (usePortAsId) {
- contents += " <config identifier=\"1\"/>\n";
- }
- if (displayIdentifier != null) {
- contents += " <display\n"
- + " name=\"" + displayIdentifier + "\"\n"
- + " windowingMode=\"" + WINDOWING_MODE_PINNED + "\"/>\n";
- }
- contents += "</display-settings>\n";
-
- final InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8));
- mStorage.setReadStream(is);
- }
-
- private void readAndAssertDisplaySettings(DisplayContent displayContent) {
- final DisplayWindowSettings settings = new DisplayWindowSettings(mWm, mStorage);
- assertEquals("Stored setting must be read",
- WINDOWING_MODE_PINNED, settings.getWindowingModeLocked(displayContent));
- assertEquals("Not stored setting must be set to default value",
- REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY,
- settings.getRemoveContentModeLocked(displayContent));
- }
-
- private String getStoredDisplayAttributeValue(String attr) throws Exception {
- try (InputStream stream = mStorage.openRead()) {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(stream, StandardCharsets.UTF_8.name());
- int type;
- while ((type = parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {
- // Do nothing.
- }
-
- if (type != XmlPullParser.START_TAG) {
- throw new IllegalStateException("no start tag found");
- }
-
- int outerDepth = parser.getDepth();
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals("display")) {
- return parser.getAttributeValue(null, attr);
- }
- }
- } finally {
- mStorage.closeRead();
- }
- return null;
- }
-
- /**
- * This method helps to ensure read and write persistent settings successfully because the
- * constructor of {@link DisplayWindowSettings} should read the persistent file from the given
- * path that also means the previous state must be written correctly.
- */
- private void applySettingsToDisplayByNewInstance(DisplayContent display) {
- // Assert that prior write completed successfully.
- assertTrue(mStorage.wasWriteSuccessful());
-
- // Read and apply settings.
- new DisplayWindowSettings(mWm, mStorage).applySettingsToDisplayLocked(display);
- }
-
- private static boolean deleteRecursively(File file) {
- boolean fullyDeleted = true;
- if (file.isFile()) {
- return file.delete();
- } else if (file.isDirectory()) {
- final File[] files = file.listFiles();
- for (File child : files) {
- fullyDeleted &= deleteRecursively(child);
- }
- fullyDeleted &= file.delete();
- }
- return fullyDeleted;
- }
-
- /** In-memory storage implementation. */
- public class TestStorage implements DisplayWindowSettings.SettingPersister {
- private InputStream mReadStream;
- private ByteArrayOutputStream mWriteStream;
-
- private boolean mWasSuccessful;
-
- /**
- * Returns input stream for reading. By default tries forward the output stream if previous
- * write was successful.
- * @see #closeRead()
- */
@Override
- public InputStream openRead() throws FileNotFoundException {
- if (mReadStream == null && mWasSuccessful) {
- mReadStream = new ByteArrayInputStream(mWriteStream.toByteArray());
- }
- if (mReadStream == null) {
- throw new FileNotFoundException();
- }
- if (mReadStream.markSupported()) {
- mReadStream.mark(Integer.MAX_VALUE);
- }
- return mReadStream;
- }
-
- /** Must be called after each {@link #openRead} to reset the position in the stream. */
- void closeRead() throws IOException {
- if (mReadStream == null) {
- throw new FileNotFoundException();
- }
- if (mReadStream.markSupported()) {
- mReadStream.reset();
- }
- mReadStream = null;
- }
-
- /**
- * Creates new or resets existing output stream for write. Automatically closes previous
- * read stream, since following reads should happen based on this new write.
- */
- @Override
- public OutputStream startWrite() throws IOException {
- if (mWriteStream == null) {
- mWriteStream = new ByteArrayOutputStream();
- } else {
- mWriteStream.reset();
- }
- if (mReadStream != null) {
- closeRead();
- }
- return mWriteStream;
+ public SettingsEntry getSettings(@NonNull DisplayInfo info) {
+ return getOverrideSettings(info);
}
@Override
- public void finishWrite(OutputStream os, boolean success) {
- mWasSuccessful = success;
- try {
- os.close();
- } catch (IOException e) {
- // This method can't throw IOException since the super implementation doesn't, so
- // we just wrap it in a RuntimeException so we end up crashing the test all the
- // same.
- throw new RuntimeException(e);
+ public SettingsEntry getOverrideSettings(@NonNull DisplayInfo info) {
+ SettingsEntry result = new SettingsEntry();
+ SettingsEntry overrideSettings = mOverrideSettingsCache.get(info);
+ if (overrideSettings != null) {
+ result.setTo(overrideSettings);
}
+ return result;
}
- /** Override the read stream of the injector. By default it uses current write stream. */
- private void setReadStream(InputStream is) {
- mReadStream = is;
- }
+ @Override
+ public void updateOverrideSettings(@NonNull DisplayInfo info,
+ @NonNull SettingsEntry settings) {
+ SettingsEntry overrideSettings = mOverrideSettingsCache.get(info);
+ if (overrideSettings == null) {
+ overrideSettings = new SettingsEntry();
+ mOverrideSettingsCache.put(info, overrideSettings);
+ }
- private boolean wasWriteSuccessful() {
- return mWasSuccessful;
+ overrideSettings.setTo(settings);
}
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 823aef0..5641fe2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -83,6 +83,8 @@
public class DragDropControllerTests extends WindowTestsBase {
private static final int TIMEOUT_MS = 3000;
private static final int TEST_UID = 12345;
+ private static final int TEST_PID = 67890;
+ private static final String TEST_PACKAGE = "com.test.package";
private TestDragDropController mTarget;
private WindowState mWindow;
@@ -118,7 +120,7 @@
* Creates a window state which can be used as a drop target.
*/
private WindowState createDropTargetWindow(String name, int ownerId) {
- final ActivityRecord activity = createTestActivityRecord(mDisplayContent);
+ final ActivityRecord activity = createNonAttachedActivityRecord(mDisplayContent);
final Task stack = createTaskStackOnDisplay(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent);
final Task task = createTaskInStack(stack, ownerId);
@@ -243,21 +245,16 @@
});
try {
session.validateAndResolveDragMimeTypeExtras(
- createClipDataForActivity(null, null), 0);
- fail("Expected failure without pending intent and user");
- } catch (IllegalArgumentException e) {
- // Expected failure
- }
- try {
- session.validateAndResolveDragMimeTypeExtras(
- createClipDataForActivity(mock(PendingIntent.class), null), 0);
+ createClipDataForActivity(mock(PendingIntent.class), null), TEST_UID, TEST_PID,
+ TEST_PACKAGE);
fail("Expected failure without user");
} catch (IllegalArgumentException e) {
// Expected failure
}
try {
session.validateAndResolveDragMimeTypeExtras(
- createClipDataForActivity(null, mock(UserHandle.class)), 0);
+ createClipDataForActivity(null, mock(UserHandle.class)), TEST_UID, TEST_PID,
+ TEST_PACKAGE);
fail("Expected failure without pending intent");
} catch (IllegalArgumentException e) {
// Expected failure
@@ -286,15 +283,48 @@
public void onAnimatorScaleChanged(float scale) {}
});
try {
- final ClipData clipData = new ClipData(
- new ClipDescription("drag", new String[] { MIMETYPE_APPLICATION_SHORTCUT }),
- new ClipData.Item(new Intent()));
-
- session.validateAndResolveDragMimeTypeExtras(clipData, TEST_UID);
+ session.validateAndResolveDragMimeTypeExtras(
+ createClipDataForShortcut(null, "test_shortcut_id", mock(UserHandle.class)),
+ TEST_UID, TEST_PID, TEST_PACKAGE);
+ fail("Expected failure without package name");
+ } catch (IllegalArgumentException e) {
+ // Expected failure
+ }
+ try {
+ session.validateAndResolveDragMimeTypeExtras(
+ createClipDataForShortcut("test_package", null, mock(UserHandle.class)),
+ TEST_UID, TEST_PID, TEST_PACKAGE);
fail("Expected failure without shortcut id");
} catch (IllegalArgumentException e) {
// Expected failure
}
+ try {
+ session.validateAndResolveDragMimeTypeExtras(
+ createClipDataForShortcut("test_package", "test_shortcut_id", null),
+ TEST_UID, TEST_PID, TEST_PACKAGE);
+ fail("Expected failure without package name");
+ } catch (IllegalArgumentException e) {
+ // Expected failure
+ }
+ }
+
+ private ClipData createClipDataForShortcut(String packageName, String shortcutId,
+ UserHandle user) {
+ final Intent data = new Intent();
+ if (packageName != null) {
+ data.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
+ }
+ if (shortcutId != null) {
+ data.putExtra(Intent.EXTRA_SHORTCUT_ID, shortcutId);
+ }
+ if (user != null) {
+ data.putExtra(Intent.EXTRA_USER, user);
+ }
+ final ClipData clipData = new ClipData(
+ new ClipDescription("drag", new String[] {
+ MIMETYPE_APPLICATION_SHORTCUT}),
+ new ClipData.Item(data));
+ return clipData;
}
@Test
@@ -308,7 +338,8 @@
new ClipDescription("drag", new String[] { MIMETYPE_APPLICATION_TASK }),
new ClipData.Item(new Intent()));
- session.validateAndResolveDragMimeTypeExtras(clipData, TEST_UID);
+ session.validateAndResolveDragMimeTypeExtras(clipData, TEST_UID, TEST_PID,
+ TEST_PACKAGE);
fail("Expected failure without task id");
} catch (IllegalArgumentException e) {
// Expected failure
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index a1606d3..02d9c42 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -82,7 +82,7 @@
addWindow(TYPE_STATUS_BAR, "statusBar");
addWindow(TYPE_NAVIGATION_BAR, "navBar");
- final WindowState win = createWindowOnStack(null, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
+ final WindowState win = createWindow(null, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
ACTIVITY_TYPE_STANDARD, TYPE_APPLICATION, mDisplayContent, "app");
final InsetsSourceControl[] controls = addWindowAndGetControlsForDispatch(win);
@@ -95,7 +95,7 @@
addWindow(TYPE_STATUS_BAR, "statusBar");
addWindow(TYPE_NAVIGATION_BAR, "navBar");
- final WindowState win = createWindowOnStack(null, WINDOWING_MODE_FREEFORM,
+ final WindowState win = createWindow(null, WINDOWING_MODE_FREEFORM,
ACTIVITY_TYPE_STANDARD, TYPE_APPLICATION, mDisplayContent, "app");
final InsetsSourceControl[] controls = addWindowAndGetControlsForDispatch(win);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
index 044f819..bf718a7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
@@ -50,6 +50,11 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_ALLOWLISTED;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_DONT_LOCK;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_PINNABLE;
import static com.android.server.wm.LockTaskController.STATUS_BAR_MASK_LOCKED;
import static com.android.server.wm.LockTaskController.STATUS_BAR_MASK_PINNED;
@@ -169,7 +174,7 @@
@Test
public void testStartLockTaskMode_once() throws Exception {
// GIVEN a task record with allowlisted auth
- Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
// WHEN calling setLockTaskMode for LOCKED mode without resuming
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
@@ -186,8 +191,8 @@
@Test
public void testStartLockTaskMode_twice() throws Exception {
// GIVEN two task records with allowlisted auth
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
- Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr2 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
// WHEN calling setLockTaskMode for LOCKED mode on both tasks
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
@@ -206,7 +211,7 @@
@Test
public void testStartLockTaskMode_pinningRequest() {
// GIVEN a task record that is not allowlisted, i.e. with pinned auth
- Task tr = getTask(Task.LOCK_TASK_AUTH_PINNABLE);
+ Task tr = getTask(LOCK_TASK_AUTH_PINNABLE);
// WHEN calling startLockTaskMode
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
@@ -218,7 +223,7 @@
@Test
public void testStartLockTaskMode_pinnedBySystem() throws Exception {
// GIVEN a task record with pinned auth
- Task tr = getTask(Task.LOCK_TASK_AUTH_PINNABLE);
+ Task tr = getTask(LOCK_TASK_AUTH_PINNABLE);
// WHEN the system calls startLockTaskMode
mLockTaskController.startLockTaskMode(tr, true, SYSTEM_UID);
@@ -237,41 +242,39 @@
@Test
public void testLockTaskViolation() {
// GIVEN one task record with allowlisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN it's not a lock task violation to try and launch this task without clearing
assertFalse(mLockTaskController.isLockTaskModeViolation(tr, false));
// THEN it's a lock task violation to launch another task that is not allowlisted
- assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(
- Task.LOCK_TASK_AUTH_PINNABLE)));
+ assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(LOCK_TASK_AUTH_PINNABLE)));
// THEN it's a lock task violation to launch another task that is disallowed from lock task
- assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(
- Task.LOCK_TASK_AUTH_DONT_LOCK)));
+ assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(LOCK_TASK_AUTH_DONT_LOCK)));
// THEN it's no a lock task violation to launch another task that is allowlisted
assertFalse(mLockTaskController.isLockTaskModeViolation(getTask(
- Task.LOCK_TASK_AUTH_ALLOWLISTED)));
+ LOCK_TASK_AUTH_ALLOWLISTED)));
assertFalse(mLockTaskController.isLockTaskModeViolation(getTask(
- Task.LOCK_TASK_AUTH_LAUNCHABLE)));
+ LOCK_TASK_AUTH_LAUNCHABLE)));
// THEN it's not a lock task violation to launch another task that is priv launchable
assertFalse(mLockTaskController.isLockTaskModeViolation(getTask(
- Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV)));
+ LOCK_TASK_AUTH_LAUNCHABLE_PRIV)));
}
@Test
public void testLockTaskViolation_emergencyCall() {
// GIVEN one task record with allowlisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// GIVEN tasks necessary for emergency calling
Task keypad = getTask(new Intent().setComponent(EMERGENCY_DIALER_COMPONENT),
- Task.LOCK_TASK_AUTH_PINNABLE);
+ LOCK_TASK_AUTH_PINNABLE);
Task callAction = getTask(new Intent(Intent.ACTION_CALL_EMERGENCY),
- Task.LOCK_TASK_AUTH_PINNABLE);
- Task dialer = getTask("com.example.dialer", Task.LOCK_TASK_AUTH_PINNABLE);
+ LOCK_TASK_AUTH_PINNABLE);
+ Task dialer = getTask("com.example.dialer", LOCK_TASK_AUTH_PINNABLE);
when(mTelecomManager.getSystemDialerPackage())
.thenReturn(dialer.intent.getComponent().getPackageName());
@@ -295,7 +298,7 @@
@Test
public void testStopLockTaskMode() throws Exception {
// GIVEN one task record with allowlisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN the same caller calls stopLockTaskMode
@@ -312,7 +315,7 @@
@Test(expected = SecurityException.class)
public void testStopLockTaskMode_differentCaller() {
// GIVEN one task record with allowlisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN a different caller calls stopLockTaskMode
@@ -324,7 +327,7 @@
@Test
public void testStopLockTaskMode_systemCaller() {
// GIVEN one task record with allowlisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN system calls stopLockTaskMode
@@ -337,8 +340,8 @@
@Test
public void testStopLockTaskMode_twoTasks() throws Exception {
// GIVEN two task records with allowlisted auth that is in lock task mode
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
- Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr2 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
@@ -358,8 +361,8 @@
@Test
public void testStopLockTaskMode_rootTask() throws Exception {
// GIVEN two task records with allowlisted auth that is in lock task mode
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
- Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr2 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
@@ -379,7 +382,7 @@
@Test
public void testStopLockTaskMode_pinned() throws Exception {
// GIVEN one task records that is in pinned mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_PINNABLE);
+ Task tr = getTask(LOCK_TASK_AUTH_PINNABLE);
mLockTaskController.startLockTaskMode(tr, true, SYSTEM_UID);
// GIVEN that the keyguard is required to show after unlocking
Settings.Secure.putInt(mContext.getContentResolver(),
@@ -406,8 +409,8 @@
@Test
public void testClearLockedTasks() throws Exception {
// GIVEN two task records with allowlisted auth that is in lock task mode
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
- Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr2 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
@@ -434,7 +437,7 @@
.thenReturn(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
// AND there is a task record
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -454,7 +457,7 @@
.thenReturn(true);
// AND there is a task record
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -471,7 +474,7 @@
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, 1, mContext.getUserId());
// AND there is a task record
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -488,7 +491,7 @@
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, 0, mContext.getUserId());
// AND there is a task record
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -574,7 +577,7 @@
@Test
public void testUpdateLockTaskFeatures() throws Exception {
// GIVEN a locked task
- Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN lock task mode should be started with default status bar masks
@@ -616,7 +619,7 @@
@Test
public void testUpdateLockTaskFeatures_differentUser() throws Exception {
// GIVEN a locked task
- Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN lock task mode should be started with default status bar masks
@@ -638,7 +641,7 @@
@Test
public void testUpdateLockTaskFeatures_keyguard() {
// GIVEN a locked task
- Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN keyguard should be disabled
@@ -704,7 +707,7 @@
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT));
// Start lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK is not enabled
@@ -758,14 +761,13 @@
* @param isAppAware {@code true} if the app has marked if allowlisted in its manifest
*/
private Task getTaskForUpdate(String pkg, boolean isAppAware) {
- final int authIfAllowlisted = isAppAware
- ? Task.LOCK_TASK_AUTH_LAUNCHABLE
- : Task.LOCK_TASK_AUTH_ALLOWLISTED;
+ final int authIfAllowlisted =
+ isAppAware ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_ALLOWLISTED;
Task tr = getTask(pkg, authIfAllowlisted);
doAnswer((invocation) -> {
boolean isAllowlisted =
mLockTaskController.isPackageAllowlisted(TEST_USER_ID, pkg);
- tr.mLockTaskAuth = isAllowlisted ? authIfAllowlisted : Task.LOCK_TASK_AUTH_PINNABLE;
+ tr.mLockTaskAuth = isAllowlisted ? authIfAllowlisted : LOCK_TASK_AUTH_PINNABLE;
return null;
}).when(tr).setLockTaskAuth();
return tr;
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index bea0d8e..d348389 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -474,6 +474,28 @@
}
@Test
+ public void testAppendOrganizedChildTaskInfo() {
+ final Task root = createTaskBuilder(".CreatedByOrganizerRoot").build();
+ root.mCreatedByOrganizer = true;
+ // Add organized and non-organized child.
+ final Task child1 = createTaskBuilder(".Task1").setParentTask(root).build();
+ final Task child2 = createTaskBuilder(".Task2").setParentTask(root).build();
+ doReturn(true).when(child1).isOrganized();
+ doReturn(false).when(child2).isOrganized();
+ mRecentTasks.add(root);
+
+ doNothing().when(mRecentTasks).loadUserRecentsLocked(anyInt());
+ doReturn(true).when(mRecentTasks).isUserRunning(anyInt(), anyInt());
+ final List<RecentTaskInfo> infos = mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */,
+ true /* getTasksAllowed */, TEST_USER_0_ID, 0 /* callingUid */).getList();
+
+ // Make sure only organized child will be appended.
+ final List<RecentTaskInfo> childrenTaskInfos = infos.get(0).childrenTaskInfos;
+ assertEquals(childrenTaskInfos.size(), 1);
+ assertEquals(childrenTaskInfos.get(0).taskId, child1.mTaskId);
+ }
+
+ @Test
public void testAddTasksHomeClearUntrackedTasks_expectFinish() {
// There may be multiple tasks with the same base intent by flags (FLAG_ACTIVITY_NEW_TASK |
// FLAG_ACTIVITY_MULTIPLE_TASK). If the previous task is still active, it should be removed
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 8094c97..cc92ddd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -16,8 +16,6 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -107,8 +105,7 @@
@Test
public void testRemovedBeforeStarted_expectCanceled() throws Exception {
- final ActivityRecord activity = createActivityRecord(mDefaultDisplay,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
AnimationAdapter adapter = mController.addAnimation(activity.getTask(),
false /* isRecentTaskInvisible */);
adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_RECENTS,
@@ -127,8 +124,7 @@
@Test
public void testCancelAfterRemove_expectIgnored() {
- final ActivityRecord activity = createActivityRecord(mDefaultDisplay,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
AnimationAdapter adapter = mController.addAnimation(activity.getTask(),
false /* isRecentTaskInvisible */);
adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_RECENTS,
@@ -149,10 +145,8 @@
public void testIncludedApps_expectTargetAndVisible() {
mWm.setRecentsAnimationController(mController);
final ActivityRecord homeActivity = createHomeActivity();
- final ActivityRecord activity = createActivityRecord(mDefaultDisplay,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
- final ActivityRecord hiddenActivity = createActivityRecord(mDefaultDisplay,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
+ final ActivityRecord hiddenActivity = createActivityRecord(mDefaultDisplay);
hiddenActivity.setVisible(false);
mDefaultDisplay.getConfiguration().windowConfiguration.setRotation(
mDefaultDisplay.getRotation());
@@ -168,8 +162,7 @@
public void testWallpaperIncluded_expectTarget() throws Exception {
mWm.setRecentsAnimationController(mController);
final ActivityRecord homeActivity = createHomeActivity();
- final ActivityRecord activity = createActivityRecord(mDefaultDisplay,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "win1");
activity.addWindow(win1);
final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
@@ -191,8 +184,7 @@
public void testWallpaperAnimatorCanceled_expectAnimationKeepsRunning() throws Exception {
mWm.setRecentsAnimationController(mController);
final ActivityRecord homeActivity = createHomeActivity();
- final ActivityRecord activity = createActivityRecord(mDefaultDisplay,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "win1");
activity.addWindow(win1);
final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
@@ -218,8 +210,7 @@
final ActivityRecord homeActivity = createHomeActivity();
final WindowState hwin1 = createWindow(null, TYPE_BASE_APPLICATION, homeActivity, "hwin1");
homeActivity.addWindow(hwin1);
- final ActivityRecord activity = createActivityRecord(mDefaultDisplay,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "win1");
activity.addWindow(win1);
final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
@@ -246,8 +237,7 @@
@Test
public void testDeferCancelAnimation() throws Exception {
mWm.setRecentsAnimationController(mController);
- final ActivityRecord activity = createActivityRecord(mDefaultDisplay,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "win1");
activity.addWindow(win1);
assertEquals(activity.getTask().getTopVisibleActivity(), activity);
@@ -269,8 +259,7 @@
@Test
public void testDeferCancelAnimationWithScreenShot() throws Exception {
mWm.setRecentsAnimationController(mController);
- final ActivityRecord activity = createActivityRecord(mDefaultDisplay,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "win1");
activity.addWindow(win1);
assertEquals(activity.getTask().getTopVisibleActivity(), activity);
@@ -301,8 +290,7 @@
@Test
public void testShouldAnimateWhenNoCancelWithDeferredScreenshot() {
mWm.setRecentsAnimationController(mController);
- final ActivityRecord activity = createActivityRecord(mDefaultDisplay,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "win1");
activity.addWindow(win1);
assertEquals(activity.getTask().getTopVisibleActivity(), activity);
@@ -325,8 +313,7 @@
final ActivityRecord homeActivity = createHomeActivity();
homeActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- final ActivityRecord landActivity = createActivityRecord(mDefaultDisplay,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final ActivityRecord landActivity = createActivityRecord(mDefaultDisplay);
landActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, landActivity, "win1");
landActivity.addWindow(win1);
@@ -365,8 +352,7 @@
private ActivityRecord prepareFixedRotationLaunchingAppWithRecentsAnim() {
final ActivityRecord homeActivity = createHomeActivity();
homeActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- final ActivityRecord activity = createActivityRecord(mDefaultDisplay,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
// Add a window so it can be animated by the recents.
final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win");
activity.addWindow(win);
@@ -441,8 +427,7 @@
homeWindow.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
// Landscape application
- final ActivityRecord activity = createActivityRecord(mDefaultDisplay,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
final WindowState applicationWindow = createWindow(null, TYPE_BASE_APPLICATION, activity,
"applicationWindow");
activity.addWindow(applicationWindow);
@@ -513,7 +498,7 @@
private ActivityRecord createHomeActivity() {
final ActivityRecord homeActivity = new ActivityBuilder(mWm.mAtmService)
- .setStack(mRootHomeTask)
+ .setParentTask(mRootHomeTask)
.setCreateTask(true)
.build();
// Avoid {@link RecentsAnimationController.TaskAnimationAdapter#createRemoteAnimationTarget}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index c10d4fa..137cedd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -93,8 +93,7 @@
ACTIVITY_TYPE_RECENTS, true /* onTop */);
ActivityRecord recentActivity = new ActivityBuilder(mAtm)
.setComponent(mRecentsComponent)
- .setCreateTask(true)
- .setStack(recentsStack)
+ .setTask(recentsStack)
.build();
ActivityRecord topActivity = new ActivityBuilder(mAtm).setCreateTask(true).build();
topActivity.getRootTask().moveToFront("testRecentsActivityVisiblility");
@@ -124,7 +123,7 @@
ActivityRecord topRunningHomeActivity = homeStack.topRunningActivity();
if (topRunningHomeActivity == null) {
topRunningHomeActivity = new ActivityBuilder(mAtm)
- .setStack(homeStack)
+ .setParentTask(homeStack)
.setCreateTask(true)
.build();
}
@@ -182,7 +181,7 @@
Task recentsStack = defaultTaskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_RECENTS, true /* onTop */);
ActivityRecord recentActivity = new ActivityBuilder(mAtm).setComponent(
- mRecentsComponent).setCreateTask(true).setStack(recentsStack).build();
+ mRecentsComponent).setCreateTask(true).setParentTask(recentsStack).build();
WindowProcessController app = recentActivity.app;
recentActivity.app = null;
@@ -214,7 +213,7 @@
if (targetActivity == null) {
targetActivity = new ActivityBuilder(mAtm)
.setCreateTask(true)
- .setStack(homeStack)
+ .setParentTask(homeStack)
.build();
}
@@ -222,7 +221,7 @@
ActivityRecord anotherHomeActivity = new ActivityBuilder(mAtm)
.setComponent(new ComponentName(mContext.getPackageName(), "Home2"))
.setCreateTask(true)
- .setStack(homeStack)
+ .setParentTask(homeStack)
.build();
// Start an activity on top so the recents activity can be started.
new ActivityBuilder(mAtm)
@@ -255,21 +254,21 @@
new ActivityBuilder(mAtm)
.setComponent(new ComponentName(mContext.getPackageName(), "App1"))
.setCreateTask(true)
- .setStack(fullscreenStack)
+ .setParentTask(fullscreenStack)
.build();
Task recentsStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_RECENTS, true /* onTop */);
new ActivityBuilder(mAtm)
.setComponent(mRecentsComponent)
.setCreateTask(true)
- .setStack(recentsStack)
+ .setParentTask(recentsStack)
.build();
Task fullscreenStack2 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
new ActivityBuilder(mAtm)
.setComponent(new ComponentName(mContext.getPackageName(), "App2"))
.setCreateTask(true)
- .setStack(fullscreenStack2)
+ .setParentTask(fullscreenStack2)
.build();
// Start the recents animation
@@ -296,21 +295,21 @@
new ActivityBuilder(mAtm)
.setComponent(new ComponentName(mContext.getPackageName(), "App1"))
.setCreateTask(true)
- .setStack(fullscreenStack)
+ .setParentTask(fullscreenStack)
.build();
Task recentsStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_RECENTS, true /* onTop */);
new ActivityBuilder(mAtm)
.setComponent(mRecentsComponent)
.setCreateTask(true)
- .setStack(recentsStack)
+ .setParentTask(recentsStack)
.build();
Task fullscreenStack2 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
new ActivityBuilder(mAtm)
.setComponent(new ComponentName(mContext.getPackageName(), "App2"))
.setCreateTask(true)
- .setStack(fullscreenStack2)
+ .setParentTask(fullscreenStack2)
.build();
// Start the recents animation
@@ -331,7 +330,7 @@
Task homeStack = taskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED,
ACTIVITY_TYPE_HOME);
ActivityRecord otherUserHomeActivity = new ActivityBuilder(mAtm)
- .setStack(homeStack)
+ .setParentTask(homeStack)
.setCreateTask(true)
.setComponent(new ComponentName(mContext.getPackageName(), "Home2"))
.build();
@@ -342,7 +341,7 @@
new ActivityBuilder(mAtm)
.setComponent(new ComponentName(mContext.getPackageName(), "App1"))
.setCreateTask(true)
- .setStack(fullscreenStack)
+ .setParentTask(fullscreenStack)
.build();
doReturn(TEST_USER_ID).when(mAtm).getCurrentUserId();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 901ed36..4b8bbc1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -38,7 +38,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
-import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
+import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE;
import static com.android.server.wm.Task.ActivityState.STOPPED;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
@@ -107,7 +107,7 @@
public void testRestoringInvalidTask() {
mRootWindowContainer.getDefaultDisplay().removeAllTasks();
Task task = mRootWindowContainer.anyTaskForId(0 /*taskId*/,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, null, false /* onTop */);
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, null, false /* onTop */);
assertNull(task);
}
@@ -117,12 +117,10 @@
*/
@Test
public void testReplacingTaskInPinnedStack() {
- final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true)
- .setStack(mFullscreenStack).build();
- final Task task = firstActivity.getTask();
-
- final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(task)
- .setStack(mFullscreenStack).build();
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
+ .setTask(mFullscreenStack).build();
+ final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
+ .setTask(mFullscreenStack).build();
mFullscreenStack.moveToFront("testReplacingTaskInPinnedStack");
@@ -152,12 +150,12 @@
@Test
public void testMovingBottomMostStackActivityToPinnedStack() {
- final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true)
- .setStack(mFullscreenStack).build();
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
+ .setTask(mFullscreenStack).build();
final Task task = firstActivity.getTask();
- final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(task)
- .setStack(mFullscreenStack).build();
+ final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
+ .setTask(mFullscreenStack).build();
mFullscreenStack.moveTaskToBack(task);
@@ -287,8 +285,7 @@
final int originalStackCount = defaultTaskDisplayArea.getStackCount();
final Task stack = defaultTaskDisplayArea.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true)
- .setStack(stack).build();
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(stack).build();
assertEquals(originalStackCount + 1, defaultTaskDisplayArea.getStackCount());
@@ -311,17 +308,15 @@
final int originalStackCount = defaultTaskDisplayArea.getStackCount();
final Task stack = defaultTaskDisplayArea.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true)
- .setStack(stack).build();
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(stack).build();
assertEquals(originalStackCount + 1, defaultTaskDisplayArea.getStackCount());
final DisplayContent dc = defaultTaskDisplayArea.getDisplayContent();
- final TaskDisplayArea secondTaskDisplayArea = WindowTestsBase.createTaskDisplayArea(
+ final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea(
dc, mRootWindowContainer.mWmService, "TestTaskDisplayArea", FEATURE_VENDOR_FIRST);
final Task secondStack = secondTaskDisplayArea.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- new ActivityBuilder(mAtm).setCreateTask(true).setStack(secondStack)
- .setUseProcess(firstActivity.app).build();
+ new ActivityBuilder(mAtm).setTask(secondStack).setUseProcess(firstActivity.app).build();
assertEquals(1, secondTaskDisplayArea.getStackCount());
// Let's pretend that the app has crashed.
@@ -339,8 +334,7 @@
.getDefaultTaskDisplayArea();
final Task stack = defaultTaskDisplayArea.createStack(
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true)
- .setStack(stack).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(stack).build();
// Created stacks are focusable by default.
assertTrue(stack.isTopActivityFocusable());
@@ -353,8 +347,8 @@
final Task pinnedStack = defaultTaskDisplayArea.createStack(
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm).setCreateTask(true)
- .setStack(pinnedStack).build();
+ final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm)
+ .setTask(pinnedStack).build();
// We should not be focusable when in pinned mode
assertFalse(pinnedStack.isTopActivityFocusable());
@@ -363,13 +357,9 @@
// Add flag forcing focusability.
pinnedActivity.info.flags |= FLAG_ALWAYS_FOCUSABLE;
- // We should not be focusable when in pinned mode
+ // Task with FLAG_ALWAYS_FOCUSABLE should be focusable.
assertTrue(pinnedStack.isTopActivityFocusable());
assertTrue(pinnedActivity.isFocusable());
-
- // Without the overridding activity, stack should not be focusable.
- pinnedStack.removeChild(pinnedActivity.getTask(), "testFocusability");
- assertFalse(pinnedStack.isTopActivityFocusable());
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index cc8b2a1..62aa02f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -16,8 +16,6 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
@@ -152,8 +150,7 @@
DisplayContent displayContent = mWm.mRoot.getDisplayContent(DEFAULT_DISPLAY);
TaskDisplayArea taskDisplayArea = displayContent.getDefaultTaskDisplayArea();
Task stack = taskDisplayArea.getStackAt(0);
- ActivityRecord activity = createActivityRecord(displayContent,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ ActivityRecord activity = createActivityRecord(displayContent);
stack.mPausingActivity = activity;
activity.setState(PAUSING, "test PAUSING");
@@ -176,7 +173,7 @@
public void testTaskLayerRank() {
final Task rootTask = new TaskBuilder(mSupervisor).build();
final Task task1 = new TaskBuilder(mSupervisor).setParentTask(rootTask).build();
- new ActivityBuilder(mAtm).setStack(task1).build().mVisibleRequested = true;
+ new ActivityBuilder(mAtm).setTask(task1).build().mVisibleRequested = true;
// RootWindowContainer#invalidateTaskLayers should post to update.
waitHandlerIdle(mWm.mH);
@@ -185,7 +182,7 @@
assertEquals(Task.LAYER_RANK_INVISIBLE, rootTask.mLayerRank);
final Task task2 = new TaskBuilder(mSupervisor).build();
- new ActivityBuilder(mAtm).setStack(task2).build().mVisibleRequested = true;
+ new ActivityBuilder(mAtm).setTask(task2).build().mVisibleRequested = true;
waitHandlerIdle(mWm.mH);
// Note that ensureActivitiesVisible is disabled in SystemServicesTestRule, so both the
@@ -208,8 +205,8 @@
final WindowProcessController wpc = activity.app;
final ActivityRecord[] activities = {
activity,
- new ActivityBuilder(mWm.mAtmService).setStack(task).setUseProcess(wpc).build(),
- new ActivityBuilder(mWm.mAtmService).setStack(task).setUseProcess(wpc).build()
+ new ActivityBuilder(mWm.mAtmService).setTask(task).setUseProcess(wpc).build(),
+ new ActivityBuilder(mWm.mAtmService).setTask(task).setUseProcess(wpc).build()
};
activities[0].detachFromProcess();
activities[1].finishing = true;
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index d68dde5..4300971 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -768,7 +768,7 @@
params.setFitInsetsTypes(0);
final TestWindowState w = new TestWindowState(
activity.mWmService, mock(Session.class), new TestIWindow(), params, activity);
- WindowTestsBase.makeWindowVisible(w);
+ makeWindowVisible(w);
w.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
activity.addWindow(w);
return w;
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 6f5389d..740f605 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -296,6 +296,7 @@
// Called when moving activity to pinned stack.
doNothing().when(mWmService.mRoot).ensureActivitiesVisible(any(),
anyInt(), anyBoolean(), anyBoolean());
+ spyOn(mWmService.mDisplayWindowSettings);
// Setup factory classes to prevent calls to native code.
mTransaction = spy(StubTransaction.class);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
index 8b025e3..4bd8edd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
@@ -79,7 +79,7 @@
// Stack should contain visible app window to be considered visible.
final Task pinnedTask = createTaskInStack(mPinnedStack, 0 /* userId */);
assertFalse(mPinnedStack.isVisible());
- final ActivityRecord pinnedApp = createTestActivityRecord(mDisplayContent);
+ final ActivityRecord pinnedApp = createNonAttachedActivityRecord(mDisplayContent);
pinnedTask.addChild(pinnedApp, 0 /* addPos */);
assertTrue(mPinnedStack.isVisible());
}
@@ -94,7 +94,7 @@
final Task stack = createTaskStackOnDisplay(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent);
final Task task = createTaskInStack(stack, 0 /* userId */);
- final ActivityRecord activity = createTestActivityRecord(mDisplayContent);
+ final ActivityRecord activity = createNonAttachedActivityRecord(mDisplayContent);
task.addChild(activity, 0 /* addPos */);
final TaskDisplayArea taskDisplayArea = activity.getDisplayArea();
activity.mNeedsAnimationBoundsLayer = true;
@@ -236,7 +236,7 @@
ActivityRecord homeActivity = rootHomeTask.getTopNonFinishingActivity();
if (homeActivity == null) {
homeActivity = new ActivityBuilder(mWm.mAtmService)
- .setStack(rootHomeTask).setCreateTask(true).build();
+ .setParentTask(rootHomeTask).setCreateTask(true).build();
}
homeActivity.setVisible(false);
homeActivity.mVisibleRequested = true;
@@ -255,10 +255,10 @@
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
final Task secondStack = secondTaskDisplayArea.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true)
- .setStack(firstStack).build();
- final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setCreateTask(true)
- .setStack(secondStack).build();
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
+ .setTask(firstStack).build();
+ final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
+ .setTask(secondStack).build();
// Activity on TDA1 is focused
mDisplayContent.setFocusedApp(firstActivity);
@@ -284,8 +284,7 @@
final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
final Task stack = taskDisplayArea.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true)
- .setStack(stack).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(stack).build();
mDisplayContent.setFocusedApp(activity);
activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
@@ -297,6 +296,37 @@
assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSET);
}
+ @Test
+ @UseTestDisplay
+ public void testRemove_reparentToDefault() {
+ final Task task = createTaskStackOnDisplay(mDisplayContent);
+ final TaskDisplayArea displayArea = task.getDisplayArea();
+ displayArea.remove();
+ assertTrue(displayArea.isRemoved());
+ assertFalse(displayArea.hasChild());
+
+ final RootWindowContainer rootWindowContainer = mWm.mAtmService.mRootWindowContainer;
+ final TaskDisplayArea defaultTaskDisplayArea =
+ rootWindowContainer.getDefaultTaskDisplayArea();
+ assertTrue(defaultTaskDisplayArea.mChildren.contains(task));
+ }
+
+ @Test
+ @UseTestDisplay
+ public void testRemove_stackCreatedByOrganizer() {
+ final Task task = createTaskStackOnDisplay(mDisplayContent);
+ task.mCreatedByOrganizer = true;
+ final TaskDisplayArea displayArea = task.getDisplayArea();
+ displayArea.remove();
+ assertTrue(displayArea.isRemoved());
+ assertFalse(displayArea.hasChild());
+
+ final RootWindowContainer rootWindowContainer = mWm.mAtmService.mRootWindowContainer;
+ final TaskDisplayArea defaultTaskDisplayArea =
+ rootWindowContainer.getDefaultTaskDisplayArea();
+ assertFalse(defaultTaskDisplayArea.mChildren.contains(task));
+ }
+
private void assertGetOrCreateStack(int windowingMode, int activityType, Task candidateTask,
boolean reuseCandidate) {
final TaskDisplayArea taskDisplayArea = candidateTask.getDisplayArea();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 1d32e17..a1097d2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -1351,7 +1351,7 @@
private ActivityRecord createSourceActivity(TestDisplayContent display) {
final Task stack = display.getDefaultTaskDisplayArea()
.createStack(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true);
- return new ActivityBuilder(mAtm).setStack(stack).setCreateTask(true).build();
+ return new ActivityBuilder(mAtm).setTask(stack).build();
}
private void addFreeformTaskTo(TestDisplayContent display, Rect bounds) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
index 27cae2f..7abe369 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
@@ -76,11 +76,8 @@
mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, dm);
removeGlobalMinSizeRestriction();
- final Task stack = createTaskStackOnDisplay(mDisplayContent);
- final ActivityRecord activity = new ActivityBuilder(stack.mAtmService)
- .setStack(stack)
- // In real case, there is no additional level for freeform mode.
- .setCreateTask(false)
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
+ .setCreateTask(true)
.build();
final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "window");
mPositioner = new TaskPositioner(mWm);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 2fa7589..f7e68ce 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -269,7 +269,8 @@
assertEquals(fullScreenBounds.height(), task.getBounds().height());
// Top activity gets used
- final ActivityRecord top = new ActivityBuilder(mAtm).setTask(task).setStack(stack).build();
+ final ActivityRecord top = new ActivityBuilder(mAtm).setTask(task).setParentTask(stack)
+ .build();
assertEquals(top, task.getTopNonFinishingActivity());
top.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height());
@@ -1001,7 +1002,8 @@
@Test
public void testNotSpecifyOrientationByFloatingTask() {
- final Task task = getTestTask();
+ final Task task = new TaskBuilder(mSupervisor)
+ .setCreateActivity(true).setCreateParentTask(true).build();
final ActivityRecord activity = task.getTopMostActivity();
final WindowContainer<?> parentContainer = task.getParent();
final TaskDisplayArea taskDisplayArea = task.getDisplayArea();
@@ -1027,10 +1029,10 @@
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
final Task secondStack = secondTaskDisplayArea.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true)
- .setStack(firstStack).build();
- final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setCreateTask(true)
- .setStack(secondStack).build();
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
+ .setTask(firstStack).build();
+ final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
+ .setTask(secondStack).build();
firstActivity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
secondActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
index 7cf30c0..4041412 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
@@ -85,12 +85,12 @@
public void testClosingAppDifferentStackOrientation() {
final Task stack = createTaskStackOnDisplay(mDisplayContent);
final Task task1 = createTaskInStack(stack, 0 /* userId */);
- ActivityRecord activity1 = createTestActivityRecord(mDisplayContent);
+ ActivityRecord activity1 = createNonAttachedActivityRecord(mDisplayContent);
task1.addChild(activity1, 0);
activity1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
final Task task2 = createTaskInStack(stack, 1 /* userId */);
- ActivityRecord activity2 = createTestActivityRecord(mDisplayContent);
+ ActivityRecord activity2 = createNonAttachedActivityRecord(mDisplayContent);
task2.addChild(activity2, 0);
activity2.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
@@ -103,12 +103,12 @@
public void testMoveTaskToBackDifferentStackOrientation() {
final Task stack = createTaskStackOnDisplay(mDisplayContent);
final Task task1 = createTaskInStack(stack, 0 /* userId */);
- ActivityRecord activity1 = createTestActivityRecord(mDisplayContent);
+ ActivityRecord activity1 = createNonAttachedActivityRecord(mDisplayContent);
task1.addChild(activity1, 0);
activity1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
final Task task2 = createTaskInStack(stack, 1 /* userId */);
- ActivityRecord activity2 = createTestActivityRecord(mDisplayContent);
+ ActivityRecord activity2 = createNonAttachedActivityRecord(mDisplayContent);
task2.addChild(activity2, 0);
activity2.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
assertEquals(SCREEN_ORIENTATION_PORTRAIT, stack.getOrientation());
@@ -217,7 +217,7 @@
public void testActivityAndTaskGetsProperType() {
final Task stack = createTaskStackOnDisplay(mDisplayContent);
final Task task1 = createTaskInStack(stack, 0 /* userId */);
- ActivityRecord activity1 = createTestActivityRecord(mDisplayContent);
+ ActivityRecord activity1 = createNonAttachedActivityRecord(mDisplayContent);
// First activity should become standard
task1.addChild(activity1, 0);
@@ -225,7 +225,7 @@
assertEquals(WindowConfiguration.ACTIVITY_TYPE_STANDARD, task1.getActivityType());
// Second activity should also become standard
- ActivityRecord activity2 = createTestActivityRecord(mDisplayContent);
+ ActivityRecord activity2 = createNonAttachedActivityRecord(mDisplayContent);
task1.addChild(activity2, WindowContainer.POSITION_TOP);
assertEquals(WindowConfiguration.ACTIVITY_TYPE_STANDARD, activity2.getActivityType());
assertEquals(WindowConfiguration.ACTIVITY_TYPE_STANDARD, task1.getActivityType());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index b6b3d66..0b257ee 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -63,7 +63,7 @@
public void testRemoveContainer() {
final Task stackController1 = createTaskStackOnDisplay(mDisplayContent);
final Task task = createTaskInStack(stackController1, 0 /* userId */);
- final ActivityRecord activity = createActivityRecordInTask(mDisplayContent, task);
+ final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
task.removeIfPossible();
// Assert that the container was removed.
@@ -76,7 +76,7 @@
public void testRemoveContainer_deferRemoval() {
final Task stackController1 = createTaskStackOnDisplay(mDisplayContent);
final Task task = createTaskInStack(stackController1, 0 /* userId */);
- final ActivityRecord activity = createActivityRecordInTask(mDisplayContent, task);
+ final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
doReturn(true).when(task).shouldDeferRemoval();
@@ -158,8 +158,8 @@
public void testIsInStack() {
final Task task1 = createTaskStackOnDisplay(mDisplayContent);
final Task task2 = createTaskStackOnDisplay(mDisplayContent);
- final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task1);
- final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task2);
+ final ActivityRecord activity1 = createActivityRecord(mDisplayContent, task1);
+ final ActivityRecord activity2 = createActivityRecord(mDisplayContent, task2);
assertEquals(activity1, task1.isInTask(activity1));
assertNull(task1.isInTask(activity2));
}
@@ -168,9 +168,9 @@
public void testRemoveChildForOverlayTask() {
final Task task = createTaskStackOnDisplay(mDisplayContent);
final int taskId = task.mTaskId;
- final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task);
- final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task);
- final ActivityRecord activity3 = createActivityRecordInTask(mDisplayContent, task);
+ final ActivityRecord activity1 = createActivityRecord(mDisplayContent, task);
+ final ActivityRecord activity2 = createActivityRecord(mDisplayContent, task);
+ final ActivityRecord activity3 = createActivityRecord(mDisplayContent, task);
activity1.setTaskOverlay(true);
activity2.setTaskOverlay(true);
activity3.setTaskOverlay(true);
@@ -207,8 +207,8 @@
final Task rootTask = createTaskStackOnDisplay(mDisplayContent);
final Task leafTask1 = createTaskInStack(rootTask, 0 /* userId */);
final Task leafTask2 = createTaskInStack(rootTask, 0 /* userId */);
- final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, leafTask1);
- final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, leafTask2);
+ final ActivityRecord activity1 = createActivityRecord(mDisplayContent, leafTask1);
+ final ActivityRecord activity2 = createActivityRecord(mDisplayContent, leafTask2);
// Check visibility of occluded tasks
doReturn(false).when(leafTask1).shouldBeVisible(any());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index feb509c..ef56c13 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -51,8 +51,8 @@
ACTIVITY_TYPE_STANDARD, mDisplayContent);
newTask.setHasBeenVisible(true);
oldTask.setHasBeenVisible(false);
- final ActivityRecord closing = createActivityRecordInTask(oldTask);
- final ActivityRecord opening = createActivityRecordInTask(newTask);
+ final ActivityRecord closing = createActivityRecord(oldTask);
+ final ActivityRecord opening = createActivityRecord(newTask);
closing.setVisible(true);
closing.mVisibleRequested = false;
opening.setVisible(false);
@@ -102,9 +102,9 @@
ACTIVITY_TYPE_STANDARD, mDisplayContent);
newTask.setHasBeenVisible(true);
oldTask.setHasBeenVisible(false);
- final ActivityRecord closing = createActivityRecordInTask(oldTask);
- final ActivityRecord opening = createActivityRecordInTask(newNestedTask);
- final ActivityRecord opening2 = createActivityRecordInTask(newNestedTask2);
+ final ActivityRecord closing = createActivityRecord(oldTask);
+ final ActivityRecord opening = createActivityRecord(newNestedTask);
+ final ActivityRecord opening2 = createActivityRecord(newNestedTask2);
closing.setVisible(true);
closing.mVisibleRequested = false;
opening.setVisible(false);
@@ -144,8 +144,8 @@
final DisplayArea tda = showTask.getDisplayArea();
showTask.setHasBeenVisible(true);
showTask2.setHasBeenVisible(true);
- final ActivityRecord showing = createActivityRecordInTask(showNestedTask);
- final ActivityRecord showing2 = createActivityRecordInTask(showTask2);
+ final ActivityRecord showing = createActivityRecord(showNestedTask);
+ final ActivityRecord showing2 = createActivityRecord(showTask2);
showing.setVisible(false);
showing.mVisibleRequested = true;
showing2.setVisible(false);
diff --git a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
index 78dfd40..45e1141 100644
--- a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
@@ -44,7 +44,7 @@
@Test
public void testFlow() {
- final ActivityRecord activity = createTestActivityRecord(mDisplayContent);
+ final ActivityRecord activity = createNonAttachedActivityRecord(mDisplayContent);
mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity);
mDisplayContent.mUnknownAppVisibilityController.notifyAppResumedFinished(activity);
mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(activity);
@@ -56,7 +56,7 @@
@Test
public void testSkipResume() {
- final ActivityRecord activity = createTestActivityRecord(mDisplayContent);
+ final ActivityRecord activity = createNonAttachedActivityRecord(mDisplayContent);
activity.mLaunchTaskBehind = true;
mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity);
mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(activity);
@@ -68,8 +68,8 @@
@Test
public void testMultiple() {
- final ActivityRecord activity1 = createTestActivityRecord(mDisplayContent);
- final ActivityRecord activity2 = createTestActivityRecord(mDisplayContent);
+ final ActivityRecord activity1 = createNonAttachedActivityRecord(mDisplayContent);
+ final ActivityRecord activity2 = createNonAttachedActivityRecord(mDisplayContent);
mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity1);
mDisplayContent.mUnknownAppVisibilityController.notifyAppResumedFinished(activity1);
mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity2);
@@ -84,7 +84,7 @@
@Test
public void testClear() {
- final ActivityRecord activity = createTestActivityRecord(mDisplayContent);
+ final ActivityRecord activity = createNonAttachedActivityRecord(mDisplayContent);
mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity);
mDisplayContent.mUnknownAppVisibilityController.clear();
assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
@@ -92,7 +92,7 @@
@Test
public void testRemoveFinishingInvisibleActivityFromUnknown() {
- final ActivityRecord activity = createTestActivityRecord(mDisplayContent);
+ final ActivityRecord activity = createNonAttachedActivityRecord(mDisplayContent);
mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity);
activity.finishing = true;
activity.mVisibleRequested = true;
@@ -102,7 +102,7 @@
@Test
public void testAppRemoved() {
- final ActivityRecord activity = createTestActivityRecord(mDisplayContent);
+ final ActivityRecord activity = createNonAttachedActivityRecord(mDisplayContent);
mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity);
mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(activity);
assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index 63367ac..a91a137 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -296,8 +296,7 @@
private WindowState createWallpaperTargetWindow(DisplayContent dc) {
final ActivityRecord homeActivity = new ActivityBuilder(mWm.mAtmService)
- .setStack(dc.getDefaultTaskDisplayArea().getRootHomeTask())
- .setCreateTask(true)
+ .setTask(dc.getDefaultTaskDisplayArea().getRootHomeTask())
.build();
homeActivity.setVisibility(true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index f5d6889..e0c72fb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -810,7 +810,7 @@
public void testOnDisplayChanged() {
final Task stack = createTaskStackOnDisplay(mDisplayContent);
final Task task = createTaskInStack(stack, 0 /* userId */);
- final ActivityRecord activity = createActivityRecordInTask(mDisplayContent, task);
+ final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
final DisplayContent newDc = createNewDisplay();
stack.getDisplayArea().removeStack(stack);
@@ -853,17 +853,17 @@
public void testTaskCanApplyAnimation() {
final Task stack = createTaskStackOnDisplay(mDisplayContent);
final Task task = createTaskInStack(stack, 0 /* userId */);
- final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task);
- final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task);
+ final ActivityRecord activity2 = createActivityRecord(mDisplayContent, task);
+ final ActivityRecord activity1 = createActivityRecord(mDisplayContent, task);
verifyWindowContainerApplyAnimation(task, activity1, activity2);
}
@Test
public void testStackCanApplyAnimation() {
final Task stack = createTaskStackOnDisplay(mDisplayContent);
- final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent,
+ final ActivityRecord activity2 = createActivityRecord(mDisplayContent,
createTaskInStack(stack, 0 /* userId */));
- final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent,
+ final ActivityRecord activity1 = createActivityRecord(mDisplayContent,
createTaskInStack(stack, 0 /* userId */));
verifyWindowContainerApplyAnimation(stack, activity1, activity2);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java
index 47e4559..78e873e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java
@@ -49,10 +49,10 @@
@UseTestDisplay(addWindows = { W_DOCK_DIVIDER, W_INPUT_METHOD })
@Test
public void testDockedDividerPosition() {
- final WindowState splitScreenWindow = createWindowOnStack(null,
+ final WindowState splitScreenWindow = createWindow(null,
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION,
mDisplayContent, "splitScreenWindow");
- final WindowState splitScreenSecondaryWindow = createWindowOnStack(null,
+ final WindowState splitScreenSecondaryWindow = createWindow(null,
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD,
TYPE_BASE_APPLICATION, mDisplayContent, "splitScreenSecondaryWindow");
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
index 8d5363c..ba144dd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
@@ -20,12 +20,16 @@
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
+import static android.provider.Settings.Global.DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.ContentResolver;
@@ -37,6 +41,9 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.util.List;
/**
* Test for {@link WindowManagerService.SettingsObserver}.
@@ -124,6 +131,36 @@
}
}
+ @Test
+ public void testEnabledIgnoreVendorDisplaySettings() {
+ try (SettingsSession ignoreVendorDisplaySettingsSession = new
+ SettingsSession(DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS)) {
+ final boolean ignoreVendorDisplaySettings =
+ !ignoreVendorDisplaySettingsSession.getSetting();
+ final Uri ignoreVendorDisplaySettingUri =
+ ignoreVendorDisplaySettingsSession.setSetting(ignoreVendorDisplaySettings);
+
+ clearInvocations(mWm.mRoot);
+ clearInvocations(mWm.mDisplayWindowSettings);
+
+ mWm.mSettingsObserver.onChange(false /* selfChange */, ignoreVendorDisplaySettingUri);
+
+ assertEquals(mWm.mDisplayWindowSettingsProvider.getVendorSettingsIgnored(),
+ ignoreVendorDisplaySettings);
+
+ ArgumentCaptor<DisplayContent> captor =
+ ArgumentCaptor.forClass(DisplayContent.class);
+ verify(mWm.mDisplayWindowSettings, times(mWm.mRoot.mChildren.size()))
+ .applySettingsToDisplayLocked(captor.capture());
+ List<DisplayContent> configuredDisplays = captor.getAllValues();
+ for (DisplayContent dc : mWm.mRoot.mChildren) {
+ assertTrue(configuredDisplays.contains(dc));
+ }
+
+ verify(mWm.mRoot, atLeastOnce()).performSurfacePlacement();
+ }
+ }
+
private class SettingsSession implements AutoCloseable {
private static final int SETTING_VALUE_OFF = 0;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index f1d49d5..7a41c02 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -389,8 +389,7 @@
final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
final Task stack = taskDisplayArea.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true)
- .setStack(stack).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(stack).build();
taskDisplayArea.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mDisplayContent.setFocusedApp(activity);
activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
@@ -428,8 +427,7 @@
final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
final Task stack = taskDisplayArea.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true)
- .setStack(stack).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(stack).build();
mDisplayContent.setFocusedApp(activity);
activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
@@ -780,7 +778,7 @@
};
private ActivityRecord makePipableActivity() {
- final ActivityRecord record = createActivityRecord(mDisplayContent,
+ final ActivityRecord record = createActivityRecordWithParentTask(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
record.info.flags |= ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
spyOn(record);
@@ -849,7 +847,7 @@
final Task stack = createStack();
final Task task = createTask(stack);
- final ActivityRecord record = createActivityRecordInTask(stack.mDisplayContent, task);
+ final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription"));
@@ -885,10 +883,10 @@
final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack);
- final ActivityRecord activity = createActivityRecordInTask(stack.mDisplayContent, task);
+ final ActivityRecord activity = createActivityRecord(stack.mDisplayContent, task);
final Task stack2 = createStack();
final Task task2 = createTask(stack2);
- final ActivityRecord activity2 = createActivityRecordInTask(stack.mDisplayContent, task2);
+ final ActivityRecord activity2 = createActivityRecord(stack.mDisplayContent, task2);
assertTrue(stack.isOrganized());
assertTrue(stack2.isOrganized());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index 94bbfca..21be6ef 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -291,25 +291,19 @@
assertEquals(1 /* minTaskLayer */, mWpc.computeOomAdjFromActivities(callback));
assertEquals(visible, callbackResult[0]);
- // The oom state will be updated in handler from activity state change.
callbackResult[0] = 0;
activity.mVisibleRequested = false;
activity.setState(Task.ActivityState.PAUSED, "test");
- waitHandlerIdle(mAtm.mH);
mWpc.computeOomAdjFromActivities(callback);
assertEquals(paused, callbackResult[0]);
- // updateProcessInfo with updateOomAdj=true should refresh the state immediately.
callbackResult[0] = 0;
activity.setState(Task.ActivityState.STOPPING, "test");
- mWpc.updateProcessInfo(false /* updateServiceConnectionActivities */,
- true /* activityChange */, true /* updateOomAdj */, false /* addPendingTopUid */);
mWpc.computeOomAdjFromActivities(callback);
assertEquals(stopping, callbackResult[0]);
callbackResult[0] = 0;
activity.setState(Task.ActivityState.STOPPED, "test");
- waitHandlerIdle(mAtm.mH);
mWpc.computeOomAdjFromActivities(callback);
assertEquals(other, callbackResult[0]);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 2691ae8..5c4563e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -17,7 +17,6 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-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.hardware.camera2.params.OutputConfiguration.ROTATION_90;
@@ -63,15 +62,18 @@
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.when;
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Rect;
+import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.util.Size;
import android.view.DisplayCutout;
+import android.view.InputWindowHandle;
import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.WindowManager;
@@ -318,8 +320,7 @@
public void testPrepareWindowToDisplayDuringRelayout() {
// Call prepareWindowToDisplayDuringRelayout for a window without FLAG_TURN_SCREEN_ON before
// calling setCurrentLaunchCanTurnScreenOn for windows with flag in the same activity.
- final ActivityRecord activity = createActivityRecord(mDisplayContent,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final ActivityRecord activity = createActivityRecord(mDisplayContent);
final WindowState first = createWindow(null, TYPE_APPLICATION, activity, "first");
final WindowState second = createWindow(null, TYPE_APPLICATION, activity, "second");
@@ -466,10 +467,10 @@
public void testDisplayIdUpdatedOnReparent() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
// fake a different display
- app.mInputWindowHandle.displayId = mDisplayContent.getDisplayId() + 1;
+ app.mInputWindowHandle.setDisplayId(mDisplayContent.getDisplayId() + 1);
app.onDisplayChanged(mDisplayContent);
- assertThat(app.mInputWindowHandle.displayId, is(mDisplayContent.getDisplayId()));
+ assertThat(app.mInputWindowHandle.getDisplayId(), is(mDisplayContent.getDisplayId()));
assertThat(app.getDisplayId(), is(mDisplayContent.getDisplayId()));
}
@@ -680,6 +681,54 @@
assertFalse(win0.canReceiveTouchInput());
}
+ @Test
+ public void testUpdateInputWindowHandle() {
+ final WindowState win = createWindow(null, TYPE_APPLICATION, "win");
+ win.mAttrs.inputFeatures = WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
+ final InputWindowHandle handle = new InputWindowHandle(
+ win.mInputWindowHandle.getInputApplicationHandle(), win.getDisplayId());
+ final InputWindowHandleWrapper handleWrapper = new InputWindowHandleWrapper(handle);
+ final IBinder inputChannelToken = mock(IBinder.class);
+ win.mInputChannelToken = inputChannelToken;
+
+ mDisplayContent.getInputMonitor().populateInputWindowHandle(handleWrapper, win);
+
+ assertTrue(handleWrapper.isChanged());
+ assertEquals(inputChannelToken, handle.token);
+ assertEquals(win.mActivityRecord.getInputApplicationHandle(false /* update */),
+ handle.inputApplicationHandle);
+ assertEquals(win.mAttrs.inputFeatures, handle.inputFeatures);
+ assertEquals(win.isVisible(), handle.visible);
+
+ final SurfaceControl sc = mock(SurfaceControl.class);
+ final SurfaceControl.Transaction transaction = mSystemServicesTestRule.mTransaction;
+ InputMonitor.setInputWindowInfoIfNeeded(transaction, sc, handleWrapper);
+
+ // The fields of input window handle are changed, so it must set input window info
+ // successfully. And then the changed flag should be reset.
+ verify(transaction).setInputWindowInfo(eq(sc), eq(handle));
+ assertFalse(handleWrapper.isChanged());
+ // Populate the same states again, the handle should not detect change.
+ mDisplayContent.getInputMonitor().populateInputWindowHandle(handleWrapper, win);
+ assertFalse(handleWrapper.isChanged());
+
+ // Apply the no change handle, the invocation of setInputWindowInfo should be skipped.
+ clearInvocations(transaction);
+ InputMonitor.setInputWindowInfoIfNeeded(transaction, sc, handleWrapper);
+ verify(transaction, never()).setInputWindowInfo(any(), any());
+
+ // Populate as an overlay to disable the input of window.
+ InputMonitor.populateOverlayInputInfo(handleWrapper, false /* isVisible */);
+ // The overlay attributes should be set.
+ assertTrue(handleWrapper.isChanged());
+ assertFalse(handle.focusable);
+ assertFalse(handle.visible);
+ assertNull(handle.token);
+ assertEquals(0L, handle.dispatchingTimeoutMillis);
+ assertEquals(WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL,
+ handle.inputFeatures);
+ }
+
@UseTestDisplay(addWindows = W_ACTIVITY)
@Test
public void testNeedsRelativeLayeringToIme_notAttached() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 62f04a1..d5fb3c5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -47,7 +47,6 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
-import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -82,7 +81,6 @@
import android.view.View;
import android.view.WindowManager;
import android.window.ITaskOrganizer;
-import android.window.WindowContainerToken;
import com.android.internal.util.ArrayUtils;
import com.android.server.AttributeCache;
@@ -248,48 +246,19 @@
return createActivityRecord(dc, windowingMode, activityType);
}
- ActivityRecord createActivityRecord(DisplayContent dc, int windowingMode, int activityType) {
- return createTestActivityRecord(dc, windowingMode, activityType);
+ WindowState createAppWindow(Task task, int type, String name) {
+ final ActivityRecord activity = createNonAttachedActivityRecord(task.getDisplayContent());
+ task.addChild(activity, 0);
+ return createWindow(null, type, activity, name);
}
- ActivityRecord createTestActivityRecord(DisplayContent dc, int windowingMode,
- int activityType) {
- final Task stack = createTaskStackOnDisplay(windowingMode, activityType, dc);
- return createTestActivityRecord(stack);
- }
-
- /** Creates an {@link ActivityRecord} and adds it to the specified {@link Task}. */
- static ActivityRecord createActivityRecordInTask(DisplayContent dc, Task task) {
- final ActivityRecord activity = createTestActivityRecord(dc);
- task.addChild(activity, POSITION_TOP);
- return activity;
- }
-
- /** Creates an {@link ActivityRecord} and adds it to the specified {@link Task}. */
- static ActivityRecord createActivityRecordInTask(Task task) {
- return createActivityRecordInTask(task.getDisplayContent(), task);
- }
-
- static ActivityRecord createTestActivityRecord(DisplayContent dc) {
- final ActivityRecord activity = new ActivityBuilder(dc.mWmService.mAtmService).build();
- postCreateActivitySetup(activity, dc);
- return activity;
- }
-
- static ActivityRecord createTestActivityRecord(Task stack) {
- final ActivityRecord activity = new ActivityBuilder(stack.mAtmService)
- .setStack(stack)
- .setCreateTask(true)
- .build();
- postCreateActivitySetup(activity, stack.getDisplayContent());
- return activity;
- }
-
- private static void postCreateActivitySetup(ActivityRecord activity, DisplayContent dc) {
- activity.onDisplayChanged(dc);
- activity.setOccludesParent(true);
- activity.setVisible(true);
- activity.mVisibleRequested = true;
+ // TODO: Move these calls to a builder?
+ WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name,
+ IWindow iwindow) {
+ final WindowToken token = createWindowToken(
+ dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
+ return createWindow(parent, type, token, name, 0 /* ownerId */,
+ false /* ownerCanAddInternalSystemWindow */, iwindow);
}
WindowState createWindow(WindowState parent, int type, String name) {
@@ -304,31 +273,15 @@
: createWindow(parent, type, parent.mToken, name, ownerId);
}
- WindowState createWindowOnStack(WindowState parent, int windowingMode, int activityType,
+ WindowState createWindow(WindowState parent, int windowingMode, int activityType,
int type, DisplayContent dc, String name) {
final WindowToken token = createWindowToken(dc, windowingMode, activityType, type);
return createWindow(parent, type, token, name);
}
- WindowState createAppWindow(Task task, int type, String name) {
- final ActivityRecord activity = createTestActivityRecord(task.getDisplayContent());
- task.addChild(activity, 0);
- return createWindow(null, type, activity, name);
- }
-
- // TODO: Move these calls to a builder?
- WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name,
- IWindow iwindow) {
- final WindowToken token = createWindowToken(
- dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
- return createWindow(parent, type, token, name, 0 /* ownerId */,
- false /* ownerCanAddInternalSystemWindow */, iwindow);
- }
-
WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
- final WindowToken token = createWindowToken(
- dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
- return createWindow(parent, type, token, name, 0 /* ownerId */);
+ return createWindow(
+ parent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type, dc, name);
}
WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name,
@@ -446,6 +399,87 @@
return task;
}
+ /** Creates an {@link ActivityRecord}. */
+ static ActivityRecord createNonAttachedActivityRecord(DisplayContent dc) {
+ final ActivityRecord activity = new ActivityBuilder(dc.mWmService.mAtmService)
+ .setOnTop(true)
+ .build();
+ postCreateActivitySetup(activity, dc);
+ return activity;
+ }
+
+ /**
+ * Creates an {@link ActivityRecord} and adds it to a new created {@link Task}.
+ * [Task] - [ActivityRecord]
+ */
+ ActivityRecord createActivityRecord(DisplayContent dc) {
+ return createActivityRecord(dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ }
+
+ /**
+ * Creates an {@link ActivityRecord} and adds it to a new created {@link Task}.
+ * [Task] - [ActivityRecord]
+ */
+ ActivityRecord createActivityRecord(DisplayContent dc, int windowingMode,
+ int activityType) {
+ final Task task = createTaskStackOnDisplay(windowingMode, activityType, dc);
+ return createActivityRecord(dc, task);
+ }
+
+ /**
+ * Creates an {@link ActivityRecord} and adds it to the specified {@link Task}.
+ * [Task] - [ActivityRecord]
+ */
+ static ActivityRecord createActivityRecord(Task task) {
+ return createActivityRecord(task.getDisplayContent(), task);
+ }
+
+ /**
+ * Creates an {@link ActivityRecord} and adds it to the specified {@link Task}.
+ * [Task] - [ActivityRecord]
+ */
+ static ActivityRecord createActivityRecord(DisplayContent dc, Task task) {
+ final ActivityRecord activity = new ActivityBuilder(dc.mWmService.mAtmService)
+ .setTask(task)
+ .setOnTop(true)
+ .build();
+ postCreateActivitySetup(activity, dc);
+ return activity;
+ }
+
+ /**
+ * Creates an {@link ActivityRecord} and adds it to a new created {@link Task}.
+ * Then adds the new created {@link Task} to a new created parent {@link Task}
+ * [Task1] - [Task2] - [ActivityRecord]
+ */
+ ActivityRecord createActivityRecordWithParentTask(DisplayContent dc, int windowingMode,
+ int activityType) {
+ final Task task = createTaskStackOnDisplay(windowingMode, activityType, dc);
+ return createActivityRecordWithParentTask(task);
+ }
+
+ /**
+ * Creates an {@link ActivityRecord} and adds it to a new created {@link Task}.
+ * Then adds the new created {@link Task} to the specified parent {@link Task}
+ * [Task1] - [Task2] - [ActivityRecord]
+ */
+ static ActivityRecord createActivityRecordWithParentTask(Task parentTask) {
+ final ActivityRecord activity = new ActivityBuilder(parentTask.mAtmService)
+ .setParentTask(parentTask)
+ .setCreateTask(true)
+ .setOnTop(true)
+ .build();
+ postCreateActivitySetup(activity, parentTask.getDisplayContent());
+ return activity;
+ }
+
+ private static void postCreateActivitySetup(ActivityRecord activity, DisplayContent dc) {
+ activity.onDisplayChanged(dc);
+ activity.setOccludesParent(true);
+ activity.setVisible(true);
+ activity.mVisibleRequested = true;
+ }
+
/** Creates a {@link DisplayContent} that supports IME and adds it to the system. */
DisplayContent createNewDisplay() {
return createNewDisplay(true /* supportIme */);
@@ -614,19 +648,20 @@
private String mProcessName = "name";
private String mAffinity;
private int mUid = 12345;
- private boolean mCreateTask;
- private Task mStack;
+ private boolean mCreateTask = false;
+ private Task mParentTask;
private int mActivityFlags;
private int mLaunchMode;
private int mResizeMode = RESIZE_MODE_RESIZEABLE;
private float mMaxAspectRatio;
private int mScreenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
- private boolean mLaunchTaskBehind;
+ private boolean mLaunchTaskBehind = false;
private int mConfigChanges;
private int mLaunchedFromPid;
private int mLaunchedFromUid;
private WindowProcessController mWpc;
private Bundle mIntentExtras;
+ private boolean mOnTop = false;
ActivityBuilder(ActivityTaskManagerService service) {
mService = service;
@@ -667,8 +702,8 @@
return this;
}
- ActivityBuilder setStack(Task stack) {
- mStack = stack;
+ ActivityBuilder setParentTask(Task parentTask) {
+ mParentTask = parentTask;
return this;
}
@@ -732,6 +767,11 @@
return this;
}
+ ActivityBuilder setOnTop(boolean onTop) {
+ mOnTop = onTop;
+ return this;
+ }
+
ActivityRecord build() {
SystemServicesTestRule.checkHoldsLock(mService.mGlobalLock);
try {
@@ -752,11 +792,11 @@
if (mCreateTask) {
mTask = new TaskBuilder(mService.mStackSupervisor)
.setComponent(mComponent)
- .setParentTask(mStack).build();
- } else if (mTask == null && mStack != null && DisplayContent.alwaysCreateStack(
- mStack.getWindowingMode(), mStack.getActivityType())) {
+ .setParentTask(mParentTask).build();
+ } else if (mTask == null && mParentTask != null && DisplayContent.alwaysCreateStack(
+ mParentTask.getWindowingMode(), mParentTask.getActivityType())) {
// The stack can be the task root.
- mTask = mStack;
+ mTask = mParentTask;
}
Intent intent = new Intent();
@@ -800,6 +840,9 @@
// to set it somewhere else since we can't mock resources.
doReturn(true).when(activity).occludesParent();
doReturn(true).when(activity).fillsParent();
+ if (mOnTop) {
+ mTask.moveToFront("createActivity");
+ }
mTask.addChild(activity);
// Make visible by default...
activity.setVisible(true);
@@ -992,8 +1035,7 @@
// Create child task with activity.
if (mCreateActivity) {
new ActivityBuilder(mSupervisor.mService)
- .setCreateTask(true)
- .setStack(task)
+ .setTask(task)
.build();
if (mOnTop) {
// We move the task to front again in order to regain focus after activity
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index dfb7280..e44d47a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -345,16 +345,16 @@
@Test
public void testStackLayers() {
final WindowState anyWindow1 = createWindow("anyWindow");
- final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,
+ final WindowState pinnedStackWindow = createWindow(null, WINDOWING_MODE_PINNED,
ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent,
"pinnedStackWindow");
- final WindowState dockedStackWindow = createWindowOnStack(null,
+ final WindowState dockedStackWindow = createWindow(null,
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION,
mDisplayContent, "dockedStackWindow");
- final WindowState assistantStackWindow = createWindowOnStack(null,
+ final WindowState assistantStackWindow = createWindow(null,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION,
mDisplayContent, "assistantStackWindow");
- final WindowState homeActivityWindow = createWindowOnStack(null, WINDOWING_MODE_FULLSCREEN,
+ final WindowState homeActivityWindow = createWindow(null, WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_HOME, TYPE_BASE_APPLICATION,
mDisplayContent, "homeActivityWindow");
final WindowState anyWindow2 = createWindow("anyWindow2");
@@ -432,16 +432,16 @@
@Test
public void testDockedDividerPosition() {
- final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,
+ final WindowState pinnedStackWindow = createWindow(null, WINDOWING_MODE_PINNED,
ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent,
"pinnedStackWindow");
- final WindowState splitScreenWindow = createWindowOnStack(null,
+ final WindowState splitScreenWindow = createWindow(null,
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION,
mDisplayContent, "splitScreenWindow");
- final WindowState splitScreenSecondaryWindow = createWindowOnStack(null,
+ final WindowState splitScreenSecondaryWindow = createWindow(null,
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD,
TYPE_BASE_APPLICATION, mDisplayContent, "splitScreenSecondaryWindow");
- final WindowState assistantStackWindow = createWindowOnStack(null,
+ final WindowState assistantStackWindow = createWindow(null,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION,
mDisplayContent, "assistantStackWindow");
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index a85eb53..1238e7b 100755
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -1468,8 +1468,11 @@
/**
* Writes the string {@param input} into the outgoing text stream for this RTT call. Since
- * RTT transmits text in real-time, this method should be called once for each character
- * the user enters into the device.
+ * RTT transmits text in real-time, this method should be called once for each user action.
+ * For example, when the user enters text as discrete characters using the keyboard, this
+ * method should be called once for each character. However, if the user enters text by
+ * pasting or autocomplete, the entire contents of the pasted or autocompleted text should
+ * be sent in one call to this method.
*
* This method is not thread-safe -- calling it from multiple threads simultaneously may
* lead to interleaved text.
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 7f87019..83e63ef 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1365,6 +1365,7 @@
* include those that were inserted before, maybe empty but not null.
* @hide
*/
+ @NonNull
@UnsupportedAppUsage
public List<SubscriptionInfo> getAllSubscriptionInfoList() {
if (VDBG) logd("[getAllSubscriptionInfoList]+");
@@ -1382,7 +1383,7 @@
}
if (result == null) {
- result = new ArrayList<>();
+ result = Collections.emptyList();
}
return result;
}
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index 3e2a6ee..b054dfc 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -240,6 +240,12 @@
*/
@Deprecated
public int getSuggestedRetryTime() {
+ // To match the pre-deprecated getSuggestedRetryTime() behavior.
+ if (mSuggestedRetryTime == RETRY_INTERVAL_UNDEFINED) {
+ return 0;
+ } else if (mSuggestedRetryTime > Integer.MAX_VALUE) {
+ return Integer.MAX_VALUE;
+ }
return (int) mSuggestedRetryTime;
}
diff --git a/telephony/java/android/telephony/ims/AudioCodecAttributes.aidl b/telephony/java/android/telephony/ims/AudioCodecAttributes.aidl
new file mode 100644
index 0000000..bbab548
--- /dev/null
+++ b/telephony/java/android/telephony/ims/AudioCodecAttributes.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.telephony.ims;
+
+parcelable AudioCodecAttributes;
diff --git a/telephony/java/android/telephony/ims/AudioCodecAttributes.java b/telephony/java/android/telephony/ims/AudioCodecAttributes.java
new file mode 100644
index 0000000..7b6ab00
--- /dev/null
+++ b/telephony/java/android/telephony/ims/AudioCodecAttributes.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.telephony.ims;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Range;
+
+/**
+ * Parcelable object to handle audio codec attributes.
+ * It provides the audio codec bitrate, bandwidth and their upper/lower bound.
+ *
+ * @hide
+ */
+@SystemApi
+public final class AudioCodecAttributes implements Parcelable {
+ // The audio codec bitrate in kbps.
+ private float mBitrateKbps;
+ // The range of the audio codec bitrate in kbps.
+ private Range<Float> mBitrateRangeKbps;
+ // The audio codec bandwidth in kHz.
+ private float mBandwidthKhz;
+ // The range of the audio codec bandwidth in kHz.
+ private Range<Float> mBandwidthRangeKhz;
+
+
+ /**
+ * Constructor.
+ *
+ * @param bitrateKbps The audio codec bitrate in kbps.
+ * @param bitrateRangeKbps The range of the audio codec bitrate in kbps.
+ * @param bandwidthKhz The audio codec bandwidth in kHz.
+ * @param bandwidthRangeKhz The range of the audio codec bandwidth in kHz.
+ */
+
+ public AudioCodecAttributes(float bitrateKbps, @NonNull Range<Float> bitrateRangeKbps,
+ float bandwidthKhz, @NonNull Range<Float> bandwidthRangeKhz) {
+ mBitrateKbps = bitrateKbps;
+ mBitrateRangeKbps = bitrateRangeKbps;
+ mBandwidthKhz = bandwidthKhz;
+ mBandwidthRangeKhz = bandwidthRangeKhz;
+ }
+
+ private AudioCodecAttributes(Parcel in) {
+ mBitrateKbps = in.readFloat();
+ mBitrateRangeKbps = new Range<>(in.readFloat(), in.readFloat());
+ mBandwidthKhz = in.readFloat();
+ mBandwidthRangeKhz = new Range<>(in.readFloat(), in.readFloat());
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeFloat(mBitrateKbps);
+ out.writeFloat(mBitrateRangeKbps.getLower());
+ out.writeFloat(mBitrateRangeKbps.getUpper());
+ out.writeFloat(mBandwidthKhz);
+ out.writeFloat(mBandwidthRangeKhz.getLower());
+ out.writeFloat(mBandwidthRangeKhz.getUpper());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final @NonNull Creator<AudioCodecAttributes> CREATOR =
+ new Creator<AudioCodecAttributes>() {
+ @Override
+ public AudioCodecAttributes createFromParcel(Parcel in) {
+ return new AudioCodecAttributes(in);
+ }
+
+ @Override
+ public AudioCodecAttributes[] newArray(int size) {
+ return new AudioCodecAttributes[size];
+ }
+ };
+
+ /**
+ * @return the exact value of the audio codec bitrate in kbps.
+ */
+ public float getBitrateKbps() {
+ return mBitrateKbps;
+ }
+
+ /**
+ * @return the range of the audio codec bitrate in kbps
+ */
+ public @NonNull Range<Float> getBitrateRangeKbps() {
+ return mBitrateRangeKbps;
+ }
+
+ /**
+ * @return the exact value of the audio codec bandwidth in kHz.
+ */
+ public float getBandwidthKhz() {
+ return mBandwidthKhz;
+ }
+
+ /**
+ * @return the range of the audio codec bandwidth in kHz.
+ */
+ public @NonNull Range<Float> getBandwidthRangeKhz() {
+ return mBandwidthRangeKhz;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "{ bitrateKbps=" + mBitrateKbps
+ + ", bitrateRangeKbps=" + mBitrateRangeKbps
+ + ", bandwidthKhz=" + mBandwidthKhz
+ + ", bandwidthRangeKhz=" + mBandwidthRangeKhz + " }";
+ }
+}
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index a7586ec..5a32075 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -29,12 +29,10 @@
import android.provider.Settings;
import android.telephony.AccessNetworkConstants;
import android.telephony.CarrierConfigManager;
-import android.telephony.SubscriptionManager;
import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IImsRcsController;
import android.telephony.ims.feature.ImsFeature;
-import android.telephony.ims.feature.RcsFeature;
import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.util.Log;
@@ -77,7 +75,7 @@
"android.telephony.ims.action.SHOW_CAPABILITY_DISCOVERY_OPT_IN";
/**
- * Receives RCS availability status updates from the ImsService.
+ * Receives RCS Feature availability status updates from the ImsService.
*
* @see #isAvailable(int)
* @see #registerRcsAvailabilityCallback(Executor, AvailabilityCallback)
@@ -101,8 +99,7 @@
final long callingIdentity = Binder.clearCallingIdentity();
try {
- mExecutor.execute(() -> mLocalCallback.onAvailabilityChanged(
- new RcsFeature.RcsImsCapabilities(config)));
+ mExecutor.execute(() -> mLocalCallback.onAvailabilityChanged(config));
} finally {
restoreCallingIdentity(callingIdentity);
}
@@ -137,7 +134,7 @@
*
* @param capabilities The new availability of the capabilities.
*/
- public void onAvailabilityChanged(@NonNull RcsFeature.RcsImsCapabilities capabilities) {
+ public void onAvailabilityChanged(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) {
}
/**@hide*/
@@ -394,7 +391,7 @@
* @hide
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public boolean isCapable(@RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability,
+ public boolean isCapable(@RcsUceAdapter.RcsImsCapabilityFlag int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int radioTech) throws ImsException {
IImsRcsController imsRcsController = getIImsRcsController();
if (imsRcsController == null) {
@@ -428,7 +425,7 @@
* @hide
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public boolean isAvailable(@RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability)
+ public boolean isAvailable(@RcsUceAdapter.RcsImsCapabilityFlag int capability)
throws ImsException {
IImsRcsController imsRcsController = getIImsRcsController();
if (imsRcsController == null) {
diff --git a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
index 2792f79..d924bae 100644
--- a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
+++ b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
@@ -17,6 +17,7 @@
package android.telephony.ims;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
@@ -90,6 +91,9 @@
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public int mAudioDirection;
+ // Audio codec attributes
+ private AudioCodecAttributes mAudioCodecAttributes;
+
// Video related information
/** @hide */
public int mVideoQuality;
@@ -191,6 +195,7 @@
public void copyFrom(ImsStreamMediaProfile profile) {
mAudioQuality = profile.mAudioQuality;
mAudioDirection = profile.mAudioDirection;
+ mAudioCodecAttributes = profile.mAudioCodecAttributes;
mVideoQuality = profile.mVideoQuality;
mVideoDirection = profile.mVideoDirection;
mRttMode = profile.mRttMode;
@@ -199,12 +204,13 @@
@NonNull
@Override
public String toString() {
- return "{ audioQuality=" + mAudioQuality +
- ", audioDirection=" + mAudioDirection +
- ", videoQuality=" + mVideoQuality +
- ", videoDirection=" + mVideoDirection +
- ", rttMode=" + mRttMode +
- ", hasRttAudioSpeech=" + mIsReceivingRttAudio + " }";
+ return "{ audioQuality=" + mAudioQuality
+ + ", audioDirection=" + mAudioDirection
+ + ", audioCodecAttribute=" + mAudioCodecAttributes
+ + ", videoQuality=" + mVideoQuality
+ + ", videoDirection=" + mVideoDirection
+ + ", rttMode=" + mRttMode
+ + ", hasRttAudioSpeech=" + mIsReceivingRttAudio + " }";
}
@Override
@@ -216,6 +222,7 @@
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mAudioQuality);
out.writeInt(mAudioDirection);
+ out.writeTypedObject(mAudioCodecAttributes, flags);
out.writeInt(mVideoQuality);
out.writeInt(mVideoDirection);
out.writeInt(mRttMode);
@@ -225,6 +232,7 @@
private void readFromParcel(Parcel in) {
mAudioQuality = in.readInt();
mAudioDirection = in.readInt();
+ mAudioCodecAttributes = in.readTypedObject(AudioCodecAttributes.CREATOR);
mVideoQuality = in.readInt();
mVideoDirection = in.readInt();
mRttMode = in.readInt();
@@ -275,6 +283,23 @@
return mAudioDirection;
}
+ /**
+ * Get the audio codec attributes {@link AudioCodecAttributes} which may be {@code null} if
+ * ImsService doesn't support this information.
+ * @return audio codec attributes
+ */
+ public @Nullable AudioCodecAttributes getAudioCodecAttributes() {
+ return mAudioCodecAttributes;
+ }
+
+ /**
+ * Set the audio codec attributes {@link AudioCodecAttributes} which includes bitrate and
+ * bandwidth information.
+ */
+ public void setAudioCodecAttributes(@NonNull AudioCodecAttributes audioCodecAttributes) {
+ mAudioCodecAttributes = audioCodecAttributes;
+ }
+
public int getVideoQuality() {
return mVideoQuality;
}
diff --git a/telephony/java/android/telephony/ims/RcsContactTerminatedReason.aidl b/telephony/java/android/telephony/ims/RcsContactTerminatedReason.aidl
new file mode 100644
index 0000000..cd1ee84
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsContactTerminatedReason.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.telephony.ims;
+
+parcelable RcsContactTerminatedReason;
diff --git a/telephony/java/android/telephony/ims/RcsContactTerminatedReason.java b/telephony/java/android/telephony/ims/RcsContactTerminatedReason.java
new file mode 100644
index 0000000..ee02564
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsContactTerminatedReason.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.telephony.ims;
+
+import android.annotation.NonNull;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * When the resource for the presence subscribe event has been terminated, the method
+ * SubscribeResponseCallback#onResourceTerminated wil be called with a list of
+ * RcsContactTerminatedReason.
+ * @hide
+ */
+public final class RcsContactTerminatedReason implements Parcelable {
+ private final Uri mContactUri;
+ private final String mReason;
+
+ public RcsContactTerminatedReason(Uri contact, String reason) {
+ mContactUri = contact;
+ mReason = reason;
+ }
+
+ private RcsContactTerminatedReason(Parcel in) {
+ mContactUri = in.readParcelable(Uri.class.getClassLoader());
+ mReason = in.readString();
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeParcelable(mContactUri, flags);
+ out.writeString(mReason);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final @NonNull Creator<RcsContactTerminatedReason> CREATOR =
+ new Creator<RcsContactTerminatedReason>() {
+ @Override
+ public RcsContactTerminatedReason createFromParcel(Parcel in) {
+ return new RcsContactTerminatedReason(in);
+ }
+
+ @Override
+ public RcsContactTerminatedReason[] newArray(int size) {
+ return new RcsContactTerminatedReason[size];
+ }
+ };
+
+ public Uri getContactUri() {
+ return mContactUri;
+ }
+
+ public String getReason() {
+ return mReason;
+ }
+}
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index c2ddcea..0aeaecc 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -47,6 +47,30 @@
private static final String TAG = "RcsUceAdapter";
/**
+ * This carrier supports User Capability Exchange as, defined by the framework using
+ * SIP OPTIONS. If set, the RcsFeature should support capability exchange. If not set, this
+ * RcsFeature should not publish capabilities or service capability requests.
+ * @hide
+ */
+ public static final int CAPABILITY_TYPE_OPTIONS_UCE = 1 << 0;
+
+ /**
+ * This carrier supports User Capability Exchange as, defined by the framework using a
+ * presence server. If set, the RcsFeature should support capability exchange. If not set, this
+ * RcsFeature should not publish capabilities or service capability requests.
+ * @hide
+ */
+ public static final int CAPABILITY_TYPE_PRESENCE_UCE = 1 << 1;
+
+ /**@hide*/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "CAPABILITY_TYPE_", value = {
+ CAPABILITY_TYPE_OPTIONS_UCE,
+ CAPABILITY_TYPE_PRESENCE_UCE
+ })
+ public @interface RcsImsCapabilityFlag {}
+
+ /**
* An unknown error has caused the request to fail.
* @hide
*/
@@ -106,11 +130,6 @@
* @hide
*/
public static final int ERROR_LOST_NETWORK = 12;
- /**
- * The request has failed because the same request has already been added to the queue.
- * @hide
- */
- public static final int ERROR_ALREADY_IN_QUEUE = 13;
/**@hide*/
@Retention(RetentionPolicy.SOURCE)
@@ -125,12 +144,90 @@
ERROR_REQUEST_TOO_LARGE,
ERROR_REQUEST_TIMEOUT,
ERROR_INSUFFICIENT_MEMORY,
- ERROR_LOST_NETWORK,
- ERROR_ALREADY_IN_QUEUE
+ ERROR_LOST_NETWORK
})
public @interface ErrorCode {}
/**
+ * A capability update has been requested due to the Entity Tag (ETag) expiring.
+ * @hide
+ */
+ public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 0;
+ /**
+ * A capability update has been requested due to moving to LTE with VoPS disabled.
+ * @hide
+ */
+ public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 1;
+ /**
+ * A capability update has been requested due to moving to LTE with VoPS enabled.
+ * @hide
+ */
+ public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 2;
+ /**
+ * A capability update has been requested due to moving to eHRPD.
+ * @hide
+ */
+ public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 3;
+ /**
+ * A capability update has been requested due to moving to HSPA+.
+ * @hide
+ */
+ public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 4;
+ /**
+ * A capability update has been requested due to moving to 3G.
+ * @hide
+ */
+ public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 5;
+ /**
+ * A capability update has been requested due to moving to 2G.
+ * @hide
+ */
+ public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 6;
+ /**
+ * A capability update has been requested due to moving to WLAN
+ * @hide
+ */
+ public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 7;
+ /**
+ * A capability update has been requested due to moving to IWLAN
+ * @hide
+ */
+ public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 8;
+ /**
+ * A capability update has been requested but the reason is unknown.
+ * @hide
+ */
+ public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 9;
+ /**
+ * A capability update has been requested due to moving to 5G NR with VoPS disabled.
+ * @hide
+ */
+ public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10;
+ /**
+ * A capability update has been requested due to moving to 5G NR with VoPS enabled.
+ * @hide
+ */
+ public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11;
+
+ /**@hide*/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "ERROR_", value = {
+ CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED,
+ CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED,
+ CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED,
+ CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD,
+ CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS,
+ CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G,
+ CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G,
+ CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN,
+ CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN,
+ CAPABILITY_UPDATE_TRIGGER_UNKNOWN,
+ CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED,
+ CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED
+ })
+ public @interface StackPublishTriggerType {}
+
+ /**
* The last publish has resulted in a "200 OK" response or the device is using SIP OPTIONS for
* UCE.
* @hide
@@ -238,38 +335,49 @@
}
/**
- * Provides a one-time callback for the response to a UCE request. After this callback is called
- * by the framework, the reference to this callback will be discarded on the service side.
+ * A callback for the response to a UCE request. The method
+ * {@link CapabilitiesCallback#onCapabilitiesReceived} will be called zero or more times as the
+ * capabilities are received for each requested contact.
+ * <p>
+ * This request will take a varying amount of time depending on if the contacts requested are
+ * cached or if it requires a network query. The timeout time of these requests can vary
+ * depending on the network, however in poor cases it could take up to a minute for a request
+ * to timeout. In that time only a subset of capabilities may have been retrieved.
+ * <p>
+ * After {@link CapabilitiesCallback#onComplete} or {@link CapabilitiesCallback#onError} has
+ * been called, the reference to this callback will be discarded on the service side.
* @see #requestCapabilities(Executor, List, CapabilitiesCallback)
* @hide
*/
- public static class CapabilitiesCallback {
+ public interface CapabilitiesCallback {
/**
- * Notify this application that the pending capability request has returned successfully.
+ * Notify this application that the pending capability request has returned successfully
+ * for one or more of the requested contacts.
* @param contactCapabilities List of capabilities associated with each contact requested.
*/
- public void onCapabilitiesReceived(
- @NonNull List<RcsContactUceCapability> contactCapabilities) {
+ void onCapabilitiesReceived(@NonNull List<RcsContactUceCapability> contactCapabilities);
- }
+ /**
+ * The pending request has completed successfully due to all requested contacts information
+ * being delivered.
+ */
+ void onComplete();
/**
* The pending request has resulted in an error and may need to be retried, depending on the
* error code.
* @param errorCode The reason for the framework being unable to process the request.
*/
- public void onError(@ErrorCode int errorCode) {
-
- }
+ void onError(@ErrorCode int errorCode);
}
private final Context mContext;
private final int mSubId;
/**
- * Not to be instantiated directly, use
- * {@link ImsRcsManager#getUceAdapter()} to instantiate this manager class.
+ * Not to be instantiated directly, use {@link ImsRcsManager#getUceAdapter()} to instantiate
+ * this manager class.
* @hide
*/
RcsUceAdapter(Context context, int subId) {
@@ -280,6 +388,9 @@
/**
* Request the User Capability Exchange capabilities for one or more contacts.
* <p>
+ * This will return the cached capabilities of the contact and will not perform a capability
+ * poll on the network unless there are contacts being queried with stale information.
+ * <p>
* Be sure to check the availability of this feature using
* {@link ImsRcsManager#isAvailable(int)} and ensuring
* {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} or
@@ -302,7 +413,7 @@
@NonNull List<Uri> contactNumbers,
@NonNull CapabilitiesCallback c) throws ImsException {
if (c == null) {
- throw new IllegalArgumentException("Must include a non-null AvailabilityCallback.");
+ throw new IllegalArgumentException("Must include a non-null CapabilitiesCallback.");
}
if (executor == null) {
throw new IllegalArgumentException("Must include a non-null Executor.");
@@ -330,6 +441,15 @@
}
}
@Override
+ public void onComplete() {
+ final long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> c.onComplete());
+ } finally {
+ restoreCallingIdentity(callingIdentity);
+ }
+ }
+ @Override
public void onError(int errorCode) {
final long callingIdentity = Binder.clearCallingIdentity();
try {
@@ -351,6 +471,88 @@
}
/**
+ * Ignore the device cache and perform a capability discovery for one contact, also called
+ * "availability fetch."
+ * <p>
+ * This will always perform a query to the network as long as requests are over the carrier
+ * availability fetch throttling threshold. If too many network requests are sent too quickly,
+ * #ERROR_TOO_MANY_REQUESTS will be returned.
+ *
+ * <p>
+ * Be sure to check the availability of this feature using
+ * {@link ImsRcsManager#isAvailable(int)} and ensuring
+ * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} or
+ * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE} is
+ * enabled or else this operation will fail with
+ * {@link #ERROR_NOT_AVAILABLE} or {@link #ERROR_NOT_ENABLED}.
+ *
+ * @param contactNumber The contact of the capabilities is being requested for.
+ * @param c A one-time callback for when the request for capabilities completes or there is
+ * an error processing the request.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public void requestNetworkAvailability(@NonNull @CallbackExecutor Executor executor,
+ @NonNull Uri contactNumber, @NonNull CapabilitiesCallback c) throws ImsException {
+ if (executor == null) {
+ throw new IllegalArgumentException("Must include a non-null Executor.");
+ }
+ if (contactNumber == null) {
+ throw new IllegalArgumentException("Must include non-null contact number.");
+ }
+ if (c == null) {
+ throw new IllegalArgumentException("Must include a non-null CapabilitiesCallback.");
+ }
+
+ IImsRcsController imsRcsController = getIImsRcsController();
+ if (imsRcsController == null) {
+ Log.e(TAG, "requestNetworkAvailability: IImsRcsController is null");
+ throw new ImsException("Cannot find remote IMS service",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+
+ IRcsUceControllerCallback internalCallback = new IRcsUceControllerCallback.Stub() {
+ @Override
+ public void onCapabilitiesReceived(List<RcsContactUceCapability> contactCapabilities) {
+ final long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() ->
+ c.onCapabilitiesReceived(contactCapabilities));
+ } finally {
+ restoreCallingIdentity(callingIdentity);
+ }
+ }
+ @Override
+ public void onComplete() {
+ final long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> c.onComplete());
+ } finally {
+ restoreCallingIdentity(callingIdentity);
+ }
+ }
+ @Override
+ public void onError(int errorCode) {
+ final long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> c.onError(errorCode));
+ } finally {
+ restoreCallingIdentity(callingIdentity);
+ }
+ }
+ };
+
+ try {
+ imsRcsController.requestNetworkAvailability(mSubId, mContext.getOpPackageName(),
+ mContext.getAttributionTag(), contactNumber, internalCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling IImsRcsController#requestNetworkAvailability", e);
+ throw new ImsException("Remote IMS Service is not available",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+ }
+
+ /**
* Gets the last publish result from the UCE service if the device is using an RCS presence
* server.
* @return The last publish result from the UCE service. If the device is using SIP OPTIONS,
diff --git a/telephony/java/android/telephony/ims/aidl/ICapabilityExchangeEventListener.aidl b/telephony/java/android/telephony/ims/aidl/ICapabilityExchangeEventListener.aidl
new file mode 100644
index 0000000..a4ffbef
--- /dev/null
+++ b/telephony/java/android/telephony/ims/aidl/ICapabilityExchangeEventListener.aidl
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.telephony.ims.aidl;
+
+import android.net.Uri;
+import android.telephony.ims.aidl.IOptionsRequestCallback;
+
+import java.util.List;
+
+/**
+ * Listener interface for the ImsService to use to notify the framework of UCE events.
+ * {@hide}
+ */
+oneway interface ICapabilityExchangeEventListener {
+ /**
+ * Trigger the framework to provide a capability update using
+ * {@link RcsCapabilityExchangeImplBase#publishCapabilities}.
+ * <p>
+ * This is typically used when trying to generate an initial PUBLISH for a new
+ * subscription to the network. The device will cache all presence publications
+ * after boot until this method is called the first time.
+ * @param publishTriggerType {@link StackPublishTriggerType} The reason for the
+ * capability update request.
+ * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is
+ * not currently connected to the framework. This can happen if the
+ * {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the
+ * {@link RcsFeature} has not received the
+ * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare
+ * cases when the Telephony stack has crashed.
+ */
+ void onRequestPublishCapabilities(int publishTriggerType);
+
+ /**
+ * Notify the framework that the device's capabilities have been unpublished from the network.
+ *
+ * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently
+ * connected to the framework. This can happen if the {@link RcsFeature} is not
+ * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
+ * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
+ * Telephony stack has crashed.
+ */
+ void onUnpublish();
+
+ /**
+ * Inform the framework of a query for this device's UCE capabilities.
+ * <p>
+ * The framework will respond via the
+ * {@link IOptionsRequestCallback#respondToCapabilityRequest} or
+ * {@link IOptionsRequestCallback#respondToCapabilityRequestWithError} method.
+ * @param contactUri The URI associated with the remote contact that is requesting capabilities.
+ * @param remoteCapabilities The remote contact's capability information.
+ * @throws ImsException If this {@link RcsSipOptionsImplBase} instance is not currently
+ * connected to the framework. This can happen if the {@link RcsFeature} is not
+ * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received
+ * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when
+ * the Telephony stack has crashed.
+ */
+ void onRemoteCapabilityRequest(in Uri contactUri,
+ in List<String> remoteCapabilities,
+ IOptionsRequestCallback cb);
+}
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
index 6d25a09..8e84e93 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
@@ -47,6 +47,9 @@
// ImsUceAdapter specific
void requestCapabilities(int subId, String callingPackage, String callingFeatureId,
in List<Uri> contactNumbers, IRcsUceControllerCallback c);
+ void requestNetworkAvailability(int subId, String callingPackage,
+ String callingFeatureId, in Uri contactNumber,
+ IRcsUceControllerCallback c);
int getUcePublishState(int subId);
boolean isUceSettingEnabled(int subId, String callingPackage, String callingFeatureId);
void setUceSettingEnabled(int subId, boolean isEnabled);
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl
index 4b98b79..b47e3c7 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl
@@ -18,8 +18,12 @@
import android.net.Uri;
import android.telephony.ims.RcsContactUceCapability;
+import android.telephony.ims.aidl.ICapabilityExchangeEventListener;
import android.telephony.ims.aidl.IImsCapabilityCallback;
+import android.telephony.ims.aidl.IOptionsResponseCallback;
+import android.telephony.ims.aidl.IPublishResponseCallback;
import android.telephony.ims.aidl.IRcsFeatureListener;
+import android.telephony.ims.aidl.ISubscribeResponseCallback;
import android.telephony.ims.feature.CapabilityChangeRequest;
import java.util.List;
@@ -40,6 +44,12 @@
IImsCapabilityCallback c);
oneway void queryCapabilityConfiguration(int capability, int radioTech,
IImsCapabilityCallback c);
+ // RcsCapabilityExchangeImplBase specific api
+ oneway void setCapabilityExchangeEventListener(ICapabilityExchangeEventListener listener);
+ oneway void publishCapabilities(in String pidfXml, IPublishResponseCallback cb);
+ oneway void subscribeForCapabilities(in List<Uri> uris, ISubscribeResponseCallback cb);
+ oneway void sendOptionsCapabilityRequest(in Uri contactUri,
+ in List<String> myCapabilities, IOptionsResponseCallback cb);
// RcsPresenceExchangeImplBase specific api
oneway void requestCapabilities(in List<Uri> uris, int operationToken);
oneway void updateCapabilities(in RcsContactUceCapability capabilities, int operationToken);
@@ -50,4 +60,4 @@
in RcsContactUceCapability ownCapabilities, int operationToken);
oneway void respondToCapabilityRequestWithError(in Uri contactUri, int code, in String reason,
int operationToken);
-}
\ No newline at end of file
+}
diff --git a/telephony/java/android/telephony/ims/aidl/IOptionsRequestCallback.aidl b/telephony/java/android/telephony/ims/aidl/IOptionsRequestCallback.aidl
new file mode 100644
index 0000000..d55670d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/aidl/IOptionsRequestCallback.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.telephony.ims.aidl;
+
+import android.telephony.ims.RcsContactUceCapability;
+
+/**
+ * Interface used by the framework to respond to OPTIONS requests.
+ * {@hide}
+ */
+oneway interface IOptionsRequestCallback {
+ /**
+ * Respond to a remote capability request from the contact specified with the capabilities
+ * of this device.
+ * @param ownCapabilities The capabilities of this device.
+ */
+ void respondToCapabilityRequest(in RcsContactUceCapability ownCapabilities);
+
+ /**
+ * Respond to a remote capability request from the contact specified with the
+ * specified error.
+ * @param contactUri A URI containing the remote contact.
+ * @param code The SIP response code to respond with.
+ * @param reason A non-null String containing the reason associated with the SIP code.
+ */
+ void respondToCapabilityRequestWithError(int code, String reason);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt b/telephony/java/android/telephony/ims/aidl/IOptionsResponseCallback.aidl
similarity index 60%
copy from packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
copy to telephony/java/android/telephony/ims/aidl/IOptionsResponseCallback.aidl
index 24768cd..a8c8329 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
+++ b/telephony/java/android/telephony/ims/aidl/IOptionsResponseCallback.aidl
@@ -13,17 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
-import android.annotation.DimenRes
-import android.annotation.UserIdInt
+package android.telephony.ims.aidl;
-data class BubbleEntity(
- @UserIdInt val userId: Int,
- val packageName: String,
- val shortcutId: String,
- val key: String,
- val desiredHeight: Int,
- @DimenRes val desiredHeightResId: Int,
- val title: String? = null
-)
+import java.util.List;
+
+/**
+ * Interface used by the framework to receive the response from the remote user
+ * through {@link RcsCapabilityExchangeImplBase#sendOptionsCapabilityRequest}
+ * {@hide}
+ */
+oneway interface IOptionsResponseCallback {
+ void onCommandError(int code);
+ void onNetworkResponse(int code, String reason, in List<String> theirCaps);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt b/telephony/java/android/telephony/ims/aidl/IPublishResponseCallback.aidl
similarity index 62%
copy from packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
copy to telephony/java/android/telephony/ims/aidl/IPublishResponseCallback.aidl
index 24768cd..481e7f8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
+++ b/telephony/java/android/telephony/ims/aidl/IPublishResponseCallback.aidl
@@ -13,17 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
-import android.annotation.DimenRes
-import android.annotation.UserIdInt
+package android.telephony.ims.aidl;
-data class BubbleEntity(
- @UserIdInt val userId: Int,
- val packageName: String,
- val shortcutId: String,
- val key: String,
- val desiredHeight: Int,
- @DimenRes val desiredHeightResId: Int,
- val title: String? = null
-)
+import java.util.List;
+
+/**
+ * Interface used by the framework to receive the response of the publish
+ * request through {@link RcsCapabilityExchangeImplBase#publishCapabilities}
+ * {@hide}
+ */
+oneway interface IPublishResponseCallback {
+ void onCommandError(int code);
+ void onNetworkResponse(int code, String reason);
+}
diff --git a/telephony/java/android/telephony/ims/aidl/IRcsUceControllerCallback.aidl b/telephony/java/android/telephony/ims/aidl/IRcsUceControllerCallback.aidl
index 5975930..0bd3e5e 100644
--- a/telephony/java/android/telephony/ims/aidl/IRcsUceControllerCallback.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IRcsUceControllerCallback.aidl
@@ -25,5 +25,6 @@
*/
oneway interface IRcsUceControllerCallback {
void onCapabilitiesReceived(in List<RcsContactUceCapability> contactCapabilities);
+ void onComplete();
void onError(int errorCode);
}
diff --git a/telephony/java/android/telephony/ims/aidl/ISubscribeResponseCallback.aidl b/telephony/java/android/telephony/ims/aidl/ISubscribeResponseCallback.aidl
new file mode 100644
index 0000000..4deaba1
--- /dev/null
+++ b/telephony/java/android/telephony/ims/aidl/ISubscribeResponseCallback.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.telephony.ims.aidl;
+
+import android.net.Uri;
+import android.telephony.ims.RcsContactTerminatedReason;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Interface used by the framework to receive the response of the subscribe
+ * request through {@link RcsCapabilityExchangeImplBase#subscribeForCapabilities}
+ * {@hide}
+ */
+oneway interface ISubscribeResponseCallback {
+ void onCommandError(int code);
+ void onNetworkResponse(int code, in String reason);
+ void onNotifyCapabilitiesUpdate(in List<String> pidfXmls);
+ void onResourceTerminated(in List<RcsContactTerminatedReason> uriTerminatedReason);
+ void onTerminated(in String reason, in String retryAfter);
+}
diff --git a/telephony/java/android/telephony/ims/aidl/RcsOptionsResponseAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/RcsOptionsResponseAidlWrapper.java
new file mode 100644
index 0000000..47a96af
--- /dev/null
+++ b/telephony/java/android/telephony/ims/aidl/RcsOptionsResponseAidlWrapper.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.telephony.ims.aidl;
+
+import android.os.RemoteException;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.stub.RcsCapabilityExchangeImplBase.OptionsResponseCallback;
+
+import java.util.List;
+
+/**
+ * Implementation of the callback OptionsResponseCallback by wrapping the internal AIDL from
+ * telephony.
+ * @hide
+ */
+public class RcsOptionsResponseAidlWrapper implements OptionsResponseCallback {
+
+ private final IOptionsResponseCallback mResponseBinder;
+
+ public RcsOptionsResponseAidlWrapper(IOptionsResponseCallback responseBinder) {
+ mResponseBinder = responseBinder;
+ }
+
+ @Override
+ public void onCommandError(int code) {
+ try {
+ mResponseBinder.onCommandError(code);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public void onNetworkResponse(int code, String reason, List<String> theirCaps)
+ throws ImsException {
+ try {
+ mResponseBinder.onNetworkResponse(code, reason, theirCaps);
+ } catch (RemoteException e) {
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/ims/aidl/RcsPublishResponseAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/RcsPublishResponseAidlWrapper.java
new file mode 100644
index 0000000..22985d0
--- /dev/null
+++ b/telephony/java/android/telephony/ims/aidl/RcsPublishResponseAidlWrapper.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.telephony.ims.aidl;
+
+import android.os.RemoteException;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.stub.RcsCapabilityExchangeImplBase.PublishResponseCallback;
+
+/**
+ * Implementation of the callback PublishResponseCallback by wrapping the internal AIDL from
+ * telephony.
+ * @hide
+ */
+public class RcsPublishResponseAidlWrapper implements PublishResponseCallback {
+
+ private final IPublishResponseCallback mResponseBinder;
+
+ public RcsPublishResponseAidlWrapper(IPublishResponseCallback responseBinder) {
+ mResponseBinder = responseBinder;
+ }
+
+ @Override
+ public void onCommandError(int code) {
+ try {
+ mResponseBinder.onCommandError(code);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public void onNetworkResponse(int code, String reason) throws ImsException {
+ try {
+ mResponseBinder.onNetworkResponse(code, reason);
+ } catch (RemoteException e) {
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/ims/aidl/RcsSubscribeResponseAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/RcsSubscribeResponseAidlWrapper.java
new file mode 100644
index 0000000..37588ed
--- /dev/null
+++ b/telephony/java/android/telephony/ims/aidl/RcsSubscribeResponseAidlWrapper.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.telephony.ims.aidl;
+
+import android.net.Uri;
+import android.os.RemoteException;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.RcsContactTerminatedReason;
+import android.telephony.ims.stub.RcsCapabilityExchangeImplBase.SubscribeResponseCallback;
+import android.util.Pair;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of the callback OptionsResponseCallback by wrapping the internal AIDL from
+ * telephony.
+ * @hide
+ */
+public class RcsSubscribeResponseAidlWrapper implements SubscribeResponseCallback {
+
+ private final ISubscribeResponseCallback mResponseBinder;
+
+ public RcsSubscribeResponseAidlWrapper(ISubscribeResponseCallback responseBinder) {
+ mResponseBinder = responseBinder;
+ }
+
+ @Override
+ public void onCommandError(int code) {
+ try {
+ mResponseBinder.onCommandError(code);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public void onNetworkResponse(int code, String reason) throws ImsException {
+ try {
+ mResponseBinder.onNetworkResponse(code, reason);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public void onNotifyCapabilitiesUpdate(List<String> pidfXmls) throws ImsException {
+ try {
+ mResponseBinder.onNotifyCapabilitiesUpdate(pidfXmls);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public void onResourceTerminated(List<Pair<Uri, String>> uriTerminatedReason)
+ throws ImsException {
+ try {
+ mResponseBinder.onResourceTerminated(getTerminatedReasonList(uriTerminatedReason));
+ } catch (RemoteException e) {
+ }
+ }
+
+ private List<RcsContactTerminatedReason> getTerminatedReasonList(
+ List<Pair<Uri, String>> uriTerminatedReason) {
+ List<RcsContactTerminatedReason> uriTerminatedReasonList = new ArrayList<>();
+ if (uriTerminatedReason != null) {
+ for (Pair<Uri, String> pair : uriTerminatedReason) {
+ RcsContactTerminatedReason reason =
+ new RcsContactTerminatedReason(pair.first, pair.second);
+ uriTerminatedReasonList.add(reason);
+ }
+ }
+ return uriTerminatedReasonList;
+ }
+
+ @Override
+ public void onTerminated(String reason, String retryAfter) throws ImsException {
+ try {
+ mResponseBinder.onTerminated(reason, retryAfter);
+ } catch (RemoteException e) {
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java b/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
index 87a5094..87a6873 100644
--- a/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
+++ b/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
@@ -28,8 +28,8 @@
import java.util.Set;
/**
- * Request to send to IMS provider, which will try to enable/disable capabilities that are added to
- * the request.
+ * Used by the framework to enable and disable MMTEL and RCS capabilities. See
+ * MmTelFeature#changeEnabledCapabilities and RcsFeature#changeEnabledCapabilities.
* {@hide}
*/
@SystemApi
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index b8ae146..5de2ddc 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -23,12 +23,22 @@
import android.net.Uri;
import android.os.RemoteException;
import android.telephony.ims.RcsContactUceCapability;
+import android.telephony.ims.RcsUceAdapter;
+import android.telephony.ims.aidl.ICapabilityExchangeEventListener;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IImsRcsFeature;
+import android.telephony.ims.aidl.IOptionsResponseCallback;
+import android.telephony.ims.aidl.IPublishResponseCallback;
import android.telephony.ims.aidl.IRcsFeatureListener;
+import android.telephony.ims.aidl.ISubscribeResponseCallback;
+import android.telephony.ims.aidl.RcsOptionsResponseAidlWrapper;
+import android.telephony.ims.aidl.RcsPublishResponseAidlWrapper;
+import android.telephony.ims.aidl.RcsSubscribeResponseAidlWrapper;
import android.telephony.ims.stub.ImsRegistrationImplBase;
-import android.telephony.ims.stub.RcsPresenceExchangeImplBase;
-import android.telephony.ims.stub.RcsSipOptionsImplBase;
+import android.telephony.ims.stub.RcsCapabilityExchangeImplBase;
+import android.telephony.ims.stub.RcsCapabilityExchangeImplBase.OptionsResponseCallback;
+import android.telephony.ims.stub.RcsCapabilityExchangeImplBase.PublishResponseCallback;
+import android.telephony.ims.stub.RcsCapabilityExchangeImplBase.SubscribeResponseCallback;
import android.util.Log;
import com.android.internal.telephony.util.TelephonyUtils;
@@ -64,9 +74,14 @@
mExecutor = executor;
}
+ /**
+ * @deprecated This method is deprecated. Please call the method
+ * setCapabilityExchangeEventListener instead.
+ */
@Override
+ @Deprecated
public void setListener(IRcsFeatureListener listener) {
- mReference.setListener(listener);
+ Log.w(LOG_TAG, "The method setListener is deprecated");
}
@Override
@@ -106,44 +121,66 @@
return executeMethodAsyncForResult(mReference::getFeatureState, "getFeatureState");
}
+ // RcsCapabilityExchangeImplBase specific APIs
+ @Override
+ public void setCapabilityExchangeEventListener(
+ @NonNull ICapabilityExchangeEventListener listener) throws RemoteException {
+ executeMethodAsync(() -> mReference.setCapabilityExchangeEventListener(listener),
+ "setCapabilityExchangeEventListener");
+ }
+
+ @Override
+ public void publishCapabilities(@NonNull String pidfXml,
+ @NonNull IPublishResponseCallback callback) throws RemoteException {
+ PublishResponseCallback callbackWrapper = new RcsPublishResponseAidlWrapper(callback);
+ executeMethodAsync(() -> mReference.getCapabilityExchangeImplBaseInternal()
+ .publishCapabilities(pidfXml, callbackWrapper), "publishCapabilities");
+ }
+
+ @Override
+ public void subscribeForCapabilities(@NonNull List<Uri> uris,
+ @NonNull ISubscribeResponseCallback callback) throws RemoteException {
+ SubscribeResponseCallback wrapper = new RcsSubscribeResponseAidlWrapper(callback);
+ executeMethodAsync(() -> mReference.getCapabilityExchangeImplBaseInternal()
+ .subscribeForCapabilities(uris, wrapper), "subscribeForCapabilities");
+ }
+
+ @Override
+ public void sendOptionsCapabilityRequest(@NonNull Uri contactUri,
+ @NonNull List<String> myCapabilities, @NonNull IOptionsResponseCallback callback)
+ throws RemoteException {
+ OptionsResponseCallback callbackWrapper = new RcsOptionsResponseAidlWrapper(callback);
+ executeMethodAsync(() -> mReference.getCapabilityExchangeImplBaseInternal()
+ .sendOptionsCapabilityRequest(contactUri, myCapabilities, callbackWrapper),
+ "sendOptionsCapabilityRequest");
+ }
+
// RcsPresenceExchangeImplBase specific APIS
@Override
public void requestCapabilities(List<Uri> uris, int operationToken) throws RemoteException {
- executeMethodAsync(() -> mReference.getPresenceExchangeInternal()
- .requestCapabilities(uris, operationToken), "requestCapabilities");
+ throw new RemoteException("Unsupported operation: requestCapabilities");
}
@Override
public void updateCapabilities(RcsContactUceCapability capabilities, int operationToken)
throws RemoteException {
- executeMethodAsync(() -> mReference.getPresenceExchangeInternal()
- .updateCapabilities(capabilities, operationToken),
- "updateCapabilities");
-
+ throw new RemoteException("Unsupported operation: updateCapabilities");
}
// RcsSipOptionsImplBase specific APIS
@Override
public void sendCapabilityRequest(Uri contactUri, RcsContactUceCapability capabilities,
int operationToken) throws RemoteException {
- executeMethodAsync(() -> mReference.getOptionsExchangeInternal()
- .sendCapabilityRequest(contactUri, capabilities, operationToken),
- "sendCapabilityRequest");
-
+ throw new RemoteException("Unsupported operation: sendCapabilityRequest");
}
@Override
public void respondToCapabilityRequest(String contactUri,
RcsContactUceCapability ownCapabilities, int operationToken)
throws RemoteException {
- executeMethodAsync(() -> mReference.getOptionsExchangeInternal()
- .respondToCapabilityRequest(contactUri, ownCapabilities,
- operationToken), "respondToCapabilityRequest");
-
+ throw new RemoteException("Unsupported operation: respondToCapabilityRequest");
}
@Override
public void respondToCapabilityRequestWithError(Uri contactUri, int code, String reason,
int operationToken) throws RemoteException {
- executeMethodAsync(() -> mReference.getOptionsExchangeInternal()
- .respondToCapabilityRequestWithError(contactUri, code, reason,
- operationToken), "respondToCapabilityRequestWithError");
+ throw new RemoteException("Unsupported operation: respondToCapabilityRequestWithError");
}
// Call the methods with a clean calling identity on the executor and wait indefinitely for
@@ -182,8 +219,8 @@
* Contains the capabilities defined and supported by a {@link RcsFeature} in the
* form of a bitmask. The capabilities that are used in the RcsFeature are
* defined as:
- * {@link RcsImsCapabilityFlag#CAPABILITY_TYPE_OPTIONS_UCE}
- * {@link RcsImsCapabilityFlag#CAPABILITY_TYPE_PRESENCE_UCE}
+ * {@link RcsUceAdatper.RcsImsCapabilityFlag#CAPABILITY_TYPE_OPTIONS_UCE}
+ * {@link RceUceAdapter.RcsImsCapabilityFlag#CAPABILITY_TYPE_PRESENCE_UCE}
*
* The enabled capabilities of this RcsFeature will be set by the framework
* using {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)}.
@@ -223,7 +260,7 @@
*/
public static final int CAPABILITY_TYPE_PRESENCE_UCE = 1 << 1;
- public RcsImsCapabilities(@RcsImsCapabilityFlag int capabilities) {
+ public RcsImsCapabilities(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) {
super(capabilities);
}
@@ -232,25 +269,24 @@
}
@Override
- public void addCapabilities(@RcsImsCapabilityFlag int capabilities) {
+ public void addCapabilities(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) {
super.addCapabilities(capabilities);
}
@Override
- public void removeCapabilities(@RcsImsCapabilityFlag int capabilities) {
+ public void removeCapabilities(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) {
super.removeCapabilities(capabilities);
}
@Override
- public boolean isCapable(@RcsImsCapabilityFlag int capabilities) {
+ public boolean isCapable(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) {
return super.isCapable(capabilities);
}
}
private final RcsFeatureBinder mImsRcsBinder;
- private IRcsFeatureListener mListenerBinder;
- private RcsPresenceExchangeImplBase mPresExchange;
- private RcsSipOptionsImplBase mSipOptions;
+ private RcsCapabilityExchangeImplBase mCapabilityExchangeImpl;
+ private ICapabilityExchangeEventListener mCapExchangeEventListener;
/**
* Create a new RcsFeature.
@@ -314,7 +350,7 @@
* @hide
*/
public boolean queryCapabilityConfiguration(
- @RcsImsCapabilities.RcsImsCapabilityFlag int capability,
+ @RcsUceAdapter.RcsImsCapabilityFlag int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
// Base Implementation - Override to provide functionality
return false;
@@ -342,37 +378,22 @@
}
/**
- * Retrieve the implementation of SIP OPTIONS for this {@link RcsFeature}.
- * <p>
- * Will only be requested by the framework if capability exchange via SIP OPTIONS is
- * configured as capable during a
+ * Retrieve the implementation of UCE for this {@link RcsFeature}, which can use either
+ * presence or OPTIONS for capability exchange.
+ *
+ * Will only be requested by the framework if capability exchange is configured
+ * as capable during a
* {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)}
* operation and the RcsFeature sets the status of the capability to true using
* {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}.
*
- * @return An instance of {@link RcsSipOptionsImplBase} that implements SIP options exchange if
- * it is supported by the device.
- * @hide
- */
- public @NonNull RcsSipOptionsImplBase getOptionsExchangeImpl() {
- // Base Implementation, override to implement functionality
- return new RcsSipOptionsImplBase();
- }
-
- /**
- * Retrieve the implementation of UCE presence for this {@link RcsFeature}.
- * Will only be requested by the framework if presence exchang is configured as capable during
- * a {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)}
- * operation and the RcsFeature sets the status of the capability to true using
- * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}.
- *
- * @return An instance of {@link RcsPresenceExchangeImplBase} that implements presence
+ * @return An instance of {@link RcsCapabilityExchangeImplBase} that implements presence
* exchange if it is supported by the device.
* @hide
*/
- public @NonNull RcsPresenceExchangeImplBase getPresenceExchangeImpl() {
- // Base Implementation, override to implement functionality.
- return new RcsPresenceExchangeImplBase();
+ public @NonNull RcsCapabilityExchangeImplBase createCapabilityExchangeImpl() {
+ // Base Implementation, override to implement functionality
+ return new RcsCapabilityExchangeImplBase();
}
/**{@inheritDoc}*/
@@ -395,39 +416,20 @@
return mImsRcsBinder;
}
- /**@hide*/
- public IRcsFeatureListener getListener() {
- synchronized (mLock) {
- return mListenerBinder;
+ private void setCapabilityExchangeEventListener(ICapabilityExchangeEventListener listener) {
+ mCapExchangeEventListener = listener;
+ if (mCapExchangeEventListener != null) {
+ onFeatureReady();
}
}
- private void setListener(IRcsFeatureListener listener) {
+ private RcsCapabilityExchangeImplBase getCapabilityExchangeImplBaseInternal() {
synchronized (mLock) {
- mListenerBinder = listener;
- if (mListenerBinder != null) {
- onFeatureReady();
+ if (mCapabilityExchangeImpl == null) {
+ mCapabilityExchangeImpl = createCapabilityExchangeImpl();
+ mCapabilityExchangeImpl.setEventListener(mCapExchangeEventListener);
}
- }
- }
-
- private RcsPresenceExchangeImplBase getPresenceExchangeInternal() {
- synchronized (mLock) {
- if (mPresExchange == null) {
- mPresExchange = getPresenceExchangeImpl();
- mPresExchange.initialize(this);
- }
- return mPresExchange;
- }
- }
-
- private RcsSipOptionsImplBase getOptionsExchangeInternal() {
- synchronized (mLock) {
- if (mSipOptions == null) {
- mSipOptions = getOptionsExchangeImpl();
- mSipOptions.initialize(this);
- }
- return mSipOptions;
+ return mCapabilityExchangeImpl;
}
}
}
diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
index fda295a..0b13efb 100644
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
@@ -87,12 +87,8 @@
/** @hide */
protected final IRcsFeatureListener getListener() throws ImsException {
- IRcsFeatureListener listener = mFeature.getListener();
- if (listener == null) {
- throw new ImsException("Connection to Framework has not been established, wait for "
- + "onFeatureReady().", ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
- }
- return mFeature.getListener();
+ throw new ImsException("This method is deprecated.",
+ ImsException.CODE_ERROR_UNSUPPORTED_OPERATION);
}
/**
diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
new file mode 100644
index 0000000..b5704bf
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.telephony.ims.stub;
+
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.Uri;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.aidl.ICapabilityExchangeEventListener;
+import android.util.Log;
+import android.util.Pair;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
+/**
+ * Base class for different types of Capability exchange.
+ * @hide
+ */
+public class RcsCapabilityExchangeImplBase {
+
+ private static final String LOG_TAG = "RcsCapExchangeImplBase";
+
+ /**
+ * Service is unknown.
+ */
+ public static final int COMMAND_CODE_SERVICE_UNKNOWN = 0;
+
+ /**
+ * The command failed with an unknown error.
+ */
+ public static final int COMMAND_CODE_GENERIC_FAILURE = 1;
+
+ /**
+ * Invalid parameter(s).
+ */
+ public static final int COMMAND_CODE_INVALID_PARAM = 2;
+
+ /**
+ * Fetch error.
+ */
+ public static final int COMMAND_CODE_FETCH_ERROR = 3;
+
+ /**
+ * Request timed out.
+ */
+ public static final int COMMAND_CODE_REQUEST_TIMEOUT = 4;
+
+ /**
+ * Failure due to insufficient memory available.
+ */
+ public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 5;
+
+ /**
+ * Network connection is lost.
+ * @hide
+ */
+ public static final int COMMAND_CODE_LOST_NETWORK_CONNECTION = 6;
+
+ /**
+ * Requested feature/resource is not supported.
+ * @hide
+ */
+ public static final int COMMAND_CODE_NOT_SUPPORTED = 7;
+
+ /**
+ * Contact or resource is not found.
+ */
+ public static final int COMMAND_CODE_NOT_FOUND = 8;
+
+ /**
+ * Service is not available.
+ */
+ public static final int COMMAND_CODE_SERVICE_UNAVAILABLE = 9;
+
+ /**
+ * Command resulted in no change in state, ignoring.
+ */
+ public static final int COMMAND_CODE_NO_CHANGE = 10;
+
+ /**@hide*/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "COMMAND_CODE_", value = {
+ COMMAND_CODE_SERVICE_UNKNOWN,
+ COMMAND_CODE_GENERIC_FAILURE,
+ COMMAND_CODE_INVALID_PARAM,
+ COMMAND_CODE_FETCH_ERROR,
+ COMMAND_CODE_REQUEST_TIMEOUT,
+ COMMAND_CODE_INSUFFICIENT_MEMORY,
+ COMMAND_CODE_LOST_NETWORK_CONNECTION,
+ COMMAND_CODE_NOT_SUPPORTED,
+ COMMAND_CODE_NOT_FOUND,
+ COMMAND_CODE_SERVICE_UNAVAILABLE,
+ COMMAND_CODE_NO_CHANGE
+ })
+ public @interface CommandCode {}
+
+ /**
+ * Interface used by the framework to receive the response of the publish request.
+ */
+ public interface PublishResponseCallback {
+ /**
+ * Notify the framework that the command associated with this callback has failed.
+ *
+ * @param code The reason why the associated command has failed.
+ * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is
+ * not currently connected to the framework. This can happen if the {@link RcsFeature}
+ * is not {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received
+ * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases
+ * when the Telephony stack has crashed.
+ */
+ void onCommandError(@CommandCode int code) throws ImsException;
+
+
+ /**
+ * Provide the framework with a subsequent network response update to
+ * {@link #publishCapabilities(String, PublishResponseCallback)}.
+ *
+ * @param code The SIP response code sent from the network for the operation
+ * token specified.
+ * @param reason The optional reason response from the network. If the network
+ * provided no reason with the code, the string should be empty.
+ * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is
+ * not currently connected to the framework. This can happen if the {@link RcsFeature}
+ * is not {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received
+ * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases
+ * when the Telephony stack has crashed.
+ */
+ void onNetworkResponse(@IntRange(from = 100, to = 699) int code,
+ @NonNull String reason) throws ImsException;
+ }
+
+ /**
+ * Interface used by the framework to respond to OPTIONS requests.
+ */
+ public interface OptionsResponseCallback {
+ /**
+ * Notify the framework that the command associated with this callback has failed.
+ *
+ * @param code The reason why the associated command has failed.
+ * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is
+ * not currently connected to the framework. This can happen if the
+ * {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the {@link RcsFeature}
+ * has not received the {@link ImsFeature#onFeatureReady()} callback. This may also happen
+ * in rare cases when the Telephony stack has crashed.
+ */
+ void onCommandError(@CommandCode int code) throws ImsException;
+
+ /**
+ * Send the response of a SIP OPTIONS capability exchange to the framework.
+ * @param code The SIP response code that was sent by the network in response
+ * to the request sent by {@link #sendOptionsCapabilityRequest}.
+ * @param reason The optional SIP response reason sent by the network.
+ * If none was sent, this should be an empty string.
+ * @param theirCaps the contact's UCE capabilities associated with the
+ * capability request.
+ * @throws ImsException If this {@link RcsSipOptionsImplBase} instance is not
+ * currently connected to the framework. This can happen if the
+ * {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the
+ * {@link RcsFeature} has not received the
+ * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare
+ * cases when the Telephony stack has crashed.
+ */
+ void onNetworkResponse(int code, @NonNull String reason,
+ @Nullable List<String> theirCaps) throws ImsException;
+ }
+
+ /**
+ * Interface used by the framework to receive the response of the subscribe request.
+ */
+ public interface SubscribeResponseCallback {
+ /**
+ * Notify the framework that the command associated with this callback has failed.
+ *
+ * @param code The reason why the associated command has failed.
+ * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is
+ * not currently connected to the framework. This can happen if the
+ * {@link RcsFeature} is not
+ * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received
+ * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in
+ * rare cases when the Telephony stack has crashed.
+ */
+ void onCommandError(@CommandCode int code) throws ImsException;
+
+ /**
+ * Notify the framework of the response to the SUBSCRIBE request from
+ * {@link #subscribeForCapabilities(List<Uri>, SubscribeResponseCallback)}.
+ *
+ * @param code The SIP response code sent from the network for the operation
+ * token specified.
+ * @param reason The optional reason response from the network. If the network
+ * provided no reason with the code, the string should be empty.
+ * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is
+ * not currently connected to the framework. This can happen if the
+ * {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the
+ * {@link RcsFeature} has not received the {@link ImsFeature#onFeatureReady()} callback.
+ * This may also happen in rare cases when the Telephony stack has crashed.
+ */
+ void onNetworkResponse(@IntRange(from = 100, to = 699) int code,
+ @NonNull String reason) throws ImsException;
+
+ /**
+ * Provides the framework with latest XML PIDF documents included in the
+ * network response for the requested contacts' capabilities requested by the
+ * Framework using {@link #requestCapabilities(List, int)}. This should be
+ * called every time a new NOTIFY event is received with new capability
+ * information.
+ *
+ * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is
+ * not currently
+ * connected to the framework. This can happen if the {@link RcsFeature} is not
+ * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received
+ * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in
+ * rare cases when the
+ * Telephony stack has crashed.
+ */
+ void onNotifyCapabilitiesUpdate(@NonNull List<String> pidfXmls) throws ImsException;
+
+ /**
+ * A resource in the resource list for the presence subscribe event has been terminated.
+ * <p>
+ * This allows the framework to know that there will not be any capability information for
+ * a specific contact URI that they subscribed for.
+ */
+ void onResourceTerminated(
+ @NonNull List<Pair<Uri, String>> uriTerminatedReason) throws ImsException;
+
+ /**
+ * The subscription associated with a previous #requestCapabilities operation
+ * has been terminated. This will mostly be due to the subscription expiring,
+ * but may also happen due to an error.
+ * <p>
+ * This allows the framework to know that there will no longer be any
+ * capability updates for the requested operationToken.
+ */
+ void onTerminated(String reason, String retryAfter) throws ImsException;
+ }
+
+
+ private ICapabilityExchangeEventListener mListener;
+
+ /**
+ * Set the event listener to send the request to Framework.
+ */
+ public void setEventListener(ICapabilityExchangeEventListener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Get the event listener.
+ */
+ public ICapabilityExchangeEventListener getEventListener() {
+ return mListener;
+ }
+
+ /**
+ * The user capabilities of one or multiple contacts have been requested by the framework.
+ * <p>
+ * The response from the network to the SUBSCRIBE request must be sent back to the framework
+ * using {@link #onSubscribeNetworkResponse(int, String, int)}. As NOTIFY requests come in from
+ * the network, the requested contact’s capabilities should be sent back to the framework using
+ * {@link #onSubscribeNotifyRequest} and {@link onSubscribeResourceTerminated}
+ * should be called with the presence information for the contacts specified.
+ * <p>
+ * Once the subscription is terminated, {@link #onSubscriptionTerminated} must be called for
+ * the framework to finish listening for NOTIFY responses.
+ * @param uris A {@link List} of the {@link Uri}s that the framework is requesting the UCE
+ * capabilities for.
+ * @param cb The callback of the subscribe request.
+ */
+ public void subscribeForCapabilities(@NonNull List<Uri> uris,
+ @NonNull SubscribeResponseCallback cb) {
+ // Stub - to be implemented by service
+ Log.w(LOG_TAG, "subscribeForCapabilities called with no implementation.");
+ try {
+ cb.onCommandError(COMMAND_CODE_NOT_SUPPORTED);
+ } catch (ImsException e) {
+ // Do not do anything, this is a stub implementation.
+ }
+ }
+
+ /**
+ * The capabilities of this device have been updated and should be published to the network.
+ * <p>
+ * If this operation succeeds, network response updates should be sent to the framework using
+ * {@link #onNetworkResponse(int, String)}.
+ * @param pidfXml The XML PIDF document containing the capabilities of this device to be sent
+ * to the carrier’s presence server.
+ * @param cb The callback of the publish request
+ */
+ public void publishCapabilities(@NonNull String pidfXml, @NonNull PublishResponseCallback cb) {
+ // Stub - to be implemented by service
+ Log.w(LOG_TAG, "publishCapabilities called with no implementation.");
+ try {
+ cb.onCommandError(COMMAND_CODE_NOT_SUPPORTED);
+ } catch (ImsException e) {
+ // Do not do anything, this is a stub implementation.
+ }
+ }
+
+ /**
+ * Push one's own capabilities to a remote user via the SIP OPTIONS presence exchange mechanism
+ * in order to receive the capabilities of the remote user in response.
+ * <p>
+ * The implementer must call {@link #onNetworkResponse} to send the response of this
+ * query back to the framework.
+ * @param contactUri The URI of the remote user that we wish to get the capabilities of.
+ * @param myCapabilities The capabilities of this device to send to the remote user.
+ * @param callback The callback of this request which is sent from the remote user.
+ */
+ public void sendOptionsCapabilityRequest(@NonNull Uri contactUri,
+ @NonNull List<String> myCapabilities, @NonNull OptionsResponseCallback callback) {
+ // Stub - to be implemented by service
+ Log.w(LOG_TAG, "sendOptionsCapabilityRequest called with no implementation.");
+ try {
+ callback.onCommandError(COMMAND_CODE_NOT_SUPPORTED);
+ } catch (ImsException e) {
+ // Do not do anything, this is a stub implementation.
+ }
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index b1700a1..d3c27dc4 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -30,77 +30,96 @@
// from RIL_Errno
int SUCCESS = 0;
- int RADIO_NOT_AVAILABLE = 1; /* If radio did not start or is resetting */
+ int RADIO_NOT_AVAILABLE = 1; /* If radio did not start or is resetting */
int GENERIC_FAILURE = 2;
- int PASSWORD_INCORRECT = 3; /* for PIN/PIN2 methods only! */
- int SIM_PIN2 = 4; /* Operation requires SIM PIN2 to be entered */
- int SIM_PUK2 = 5; /* Operation requires SIM PIN2 to be entered */
+ int PASSWORD_INCORRECT = 3; /* for PIN/PIN2 methods only! */
+ int SIM_PIN2 = 4; /* Operation requires SIM PIN2 to be entered */
+ int SIM_PUK2 = 5; /* Operation requires SIM PIN2 to be entered */
int REQUEST_NOT_SUPPORTED = 6;
int REQUEST_CANCELLED = 7;
- int OP_NOT_ALLOWED_DURING_VOICE_CALL = 8; /* data operation is not allowed during voice call in
- class C */
- int OP_NOT_ALLOWED_BEFORE_REG_NW = 9; /* request is not allowed before device registers to
- network */
- int SMS_SEND_FAIL_RETRY = 10; /* send sms fail and need retry */
- int SIM_ABSENT = 11; /* ICC card is absent */
- int SUBSCRIPTION_NOT_AVAILABLE = 12; /* fail to find CDMA subscription from specified
- location */
- int MODE_NOT_SUPPORTED = 13; /* HW does not support preferred network type */
- int FDN_CHECK_FAILURE = 14; /* send operation barred error when FDN is enabled */
- int ILLEGAL_SIM_OR_ME = 15; /* network selection failure due
- to wrong SIM/ME and no
- retries needed */
- int MISSING_RESOURCE = 16; /* no logical channel available */
- int NO_SUCH_ELEMENT = 17; /* application not found on SIM */
- int DIAL_MODIFIED_TO_USSD = 18; /* DIAL request modified to USSD */
- int DIAL_MODIFIED_TO_SS = 19; /* DIAL request modified to SS */
- int DIAL_MODIFIED_TO_DIAL = 20; /* DIAL request modified to DIAL with different data*/
- int USSD_MODIFIED_TO_DIAL = 21; /* USSD request modified to DIAL */
- int USSD_MODIFIED_TO_SS = 22; /* USSD request modified to SS */
- int USSD_MODIFIED_TO_USSD = 23; /* USSD request modified to different USSD request */
- int SS_MODIFIED_TO_DIAL = 24; /* SS request modified to DIAL */
- int SS_MODIFIED_TO_USSD = 25; /* SS request modified to USSD */
- int SUBSCRIPTION_NOT_SUPPORTED = 26; /* Subscription not supported */
- int SS_MODIFIED_TO_SS = 27; /* SS request modified to different SS request */
- int SIM_ALREADY_POWERED_OFF = 29; /* SAP: 0x03, Error card aleready powered off */
- int SIM_ALREADY_POWERED_ON = 30; /* SAP: 0x05, Error card already powered on */
- int SIM_DATA_NOT_AVAILABLE = 31; /* SAP: 0x06, Error data not available */
+ int OP_NOT_ALLOWED_DURING_VOICE_CALL = 8; /* data operation is not allowed during voice
+ call in class C */
+ int OP_NOT_ALLOWED_BEFORE_REG_NW = 9; /* request is not allowed before device
+ registers to network */
+ int SMS_SEND_FAIL_RETRY = 10; /* send sms fail and need retry */
+ int SIM_ABSENT = 11; /* ICC card is absent */
+ int SUBSCRIPTION_NOT_AVAILABLE = 12; /* fail to find CDMA subscription from specified
+ location */
+ int MODE_NOT_SUPPORTED = 13; /* HW does not support preferred network type */
+ int FDN_CHECK_FAILURE = 14; /* send operation barred error when FDN is
+ enabled */
+ int ILLEGAL_SIM_OR_ME = 15; /* network selection failure due to wrong
+ SIM/ME and no retries needed */
+ int MISSING_RESOURCE = 16; /* no logical channel available */
+ int NO_SUCH_ELEMENT = 17; /* application not found on SIM */
+ int DIAL_MODIFIED_TO_USSD = 18; /* DIAL request modified to USSD */
+ int DIAL_MODIFIED_TO_SS = 19; /* DIAL request modified to SS */
+ int DIAL_MODIFIED_TO_DIAL = 20; /* DIAL request modified to DIAL with
+ different data*/
+ int USSD_MODIFIED_TO_DIAL = 21; /* USSD request modified to DIAL */
+ int USSD_MODIFIED_TO_SS = 22; /* USSD request modified to SS */
+ int USSD_MODIFIED_TO_USSD = 23; /* USSD request modified to different USSD
+ request */
+ int SS_MODIFIED_TO_DIAL = 24; /* SS request modified to DIAL */
+ int SS_MODIFIED_TO_USSD = 25; /* SS request modified to USSD */
+ int SUBSCRIPTION_NOT_SUPPORTED = 26; /* Subscription not supported */
+ int SS_MODIFIED_TO_SS = 27; /* SS request modified to different SS
+ request */
+ int SIM_ALREADY_POWERED_OFF = 29; /* SAP: 0x03, Error card aleready powered off */
+ int SIM_ALREADY_POWERED_ON = 30; /* SAP: 0x05, Error card already powered on */
+ int SIM_DATA_NOT_AVAILABLE = 31; /* SAP: 0x06, Error data not available */
int SIM_SAP_CONNECT_FAILURE = 32;
int SIM_SAP_MSG_SIZE_TOO_LARGE = 33;
int SIM_SAP_MSG_SIZE_TOO_SMALL = 34;
int SIM_SAP_CONNECT_OK_CALL_ONGOING = 35;
- int LCE_NOT_SUPPORTED = 36; /* Link Capacity Estimation (LCE) not supported */
- int NO_MEMORY = 37; /* Not sufficient memory to process the request */
- int INTERNAL_ERR = 38; /* Hit unexpected vendor internal error scenario */
- int SYSTEM_ERR = 39; /* Hit platform or system error */
- int MODEM_ERR = 40; /* Hit unexpected modem error */
- int INVALID_STATE = 41; /* Unexpected request for the current state */
- int NO_RESOURCES = 42; /* Not sufficient resource to process the request */
- int SIM_ERR = 43; /* Received error from SIM card */
- int INVALID_ARGUMENTS = 44; /* Received invalid arguments in request */
- int INVALID_SIM_STATE = 45; /* Can not process the request in current SIM state */
- int INVALID_MODEM_STATE = 46; /* Can not process the request in current Modem state */
- int INVALID_CALL_ID = 47; /* Received invalid call id in request */
- int NO_SMS_TO_ACK = 48; /* ACK received when there is no SMS to ack */
- int NETWORK_ERR = 49; /* Received error from network */
- int REQUEST_RATE_LIMITED = 50; /* Operation denied due to overly-frequent requests */
- int SIM_BUSY = 51; /* SIM is busy */
- int SIM_FULL = 52; /* The target EF is full */
- int NETWORK_REJECT = 53; /* Request is rejected by network */
- int OPERATION_NOT_ALLOWED = 54; /* Not allowed the request now */
- int EMPTY_RECORD = 55; /* The request record is empty */
- int INVALID_SMS_FORMAT = 56; /* Invalid sms format */
- int ENCODING_ERR = 57; /* Message not encoded properly */
- int INVALID_SMSC_ADDRESS = 58; /* SMSC address specified is invalid */
- int NO_SUCH_ENTRY = 59; /* No such entry present to perform the request */
- int NETWORK_NOT_READY = 60; /* Network is not ready to perform the request */
- int NOT_PROVISIONED = 61; /* Device doesnot have this value provisioned */
- int NO_SUBSCRIPTION = 62; /* Device doesnot have subscription */
- int NO_NETWORK_FOUND = 63; /* Network cannot be found */
- int DEVICE_IN_USE = 64; /* Operation cannot be performed because the device
- is currently in use */
- int ABORTED = 65; /* Operation aborted */
- int INVALID_RESPONSE = 66; /* Invalid response sent by vendor code */
+ int LCE_NOT_SUPPORTED = 36; /* Link Capacity Estimation (LCE) not
+ supported */
+ int NO_MEMORY = 37; /* Not sufficient memory to process the
+ request */
+ int INTERNAL_ERR = 38; /* Hit unexpected vendor internal error
+ scenario */
+ int SYSTEM_ERR = 39; /* Hit platform or system error */
+ int MODEM_ERR = 40; /* Hit unexpected modem error */
+ int INVALID_STATE = 41; /* Unexpected request for the current state */
+ int NO_RESOURCES = 42; /* Not sufficient resource to process the
+ request */
+ int SIM_ERR = 43; /* Received error from SIM card */
+ int INVALID_ARGUMENTS = 44; /* Received invalid arguments in request */
+ int INVALID_SIM_STATE = 45; /* Can not process the request in current SIM
+ state */
+ int INVALID_MODEM_STATE = 46; /* Can not process the request in current Modem
+ state */
+ int INVALID_CALL_ID = 47; /* Received invalid call id in request */
+ int NO_SMS_TO_ACK = 48; /* ACK received when there is no SMS to ack */
+ int NETWORK_ERR = 49; /* Received error from network */
+ int REQUEST_RATE_LIMITED = 50; /* Operation denied due to overly-frequent
+ requests */
+ int SIM_BUSY = 51; /* SIM is busy */
+ int SIM_FULL = 52; /* The target EF is full */
+ int NETWORK_REJECT = 53; /* Request is rejected by network */
+ int OPERATION_NOT_ALLOWED = 54; /* Not allowed the request now */
+ int EMPTY_RECORD = 55; /* The request record is empty */
+ int INVALID_SMS_FORMAT = 56; /* Invalid sms format */
+ int ENCODING_ERR = 57; /* Message not encoded properly */
+ int INVALID_SMSC_ADDRESS = 58; /* SMSC address specified is invalid */
+ int NO_SUCH_ENTRY = 59; /* No such entry present to perform the
+ request */
+ int NETWORK_NOT_READY = 60; /* Network is not ready to perform the
+ request */
+ int NOT_PROVISIONED = 61; /* Device doesnot have this value
+ provisioned */
+ int NO_SUBSCRIPTION = 62; /* Device doesnot have subscription */
+ int NO_NETWORK_FOUND = 63; /* Network cannot be found */
+ int DEVICE_IN_USE = 64; /* Operation cannot be performed because the
+ device is currently in use */
+ int ABORTED = 65; /* Operation aborted */
+ int INVALID_RESPONSE = 66; /* Invalid response sent by vendor code */
+ int SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED = 67; /* 1X voice and SMS are not allowed
+ simulteneously */
+ int ACCESS_BARRED = 68; /* SMS access is barred */
+ int BLOCKED_DUE_TO_CALL = 69; /* SMS is blocked due to call control */
+ int RF_HARDWARE_ISSUE = 70; /* RF HW issue is detected */
+ int NO_RF_CALIBRATION_INFO = 71; /* No RF calibration in device */
// Below is list of OEM specific error codes which can by used by OEMs in case they don't want to
// reveal particular replacement for Generic failure
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
index 1adbc2d..f49d4fc 100644
--- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
@@ -32,7 +32,7 @@
- // Code below generated by codegen v1.0.18.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -98,8 +98,8 @@
};
@DataClass.Generated(
- time = 1603836848866L,
- codegenVersion = "1.0.18",
+ time = 1604522375155L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java",
inputSignatures = "private int mBaseData\nclass HierrarchicalDataClassBase extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genSetters=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
index a4fdcd1..e8cce23 100644
--- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
@@ -46,7 +46,7 @@
- // Code below generated by codegen v1.0.18.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -120,8 +120,8 @@
};
@DataClass.Generated(
- time = 1603836849753L,
- codegenVersion = "1.0.18",
+ time = 1604522376059L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java",
inputSignatures = "private @android.annotation.NonNull java.lang.String mChildData\nclass HierrarchicalDataClassChild extends com.android.codegentest.HierrarchicalDataClassBase implements []\n@com.android.internal.util.DataClass(genParcelable=true, genConstructor=false, genSetters=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
index f0d728e..9de6552 100644
--- a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
@@ -54,7 +54,7 @@
- // Code below generated by codegen v1.0.18.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -412,10 +412,10 @@
}
@DataClass.Generated(
- time = 1603836847927L,
- codegenVersion = "1.0.18",
+ time = 1604522374190L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java",
- inputSignatures = " @android.annotation.NonNull java.lang.String[] mStringArray\n @android.annotation.NonNull int[] mIntArray\n @android.annotation.NonNull java.util.List<java.lang.String> mStringList\n @android.annotation.NonNull java.util.Map<java.lang.String,com.android.codegentest.SampleWithCustomBuilder> mMap\n @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.String> mStringMap\n @android.annotation.NonNull android.util.SparseArray<com.android.codegentest.SampleWithCustomBuilder> mSparseArray\n @android.annotation.NonNull android.util.SparseIntArray mSparseIntArray\n @java.lang.SuppressWarnings({\"WeakerAccess\"}) @android.annotation.Nullable java.lang.Boolean mNullableBoolean\nclass ParcelAllTheThingsDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)")
+ inputSignatures = " @android.annotation.NonNull java.lang.String[] mStringArray\n @android.annotation.NonNull int[] mIntArray\n @android.annotation.NonNull java.util.List<java.lang.String> mStringList\n @android.annotation.NonNull java.util.Map<java.lang.String,com.android.codegentest.SampleWithCustomBuilder> mMap\n @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.String> mStringMap\n @android.annotation.NonNull android.util.SparseArray<com.android.codegentest.SampleWithCustomBuilder> mSparseArray\n @android.annotation.NonNull android.util.SparseIntArray mSparseIntArray\n @java.lang.SuppressWarnings @android.annotation.Nullable java.lang.Boolean mNullableBoolean\nclass ParcelAllTheThingsDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)")
@Deprecated
private void __metadata() {}
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
index a3f458b..5a3e273 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
@@ -344,7 +344,7 @@
- // Code below generated by codegen v1.0.18.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -1874,10 +1874,10 @@
}
@DataClass.Generated(
- time = 1603836845952L,
- codegenVersion = "1.0.18",
+ time = 1604522372172L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java",
- inputSignatures = "public static final java.lang.String STATE_NAME_UNDEFINED\npublic static final java.lang.String STATE_NAME_ON\npublic static final java.lang.String STATE_NAME_OFF\npublic static final int STATE_ON\npublic static final int STATE_OFF\npublic static final int STATE_UNDEFINED\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate int mNum\nprivate int mNum2\nprivate int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient android.net.LinkAddress[] mLinkAddresses6\ntransient int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=6L) int mDayOfWeek\nprivate @android.annotation.Size(2L) @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate static java.lang.String defaultName4()\nprivate int[] lazyInitTmpStorage()\npublic android.net.LinkAddress[] getLinkAddresses4()\nprivate boolean patternEquals(java.util.regex.Pattern)\nprivate int patternHashCode()\nprivate void onConstructed()\npublic void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)")
+ inputSignatures = "public static final java.lang.String STATE_NAME_UNDEFINED\npublic static final java.lang.String STATE_NAME_ON\npublic static final java.lang.String STATE_NAME_OFF\npublic static final int STATE_ON\npublic static final int STATE_OFF\npublic static final int STATE_UNDEFINED\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate int mNum\nprivate int mNum2\nprivate int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient android.net.LinkAddress[] mLinkAddresses6\ntransient int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange int mDayOfWeek\nprivate @android.annotation.Size @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange float[] mCoords\nprivate static java.lang.String defaultName4()\nprivate int[] lazyInitTmpStorage()\npublic android.net.LinkAddress[] getLinkAddresses4()\nprivate boolean patternEquals(java.util.regex.Pattern)\nprivate int patternHashCode()\nprivate void onConstructed()\npublic void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)")
@Deprecated
private void __metadata() {}
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
index e356704..3ab3445 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
@@ -85,7 +85,7 @@
- // Code below generated by codegen v1.0.18.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -253,8 +253,8 @@
}
@DataClass.Generated(
- time = 1603836846970L,
- codegenVersion = "1.0.18",
+ time = 1604522373190L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java",
inputSignatures = " long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n long creationTimestamp\nprivate static java.util.concurrent.TimeUnit unparcelDelayUnit(android.os.Parcel)\nprivate void parcelDelayUnit(android.os.Parcel,int)\nclass SampleWithCustomBuilder extends java.lang.Object implements [android.os.Parcelable]\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java b/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
index 07ec31d..8901cac 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
@@ -36,7 +36,7 @@
- // Code below generated by codegen v1.0.18.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -135,8 +135,8 @@
};
@DataClass.Generated(
- time = 1603836851627L,
- codegenVersion = "1.0.18",
+ time = 1604522377998L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
inputSignatures = " @android.annotation.NonNull java.lang.String mBar\nclass NestedDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
@Deprecated
@@ -160,7 +160,7 @@
- // Code below generated by codegen v1.0.18.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -259,8 +259,8 @@
};
@DataClass.Generated(
- time = 1603836851635L,
- codegenVersion = "1.0.18",
+ time = 1604522378007L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
inputSignatures = " @android.annotation.NonNull long mBaz2\nclass NestedDataClass3 extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
@Deprecated
@@ -274,7 +274,7 @@
- // Code below generated by codegen v1.0.18.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -373,8 +373,8 @@
};
@DataClass.Generated(
- time = 1603836851640L,
- codegenVersion = "1.0.18",
+ time = 1604522378015L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
inputSignatures = " @android.annotation.NonNull java.lang.String mBaz\nclass NestedDataClass2 extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
index 5cbc6b3..ac776f3 100644
--- a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
+++ b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
@@ -15,8 +15,10 @@
*/
package com.android.codegentest;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.pm.PackageManager;
import com.android.internal.util.DataClass;
@@ -57,9 +59,12 @@
/** Unrelated methods should be noted, without triggering staleness false positives */
public @NonNull String someMethod(int param) { return null; }
+ /** Inlined constants in annotation args should be fine */
+ private @IntRange(from = PackageManager.PERMISSION_GRANTED) void annotatedWithConstArg() {}
- // Code below generated by codegen v1.0.18.
+
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -84,10 +89,10 @@
}
@DataClass.Generated(
- time = 1603836850677L,
- codegenVersion = "1.0.18",
+ time = 1604522377011L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java",
- inputSignatures = "private @android.annotation.Nullable java.util.List<java.util.Set<?>> mUsesWildcards\npublic @android.annotation.NonNull java.lang.String someMethod(int)\nclass StaleDataclassDetectorFalsePositivesTest extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false)")
+ inputSignatures = "private @android.annotation.Nullable java.util.List<java.util.Set<?>> mUsesWildcards\npublic @android.annotation.NonNull java.lang.String someMethod(int)\nprivate @android.annotation.IntRange void annotatedWithConstArg()\nclass StaleDataclassDetectorFalsePositivesTest extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index 6b974ff..db0eed8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -45,6 +45,15 @@
}
}
+fun WmAssertion.visibleWindowsShownMoreThanOneConsecutiveEntry(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("visibleWindowShownMoreThanOneConsecutiveEntry", bugId, enabled) {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+}
+
@JvmOverloads
fun LayersAssertion.noUncoveredRegions(
beginRotation: Int,
@@ -159,6 +168,15 @@
}
}
+fun LayersAssertion.visibleLayersShownMoreThanOneConsecutiveEntry(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("visibleLayersShownMoreThanOneConsecutiveEntry", bugId, enabled) {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+}
+
fun EventLogAssertion.focusChanges(
vararg windows: String,
bugId: Int = 0,
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
index d31c4ba..72efdb1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
@@ -43,12 +43,12 @@
}
}
-fun LayersAssertion.wallpaperLayerBecomesInvisible(
+fun LayersAssertion.appLayerReplacesWallpaperLayer(
testApp: IAppHelper,
bugId: Int = 0,
enabled: Boolean = bugId == 0
) {
- all("wallpaperLayerBecomesInvisible", bugId, enabled) {
+ all("appLayerReplacesWallpaperLayer", bugId, enabled) {
this.showsLayer("Wallpaper")
.then()
.replaceVisibleLayer("Wallpaper", testApp.getPackage())
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index ad23d9f..1f03c4d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -38,6 +38,8 @@
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -87,6 +89,7 @@
windowManagerTrace {
navBarWindowIsAlwaysVisible()
statusBarWindowIsAlwaysVisible()
+ visibleWindowsShownMoreThanOneConsecutiveEntry()
appWindowReplacesLauncherAsTopWindow(testApp)
wallpaperWindowBecomesInvisible()
@@ -102,8 +105,10 @@
configuration.endRotation)
navBarLayerIsAlwaysVisible(enabled = false)
statusBarLayerIsAlwaysVisible(enabled = false)
+ visibleLayersShownMoreThanOneConsecutiveEntry(
+ enabled = Surface.ROTATION_0 == configuration.endRotation)
- wallpaperLayerBecomesInvisible(testApp)
+ appLayerReplacesWallpaperLayer(testApp)
}
eventLog {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
new file mode 100644
index 0000000..1833874
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.helpers.reopenAppFromOverview
+import com.android.server.wm.flicker.helpers.hasWindow
+import com.android.server.wm.flicker.helpers.buildTestTag
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Launch an app from the recents app view (the overview)
+ * To run this test: `atest FlickerTests:OpenAppFromOverviewTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class OpenAppFromOverviewTest(
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = StandardAppHelper(instrumentation,
+ "com.android.server.wm.flicker.testapp", "SimpleApp")
+ return FlickerTestRunnerFactory(instrumentation, repetitions = 10)
+ .buildTest { configuration ->
+ withTag { buildTestTag("openAppFromOverview", testApp, configuration) }
+ repeat { configuration.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.open()
+ }
+ eachRun {
+ device.pressHome()
+ device.pressRecentApps()
+ this.setRotation(configuration.startRotation)
+ }
+ }
+ transitions {
+ device.reopenAppFromOverview()
+ device.hasWindow(testApp.getPackage())
+ }
+ teardown {
+ test {
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 5886a61..9b4223a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -38,6 +38,8 @@
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -91,9 +93,10 @@
windowManagerTrace {
navBarWindowIsAlwaysVisible()
statusBarWindowIsAlwaysVisible()
+ visibleWindowsShownMoreThanOneConsecutiveEntry()
appWindowReplacesLauncherAsTopWindow(testApp)
- wallpaperWindowBecomesInvisible(enabled = false)
+ wallpaperWindowBecomesInvisible()
}
layersTrace {
@@ -106,8 +109,10 @@
configuration.endRotation)
navBarLayerIsAlwaysVisible(enabled = false)
statusBarLayerIsAlwaysVisible(enabled = false)
+ visibleLayersShownMoreThanOneConsecutiveEntry(
+ enabled = Surface.ROTATION_0 == configuration.endRotation)
- wallpaperLayerBecomesInvisible(testApp)
+ appLayerReplacesWallpaperLayer(testApp)
}
eventLog {
diff --git a/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java b/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
index b7d72db..c769a6f 100644
--- a/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
+++ b/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
@@ -16,8 +16,6 @@
package com.android.tests.rollback.host;
-import static com.android.tests.rollback.host.WatchdogEventLogger.watchdogEventOccurred;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -31,7 +29,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.List;
import java.util.concurrent.TimeUnit;
/**
@@ -98,12 +95,11 @@
// Verify rollback was executed after health check deadline
runPhase("testNetworkFailedRollback_Phase3");
- List<String> watchdogEvents = mLogger.getWatchdogLoggingEvents();
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
+ assertTrue(mLogger.watchdogEventOccurred(ROLLBACK_INITIATE, null,
REASON_EXPLICIT_HEALTH_CHECK, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
+ assertTrue(mLogger.watchdogEventOccurred(ROLLBACK_BOOT_TRIGGERED, null,
null, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_SUCCESS, null, null, null));
+ assertTrue(mLogger.watchdogEventOccurred(ROLLBACK_SUCCESS, null, null, null));
} finally {
// Reconnect internet again so we won't break tests which assume internet available
getDevice().executeShellCommand("svc wifi enable");
@@ -134,8 +130,7 @@
// Verify rollback was not executed after health check deadline
runPhase("testNetworkPassedDoesNotRollback_Phase3");
- List<String> watchdogEvents = mLogger.getWatchdogLoggingEvents();
- assertEquals(watchdogEventOccurred(watchdogEvents, null, null,
+ assertEquals(mLogger.watchdogEventOccurred(null, null,
REASON_EXPLICIT_HEALTH_CHECK, null), false);
}
}
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 725bfa9..2ebb9c1 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -16,8 +16,6 @@
package com.android.tests.rollback.host;
-import static com.android.tests.rollback.host.WatchdogEventLogger.watchdogEventOccurred;
-
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
@@ -158,12 +156,11 @@
runPhase("testBadApkOnly_Phase4");
- List<String> watchdogEvents = mLogger.getWatchdogLoggingEvents();
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
+ assertTrue(mLogger.watchdogEventOccurred(ROLLBACK_INITIATE, null,
REASON_APP_CRASH, TESTAPP_A));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
+ assertTrue(mLogger.watchdogEventOccurred(ROLLBACK_BOOT_TRIGGERED, null,
null, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_SUCCESS, null, null, null));
+ assertTrue(mLogger.watchdogEventOccurred(ROLLBACK_SUCCESS, null, null, null));
}
@Test
@@ -192,12 +189,11 @@
// verify rollback committed
runPhase("testNativeWatchdogTriggersRollback_Phase3");
- List<String> watchdogEvents = mLogger.getWatchdogLoggingEvents();
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
+ assertTrue(mLogger.watchdogEventOccurred(ROLLBACK_INITIATE, null,
REASON_NATIVE_CRASH, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
+ assertTrue(mLogger.watchdogEventOccurred(ROLLBACK_BOOT_TRIGGERED, null,
null, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_SUCCESS, null, null, null));
+ assertTrue(mLogger.watchdogEventOccurred(ROLLBACK_SUCCESS, null, null, null));
}
@Test
@@ -233,12 +229,11 @@
// verify all available rollbacks have been committed
runPhase("testNativeWatchdogTriggersRollbackForAll_Phase4");
- List<String> watchdogEvents = mLogger.getWatchdogLoggingEvents();
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
+ assertTrue(mLogger.watchdogEventOccurred(ROLLBACK_INITIATE, null,
REASON_NATIVE_CRASH, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
+ assertTrue(mLogger.watchdogEventOccurred(ROLLBACK_BOOT_TRIGGERED, null,
null, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_SUCCESS, null, null, null));
+ assertTrue(mLogger.watchdogEventOccurred(ROLLBACK_SUCCESS, null, null, null));
}
/**
@@ -316,12 +311,11 @@
// Verify rollback occurred due to crash of apk-in-apex
runPhase("testRollbackApexWithApkCrashing_Phase3");
- List<String> watchdogEvents = mLogger.getWatchdogLoggingEvents();
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
+ assertTrue(mLogger.watchdogEventOccurred(ROLLBACK_INITIATE, null,
REASON_APP_CRASH, TESTAPP_A));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
+ assertTrue(mLogger.watchdogEventOccurred(ROLLBACK_BOOT_TRIGGERED, null,
null, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_SUCCESS, null, null, null));
+ assertTrue(mLogger.watchdogEventOccurred(ROLLBACK_SUCCESS, null, null, null));
}
/**
diff --git a/tests/RollbackTest/lib/src/com/android/tests/rollback/host/WatchdogEventLogger.java b/tests/RollbackTest/lib/src/com/android/tests/rollback/host/WatchdogEventLogger.java
index 8873150..6b0d1f8 100644
--- a/tests/RollbackTest/lib/src/com/android/tests/rollback/host/WatchdogEventLogger.java
+++ b/tests/RollbackTest/lib/src/com/android/tests/rollback/host/WatchdogEventLogger.java
@@ -17,52 +17,50 @@
package com.android.tests.rollback.host;
import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.device.LogcatReceiver;
-import com.android.tradefed.result.InputStreamSource;
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.ArrayList;
-import java.util.List;
+import static com.google.common.truth.Truth.assertThat;
public class WatchdogEventLogger {
- private LogcatReceiver mReceiver;
+ private static final String[] ROLLBACK_EVENT_TYPES = {
+ "ROLLBACK_INITIATE", "ROLLBACK_BOOT_TRIGGERED", "ROLLBACK_SUCCESS"};
+ private static final String[] ROLLBACK_EVENT_ATTRS = {
+ "logPackage", "rollbackReason", "failedPackageName"};
+ private static final String PROP_PREFIX = "persist.sys.rollbacktest.";
- public void start(ITestDevice device) {
- mReceiver = new LogcatReceiver(device, "logcat -s WatchdogRollbackLogger",
- device.getOptions().getMaxLogcatDataSize(), 0);
- mReceiver.start();
- }
+ private ITestDevice mDevice;
- public void stop() {
- if (mReceiver != null) {
- mReceiver.stop();
- mReceiver.clear();
- }
- }
-
- /**
- * Returns a list of all Watchdog logging events which have occurred.
- */
- public List<String> getWatchdogLoggingEvents() throws Exception {
- try (InputStreamSource logcatStream = mReceiver.getLogcatData()) {
- return getWatchdogLoggingEvents(logcatStream);
- }
- }
-
- private static List<String> getWatchdogLoggingEvents(InputStreamSource inputStreamSource)
- throws Exception {
- List<String> watchdogEvents = new ArrayList<>();
- InputStream inputStream = inputStreamSource.createInputStream();
- BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
- String line;
- while ((line = reader.readLine()) != null) {
- if (line.contains("Watchdog event occurred")) {
- watchdogEvents.add(line);
+ private void resetProperties(boolean enabled) throws Exception {
+ try {
+ mDevice.enableAdbRoot();
+ assertThat(mDevice.setProperty(
+ PROP_PREFIX + "enabled", String.valueOf(enabled))).isTrue();
+ for (String type : ROLLBACK_EVENT_TYPES) {
+ String key = PROP_PREFIX + type;
+ assertThat(mDevice.setProperty(key, "")).isTrue();
+ for (String attr : ROLLBACK_EVENT_ATTRS) {
+ assertThat(mDevice.setProperty(key + "." + attr, "")).isTrue();
+ }
}
+ } finally {
+ mDevice.disableAdbRoot();
}
- return watchdogEvents;
+ }
+
+ public void start(ITestDevice device) throws Exception {
+ mDevice = device;
+ resetProperties(true);
+ }
+
+ public void stop() throws Exception {
+ if (mDevice != null) {
+ resetProperties(false);
+ }
+ }
+
+ private boolean matchProperty(String type, String attr, String expectedVal) throws Exception {
+ String key = PROP_PREFIX + type + "." + attr;
+ String val = mDevice.getProperty(key);
+ return expectedVal == null || expectedVal.equals(val);
}
/**
@@ -71,33 +69,11 @@
* Check the value of all non-null parameters against the list of Watchdog events that have
* occurred, and return {@code true} if an event exists which matches all criteria.
*/
- public static boolean watchdogEventOccurred(List<String> loggingEvents,
- String type, String logPackage,
+ public boolean watchdogEventOccurred(String type, String logPackage,
String rollbackReason, String failedPackageName) throws Exception {
- List<String> eventCriteria = new ArrayList<>();
- if (type != null) {
- eventCriteria.add("type: " + type);
- }
- if (logPackage != null) {
- eventCriteria.add("logPackage: " + logPackage);
- }
- if (rollbackReason != null) {
- eventCriteria.add("rollbackReason: " + rollbackReason);
- }
- if (failedPackageName != null) {
- eventCriteria.add("failedPackageName: " + failedPackageName);
- }
- for (String loggingEvent: loggingEvents) {
- boolean matchesCriteria = true;
- for (String criterion: eventCriteria) {
- if (!loggingEvent.contains(criterion)) {
- matchesCriteria = false;
- }
- }
- if (matchesCriteria) {
- return true;
- }
- }
- return false;
+ return mDevice.getBooleanProperty(PROP_PREFIX + type, false)
+ && matchProperty(type, "logPackage", logPackage)
+ && matchProperty(type, "rollbackReason", rollbackReason)
+ && matchProperty(type, "failedPackageName", failedPackageName);
}
}
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 11a83eb..6b7ea66 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -359,7 +359,7 @@
assertFalse(nr.satisfiedByNetworkCapabilities(new NetworkCapabilities()));
}
- @Test
+ @Test @IgnoreUpTo(Build.VERSION_CODES.R)
public void testOemPrivate() {
NetworkCapabilities nc = new NetworkCapabilities();
// By default OEM_PRIVATE is neither in the unwanted or required lists and the network is
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java
index 91c9a2a..6de31f6 100644
--- a/tests/net/java/android/net/MacAddressTest.java
+++ b/tests/net/java/android/net/MacAddressTest.java
@@ -22,11 +22,11 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.net.util.MacAddressUtils;
-
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.net.module.util.MacAddressUtils;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/tests/vcn/Android.bp b/tests/vcn/Android.bp
new file mode 100644
index 0000000..f967bf0
--- /dev/null
+++ b/tests/vcn/Android.bp
@@ -0,0 +1,27 @@
+//########################################################################
+// Build FrameworksVcnTests package
+//########################################################################
+
+android_test {
+ name: "FrameworksVcnTests",
+ srcs: [
+ "java/**/*.java",
+ "java/**/*.kt",
+ ],
+ platform_apis: true,
+ test_suites: ["device-tests"],
+ certificate: "platform",
+ static_libs: [
+ "androidx.test.rules",
+ "frameworks-base-testutils",
+ "framework-protos",
+ "mockito-target-minus-junit4",
+ "platform-test-annotations",
+ "services.core",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "android.test.mock",
+ ],
+}
diff --git a/tests/vcn/AndroidManifest.xml b/tests/vcn/AndroidManifest.xml
new file mode 100644
index 0000000..2ad9aac
--- /dev/null
+++ b/tests/vcn/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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.frameworks.tests.vcn">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.tests.vcn"
+ android:label="Frameworks VCN Tests" />
+</manifest>
diff --git a/tests/vcn/AndroidTest.xml b/tests/vcn/AndroidTest.xml
new file mode 100644
index 0000000..dc521fd
--- /dev/null
+++ b/tests/vcn/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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 VCN Tests.">
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="FrameworksVcnTests.apk" />
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-tag" value="FrameworksVcnTests" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.frameworks.tests.vcn" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
diff --git a/tests/vcn/TEST_MAPPING b/tests/vcn/TEST_MAPPING
new file mode 100644
index 0000000..54fa411
--- /dev/null
+++ b/tests/vcn/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksVcnTests"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tools/codegen/src/com/android/codegen/ClassInfo.kt b/tools/codegen/src/com/android/codegen/ClassInfo.kt
index bf95a2e..056898c 100644
--- a/tools/codegen/src/com/android/codegen/ClassInfo.kt
+++ b/tools/codegen/src/com/android/codegen/ClassInfo.kt
@@ -1,12 +1,14 @@
package com.android.codegen
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
+import com.github.javaparser.ast.body.TypeDeclaration
open class ClassInfo(val classAst: ClassOrInterfaceDeclaration, val fileInfo: FileInfo) {
val fileAst = fileInfo.fileAst
val nestedClasses = classAst.members.filterIsInstance<ClassOrInterfaceDeclaration>()
+ val nestedTypes = classAst.members.filterIsInstance<TypeDeclaration<*>>()
val superInterfaces = classAst.implementedTypes.map { it.asString() }
val superClass = classAst.extendedTypes.getOrNull(0)
diff --git a/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt b/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt
index 69ff18d..83108e5 100644
--- a/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt
+++ b/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt
@@ -63,6 +63,7 @@
append("@")
append(getFullClassName(ann.nameAsString))
if (ann is MarkerAnnotationExpr) return@buildString
+ if (!ann.nameAsString.startsWith("DataClass")) return@buildString
append("(")
@@ -128,7 +129,7 @@
if (classAst.nameAsString == className) return thisPackagePrefix + classAst.nameAsString
- nestedClasses.find {
+ nestedTypes.find {
it.nameAsString == className
}?.let { return thisClassPrefix + it.nameAsString }
diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt
index ca658a9..2e176c3 100644
--- a/tools/codegen/src/com/android/codegen/SharedConstants.kt
+++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt
@@ -1,7 +1,7 @@
package com.android.codegen
const val CODEGEN_NAME = "codegen"
-const val CODEGEN_VERSION = "1.0.18"
+const val CODEGEN_VERSION = "1.0.20"
const val CANONICAL_BUILDER_CLASS = "Builder"
const val BASE_BUILDER_CLASS = "BaseBuilder"
diff --git a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
index 51faa49..1aec9b8 100644
--- a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
+++ b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
@@ -98,8 +98,10 @@
private fun elemToString(elem: Element): String {
return buildString {
- append(elem.modifiers.joinToString(" ") { it.name.toLowerCase() }).append(" ")
- append(elem.annotationMirrors.joinToString(" ")).append(" ")
+ append(elem.modifiers.joinToString(" ") { it.name.toLowerCase() })
+ append(" ")
+ append(elem.annotationMirrors.joinToString(" ", transform = { annotationToString(it) }))
+ append(" ")
if (elem is Symbol) {
if (elem.type is Type.MethodType) {
append((elem.type as Type.MethodType).returnType)
@@ -112,6 +114,14 @@
}
}
+ private fun annotationToString(ann: AnnotationMirror): String {
+ return if (ann.annotationType.toString().startsWith("com.android.internal.util.DataClass")) {
+ ann.toString()
+ } else {
+ ann.toString().substringBefore("(")
+ }
+ }
+
private fun processSingleFile(elementAnnotatedWithGenerated: Element) {
val classElement = elementAnnotatedWithGenerated.enclosingElement
diff --git a/tools/validatekeymaps/Android.bp b/tools/validatekeymaps/Android.bp
index 2759e29..15b8b41 100644
--- a/tools/validatekeymaps/Android.bp
+++ b/tools/validatekeymaps/Android.bp
@@ -16,18 +16,25 @@
static_libs: [
"libbase",
- "libbinder",
"libinput",
"libutils",
"libcutils",
"liblog",
"libui-types",
],
+ target: {
+ linux_glibc: {
+ static_libs: [
+ // libbinder is only available for linux
+ "libbinder",
+ ],
+ },
+ },
// This tool is prebuilt if we're doing an app-only build.
product_variables: {
unbundled_build: {
- enabled: false,
+ enabled: false,
},
},
}
diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp
index 0af6266..3865076 100644
--- a/tools/validatekeymaps/Main.cpp
+++ b/tools/validatekeymaps/Main.cpp
@@ -105,8 +105,8 @@
}
case FILETYPE_KEYCHARACTERMAP: {
- base::Result<std::shared_ptr<KeyCharacterMap>> ret = KeyCharacterMap::load(filename,
- KeyCharacterMap::FORMAT_ANY);
+ base::Result<std::shared_ptr<KeyCharacterMap>> ret =
+ KeyCharacterMap::load(filename, KeyCharacterMap::Format::ANY);
if (!ret) {
error("Error %s parsing key character map file.\n\n", ret.error().message().c_str());
return false;
diff --git a/wifi/api/current.txt b/wifi/api/current.txt
index d5ef703..5c4e615 100644
--- a/wifi/api/current.txt
+++ b/wifi/api/current.txt
@@ -105,6 +105,7 @@
field @Deprecated public String FQDN;
field @Deprecated public static final int SECURITY_TYPE_EAP = 3; // 0x3
field @Deprecated public static final int SECURITY_TYPE_EAP_SUITE_B = 5; // 0x5
+ field @Deprecated public static final int SECURITY_TYPE_EAP_WPA3_ENTERPRISE = 9; // 0x9
field @Deprecated public static final int SECURITY_TYPE_OPEN = 0; // 0x0
field @Deprecated public static final int SECURITY_TYPE_OWE = 6; // 0x6
field @Deprecated public static final int SECURITY_TYPE_PSK = 2; // 0x2
diff --git a/wifi/jarjar-rules.txt b/wifi/jarjar-rules.txt
index ff06a18..d235c80 100644
--- a/wifi/jarjar-rules.txt
+++ b/wifi/jarjar-rules.txt
@@ -114,8 +114,6 @@
## used by both framework-wifi and service-wifi ##
rule android.content.pm.BaseParceledListSlice* com.android.wifi.x.@0
rule android.content.pm.ParceledListSlice* com.android.wifi.x.@0
-rule android.net.util.MacAddressUtils* com.android.wifi.x.@0
-rule android.net.util.nsd.DnsSdTxtRecord* com.android.wifi.x.@0
rule android.os.HandlerExecutor* com.android.wifi.x.@0
rule android.telephony.Annotation* com.android.wifi.x.@0
rule com.android.internal.util.AsyncChannel* com.android.wifi.x.@0
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index c0f6e7a..e9d1a00 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -1026,9 +1026,17 @@
+ channels.size() + ") configured");
}
for (int i = 0; i < channels.size(); i++) {
- if (!isChannelBandPairValid(channels.valueAt(i), channels.keyAt(i))) {
- throw new IllegalArgumentException("Invalid channel(" + channels.valueAt(i)
- + ") & band (" + channels.keyAt(i) + ") configured");
+ int channel = channels.valueAt(i);
+ int band = channels.keyAt(i);
+ if (channel == 0) {
+ if (!isBandValid(band)) {
+ throw new IllegalArgumentException("Invalid band type: " + band);
+ }
+ } else {
+ if (!isChannelBandPairValid(channel, band)) {
+ throw new IllegalArgumentException("Invalid channel(" + channel
+ + ") & band (" + band + ") configured");
+ }
}
}
mChannels = channels.clone();
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 8103ff7..2772bf9 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -29,7 +29,6 @@
import android.net.ProxyInfo;
import android.net.StaticIpConfiguration;
import android.net.Uri;
-import android.net.util.MacAddressUtils;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -43,6 +42,7 @@
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.net.module.util.MacAddressUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -447,6 +447,8 @@
public static final int SECURITY_TYPE_WAPI_PSK = 7;
/** Security type for a WAPI Certificate network. */
public static final int SECURITY_TYPE_WAPI_CERT = 8;
+ /** Security type for a WPA3-Enterprise network. */
+ public static final int SECURITY_TYPE_EAP_WPA3_ENTERPRISE = 9;
/**
* Security types we support.
@@ -462,7 +464,8 @@
SECURITY_TYPE_EAP_SUITE_B,
SECURITY_TYPE_OWE,
SECURITY_TYPE_WAPI_PSK,
- SECURITY_TYPE_WAPI_CERT
+ SECURITY_TYPE_WAPI_CERT,
+ SECURITY_TYPE_EAP_WPA3_ENTERPRISE,
})
public @interface SecurityType {}
@@ -478,8 +481,9 @@
* {@link #SECURITY_TYPE_SAE},
* {@link #SECURITY_TYPE_EAP_SUITE_B},
* {@link #SECURITY_TYPE_OWE},
- * {@link #SECURITY_TYPE_WAPI_PSK}, or
- * {@link #SECURITY_TYPE_WAPI_CERT}
+ * {@link #SECURITY_TYPE_WAPI_PSK},
+ * {@link #SECURITY_TYPE_WAPI_CERT},
+ * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE}
*/
public void setSecurityParams(@SecurityType int securityType) {
// Clear all the bitsets.
@@ -555,6 +559,16 @@
allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.SMS4);
allowedGroupCiphers.set(WifiConfiguration.GroupCipher.SMS4);
break;
+ case SECURITY_TYPE_EAP_WPA3_ENTERPRISE:
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
+ allowedProtocols.set(WifiConfiguration.Protocol.RSN);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
+ requirePmf = true;
+ break;
default:
throw new IllegalArgumentException("unknown security type " + securityType);
}
@@ -1360,36 +1374,26 @@
* @hide
*/
public static final int NETWORK_SELECTION_DISABLED_STARTING_INDEX = 1;
- /**
- * The starting index for network selection temporarily disabled reasons.
- * @hide
- */
- public static final int TEMPORARILY_DISABLED_STARTING_INDEX = 1;
- /** This network is disabled because of multiple association rejections. */
+ /** This network is temporarily disabled because of multiple association rejections. */
public static final int DISABLED_ASSOCIATION_REJECTION = 1;
- /** This network is disabled because of multiple authentication failure. */
+ /** This network is temporarily disabled because of multiple authentication failure. */
public static final int DISABLED_AUTHENTICATION_FAILURE = 2;
- /** This network is disabled because of multiple DHCP failure. */
+ /** This network is temporarily disabled because of multiple DHCP failure. */
public static final int DISABLED_DHCP_FAILURE = 3;
/** This network is temporarily disabled because it has no Internet access. */
public static final int DISABLED_NO_INTERNET_TEMPORARY = 4;
- /**
- * The starting index for network selection permanently disabled reasons.
- * @hide
- */
- public static final int PERMANENTLY_DISABLED_STARTING_INDEX = 5;
- /** This network is disabled due to absence of user credentials */
+ /** This network is permanently disabled due to absence of user credentials */
public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 5;
/**
* This network is permanently disabled because it has no Internet access and the user does
* not want to stay connected.
*/
public static final int DISABLED_NO_INTERNET_PERMANENT = 6;
- /** This network is disabled due to WifiManager disabling it explicitly. */
+ /** This network is permanently disabled due to WifiManager disabling it explicitly. */
public static final int DISABLED_BY_WIFI_MANAGER = 7;
- /** This network is disabled due to wrong password. */
+ /** This network is permanently disabled due to wrong password. */
public static final int DISABLED_BY_WRONG_PASSWORD = 8;
- /** This network is disabled because service is not subscribed. */
+ /** This network is permanently disabled because service is not subscribed. */
public static final int DISABLED_AUTHENTICATION_NO_SUBSCRIPTION = 9;
/**
* All other disable reasons should be strictly less than this value.
@@ -1439,6 +1443,8 @@
/**
* Network Selection disable timeout for the error. After the timeout milliseconds,
* enable the network again.
+ * If this is set to Integer.MAX_VALUE, the network will be permanently disabled until
+ * the next time the user manually connects to it.
*/
public final int mDisableTimeoutMillis;
diff --git a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
index 35853c0..f5ffd93 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
@@ -373,14 +373,8 @@
configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B);
} else {
// WPA3-Enterprise
- configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
- configuration.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
- configuration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
- configuration.allowedPairwiseCiphers.set(
- WifiConfiguration.PairwiseCipher.GCMP_256);
- configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
- configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
- configuration.requirePmf = true;
+ configuration.setSecurityParams(
+ WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
}
configuration.enterpriseConfig = mWpa3EnterpriseConfig;
} else if (mIsEnhancedOpen) { // OWE network
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index dc6ec90..dc51897 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -802,14 +802,8 @@
configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B);
} else {
// WPA3-Enterprise
- configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
- configuration.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
- configuration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
- configuration.allowedPairwiseCiphers.set(
- WifiConfiguration.PairwiseCipher.GCMP_256);
- configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
- configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
- configuration.requirePmf = true;
+ configuration.setSecurityParams(
+ WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
}
configuration.enterpriseConfig = mWpa3EnterpriseConfig;
} else if (mIsEnhancedOpen) { // OWE network
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
index dad431c..e2f40cf 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
@@ -17,10 +17,11 @@
package android.net.wifi.p2p.nsd;
import android.compat.annotation.UnsupportedAppUsage;
-import android.net.util.nsd.DnsSdTxtRecord;
import android.os.Build;
import android.text.TextUtils;
+import com.android.net.module.util.DnsSdTxtRecord;
+
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
diff --git a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
index 4a94f1f..ad0fdd3 100644
--- a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
@@ -398,6 +398,21 @@
assertThat(dual_channels_config.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
assertTrue(dual_channels.toString().equals(dual_channels_config.getChannels().toString()));
assertThat(dual_channels_config.getChannel()).isEqualTo(2);
+
+ // Test different parameters.
+ dual_channels.clear();
+ dual_channels.put(SoftApConfiguration.BAND_5GHZ, 149);
+ dual_channels.put(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ, 0);
+ expected_dual_bands[0] = SoftApConfiguration.BAND_5GHZ;
+ expected_dual_bands[1] = SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ;
+ dual_channels_config = new SoftApConfiguration.Builder()
+ .setSsid("ssid")
+ .setChannels(dual_channels)
+ .build();
+ assertTrue(Arrays.equals(expected_dual_bands, dual_channels_config.getBands()));
+ assertThat(dual_channels_config.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
+ assertTrue(dual_channels.toString().equals(dual_channels_config.getChannels().toString()));
+ assertThat(dual_channels_config.getChannel()).isEqualTo(149);
}
@Test
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index f09c37d..6247924 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -18,6 +18,7 @@
import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP;
import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE;
import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OPEN;
import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OWE;
import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_PSK;
@@ -33,13 +34,14 @@
import static org.junit.Assert.assertTrue;
import android.net.MacAddress;
-import android.net.util.MacAddressUtils;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
import android.os.Parcel;
import androidx.test.filters.SmallTest;
+import com.android.net.module.util.MacAddressUtils;
+
import org.junit.Before;
import org.junit.Test;
@@ -581,6 +583,26 @@
}
/**
+ * Ensure that {@link WifiConfiguration#setSecurityParams(int)} sets up the
+ * {@link WifiConfiguration} object correctly for WPA3 Enterprise security type.
+ * @throws Exception
+ */
+ @Test
+ public void testSetSecurityParamsForWpa3Enterprise() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+
+ config.setSecurityParams(SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
+
+ assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP));
+ assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.GCMP_256));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.GCMP_256));
+ assertTrue(config.requirePmf);
+ }
+
+ /**
* Test that the NetworkSelectionStatus Builder returns the same values that was set, and that
* calling build multiple times returns different instances.
*/
@@ -641,6 +663,9 @@
configuration.setSecurityParams(SECURITY_TYPE_EAP);
assertFalse(configuration.needsPreSharedKey());
+ configuration.setSecurityParams(SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
+ assertFalse(configuration.needsPreSharedKey());
+
configuration.setSecurityParams(SECURITY_TYPE_EAP_SUITE_B);
assertFalse(configuration.needsPreSharedKey());
}
@@ -667,6 +692,9 @@
configuration.setSecurityParams(SECURITY_TYPE_EAP);
assertEquals(KeyMgmt.WPA_EAP, configuration.getAuthType());
+ configuration.setSecurityParams(SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
+ assertEquals(KeyMgmt.WPA_EAP, configuration.getAuthType());
+
configuration.setSecurityParams(SECURITY_TYPE_EAP_SUITE_B);
assertEquals(KeyMgmt.SUITE_B_192, configuration.getAuthType());